블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Python (8)
TinyXML (5)
STL (13)
D3D (3)
MFC (1)
C/C++ (54)
C++/CLI (45)
C# (250)
WinForm (6)
WPF (5)
Math (10)
A.I. (1)
Win32API (11)
Algorithm (3)
Design Pattern (7)
UML (1)
MaxScript (1)
FMOD (4)
FX Studio (1)
Lua (2)
Terrain (1)
Shader (3)
boost (2)
Xml (2)
JSON (4)
Etc (11)
Monad (1)
Html5 (4)
Qt (1)
Houdini (0)
Regex (10)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
04-26 06:22
반응형

'Programming > Design Pattern' 카테고리의 다른 글

C# 디자인패턴  (0) 2010.12.15
Dependency를 관리하는 방법  (0) 2010.10.21
Design Pattern Examples in C#  (0) 2010.07.23
GoF의 디자인패턴  (0) 2010.07.23
FSM - 유한 상태 기계 (Finite State Machine)  (0) 2010.07.09
Posted by blueasa
, |

 

한빛네트워크에는 양질의 칼럼들이 많이 있습니다.

다음은 한동훈님의 칼럼 중에 Advanced C#을 주제로 작성된 칼럼들의 링크입니다.

 

Advanced C# 1. UML
http://network.hanbitbook.co.kr/view.php?bi_id=589

 

Advanced C# 2. 인터페이스
http://network.hanbitbook.co.kr/view.php?bi_id=590

 

Advanced C# 3. 디자인 패턴(DP)과 Simple Factory Pattern
http://network.hanbitbook.co.kr/view.php?bi_id=593

 

Advanced C# 4. DP - Monostate, Utility, Singleton Pattern
http://network.hanbitbook.co.kr/view.php?bi_id=595

 

Advanced C# 5. DP - Factory Method
http://network.hanbitbook.co.kr/view.php?bi_id=596

 

Advanced C# 6. DP - Abstract Factory
http://network.hanbitbook.co.kr/view.php?bi_id=594

 

Advanced C# 7. DP - Builder
http://network.hanbitbook.co.kr/view.php?bi_id=600

 

Advanced C# 8. DP - Prototype 패턴
http://network.hanbitbook.co.kr/view.php?bi_id=601

 

Advanced C# 9. 알고리즘 분석(Algorithm Analysis)
http://network.hanbitbook.co.kr/view.php?bi_id=602

 

Advanced C# 10. 분할의 아름다움 - 재귀와 비재귀
http://network.hanbitbook.co.kr/view.php?bi_id=603

 

Advanced C# 11. 방정식, 미적분법 그리고 delegate
http://network.hanbitbook.co.kr/view.php?bi_id=614

반응형
Posted by blueasa
, |

일전에 Dependency에 대한 고찰이라는 글로, Dependency의 종류와 xDepend 툴들을 소개한 적이 있습니다.

이번 POST는 윗 글의 연장선상으로 Dependency 를 해결하기 위한 올바른 설계 방법 몇가지를 소개하고자 합니다.

물론 재미난(?) 그래프로 여러분의 시스템의 Depedency를 파악하는 것을 보여드리고 싶지만..  모든 일에는 순서가 있는 법.  여러분이 와 닿는 그림과 코드로 간단히 설명드리도록 하겠습니다.

Dependency가 없는 상태로 시스템을 구축한다는 것은 불가능합니다. 재사용의 미덕이 바로 Dependency의 또다른 이름이기도 하죠.

어떻게 하면 Dependency를 잘 관리할수 있을까?  그 해답을 제시해주신  아키텍트를 소개하고자 합니다.

그 분은 바로 Object Mentor의 Robert C. Martin 입니다.  Clean Code의 저자로써 알려져 있지만, 사실 이것보다  이름을 더 크게 알리게 한 주역은 패턴의 5가지 법칙(OCP, DIP, LIP, ISP, SRP)입니다.

그런데 이 5원칙의 빛에 가려 숨겨진 Principle이 하나 있는데요.  이름하여 패키지 구조의 원칙들(Principles of Package Architecture) 입니다.

이 논문에서 Dependency를 깨거나 완화하는 방법들을 여러분에게 소개하고자 합니다.

1단계: Circular Depedency를 무너 뜨려라

Circular Dependency는 패키지 소프트웨어를 만드는 구조에서 꼭 피해야 되는 구조입니다. 바로 Change Propagation (변화 전파)이 체인을 이루어 구성될수 있기 때문입니다.

여러분의 모듈중 일부분에 변화를 가하면, 다른 것들이 연쇄적으로 체인과 같이 묶여 변화를 한다면 어떻게 될까요?   생각만 해도 무시무시한 일이죠. 결국 그래프를 이루는 모든 모듈에 대해서 검증(테스팅)을 해야 하는 문제가 발생합니다.

Robert C. Martin은 Circular Dependency를 끊는 방법으로 완충작용을 해줄 새로운 Package 생성 또는  Interface 를 통해 변화를 상쇄시키는 방법을권하고 있습니다.

개발자라면 누구나, Try.. Catch문을 걸어서 발생한 오류를 화면에 MessageBox로 뛰워 본 경험이 있을 겁니다.  이렇게 되면 바로 위 그림과 같은 Circular Dependency가 발생하게 됩니다.

이 그림은 통신 모듈에 필요한 에러사항들을 GUI 관련 모듈을 통해 출력하다 보니, 이 세가지가 연관성을 갖게 되는 것입니다.   이러한 관계를 끊기 위해서 Robert C. Martin은 아래와 같이 새로운 Package를 만드는 것을 권고하고 있습니다.

시스템에서 사용하는 모든 메세지(Error 메세지를 포함)를 관리하는 Manager를 별도로 두어,  GUI와 통신 모듈이 한 방향으로 Dependency를 구성해 Circular Dependency를 끊어 버린 경우입니다.

이런 상황에서는  Log4X (NET, J)처럼 Attribute(AOP) 이용해 기존 모듈에 영향을 최소화하거나,  Listener를 이용해 IoC를 구성하는 것도 좋은 방법입니다. (IoC는 뒷부분에서 언급하도록 하죠)

또 다른 형태의  Circular Dependency를 보도록 합시다.

이 것은  두 패키지를 구성하는 내부 모듈들간에  간접적인 Circular Dependency가 생겼습니다.  하지만 Interface를 통해서 완충 장치를 두어 해결한 경우입니다. 이건 그림을 보니 다 아실것이라 생각이 들어서 패스하도록 하죠 :)

2 단계: 무거운 Dependency를 깨뜨리는 무기, IoC (Inversion of Control)

무거운 Dependency라고 해서 읽으신 분이 의아해 하셨을 겁니다.  이 의미는 모듈간에 강력한 결합으로 인하여  쉽게 테스트하거나 확장하기 어려운  상황에 무거운(Heavy) Dependency라고 합니다.

또는 전에 언급했던 Implementation Dependency에서 특정 모듈이 없으면 아예 돌아가지도 않는 상황을 말하는 Hard Dependency라고 봐도 무방합니다.

01 // your API
02 public class Tracer {
03     MessageQueue mq = new MessageQueue(…);
04     public void Trace(string message){
05         mq.Send(message);
06     }
07 }
08  
09 // your customer’s program that is hard to test
10 Tracer tracer = new Tracer();
11 public void ProcessOrder(Order order){
12     tracer.Trace(order.Id);
13     
14 }

이 소스 코드는 Tracer를 MessageQueue 로만 데이터를 추적할수 있기 때문에, Tracing이 어렵고 확장성 역시 떨어집니다.  MessageQueue에서 다른 형태로 출력을 하기 위해서는 결국 Tracer를 수정해야 되는 문제가 발생하죠.

그래서 IoC (Inversion of Control)을 적용하여, 다양한 방법으로 데이터를 추적할수 잇는 TraceListner를 아래와 같이 설계를 해봅시다.

01 // your better API using IoC (Inversion Of Control)
02 public abstract class TraceListener {
03     public abstract void Trace(string message);
04 }
05  
06 public class Tracer {
07     TraceListener listener;
08  
09     public Tracer(TraceListener listener){
10         this.listener = listener;
11     }
12  
13     public void Trace(string message){
14         listener.Trace(message);
15     }
16 }
17  
18 // Dependency Injection
19 Tracer tracer = new Tracer(new FileListener());
20  
21 public void ProcessOrder(Order order){
22     tracer.Trace(order.Id);
23     
24 }

소스에서 보이는 IoC의 핵심 키워드인 XXXListenr(TraceListener)를 통해서 MessageQueue외에도 File, XML과 같은 다양한 형태로 출력을 할수 있을뿐만 아니라, 확장성과 테스팅이 좀더 용이 하게 되었습니다.

3단계: NINJA가 도와 드려요! 한발더 Dependency Injection (NInject)

IoC를 이용하여 좀더 변화에 유연하며 확장 가능한 소스코드가  생성되었습니다.

하지만 FileListener를 XXXListener로 변경을 위해서는 소스 코드를 변경하거나 Metadata 형식 (Component Configurator)를 직접 구축해야 합니다.

이러한 문제점들을 한방에 해결해 줄수 있는 정보들을 실시간을 삽입,삭제 변경할수 있는 Dependency Injection Container가 나왔습니다.

Container를 통해서 이제 우리는 Dependency의 제어가 한결 더 쉬워졌습니다.

위 의 예를 잠시 이용해 볼까요?


출처 : http://arload.wordpress.com/2008/12/07/dependency_managment/

반응형
Posted by blueasa
, |
Link : http://www.codeproject.com/KB/architecture/DesignPatternExampleCS.aspx

Simple examples illustrate Design Pattern

Introduction

Design patterns are some common ideas in writing programs. The whole list and their definitions can be found here. The link has very good descriptions and examples, so I won't repeat the definitions here. I think that the design patterns are not easy to understand, and there are too many examples to remember. In order to apply the design patterns to solve a problem, you would need to understand and remember the patterns so that you could see them in the problem. I couldn't remember even half of the names; I couldn't accurately recite a single pattern definition; and I am not sure whether I fully understand the definitions of the design patterns. However, I have been helped by a simple example which makes the patterns easy to understand and remember. I would like to share it and hope that it can help other people, too.

Background

I took the training from NetObjectives several years ago. I don't remember much of the definitions or principles from the training, but their example sticks in my mind. It is a simple problem but it holds several patterns in the problem.

The example is this: We need to design classes for two Shapes: Rectangle and Circle. We need to draw them on different devices: Console and Printer. The shapes can be moved and expanded. In the future, we might need to support other forms of transformation, such as rotate and distort. After transforming the shapes, we need to be able to undo it. We need to support more complex shapes which are comprised of simpler shapes.

Patterns in this Example

We first abstract the Rectangle and Circle as Shape. If the Shapes know how to draw on Printer and Console, then we would need different versions of Shapes. So, it is better to separate the Shape from the Drawing devices.We also abstract the Console and Printer as Drawing devices. This is actually using Bridge pattern because that it decouples the implementation of Shape and Drawing. In the following snippet, the IShape holds a reference to IDrawing object. Shape has two implementations: Circle and Rectangle. Drawing has two implementations: V1 and V2.

Collapse | Copy Code
/*
IShape------------->IDrawing
 /    \              / \
Circle Rectangle    V1 V2
*/
abstract class IShape
{
 protected IDrawing drawing;
 abstract public void Draw();
}
abstract class IDrawing
{
    abstract public void DrawLine();
 abstract public void DrawCircle();
}
class Circle:IShape
{
 override public void Draw(){drawing.DrawCircle();}
}
class Rectangle:IShape
{
 override public void Draw(){drawing.DrawLine(); drawing.DrawLine();}
}
class V1Drawing:IDrawing
{
 override public void DrawLine(){}
 override public void DrawCircle(){}
}
class V2Drawing:IDrawing
{
 override public void DrawLine(){}
 override public void DrawCircle(){}
}

Suppose that there are fixed number of Shapes, but there will be new types of Transformations. In order to support new types of Transformations, we can use the Visitor pattern to make Shapes class future proof. In the following snippet, the Shape class defines operation interface Accept(ITransform), so that new transform types can operated on shapes without modifying Shape classes.

Collapse | Copy Code
/*
   IShape---------->ITransform
 /    \            / \
Circle Rectangle Move Expand
*/
    abstract class IShape
    {
        abstract public void Accept(ITransform transform);
    }
    abstract class ITransform
    {
        abstract public void TransformCircle(Circle c);
        abstract public void TransformRectangle(Rectangle rect);
    }
    class Circle : IShape
    {
        override public void Accept(ITransform transform)
        {
            transform.TransformCircle(this);
        }
    }
    class Rectangle : IShape
    {
        override public void Accept(ITransform transform)
        {
            transform.TransformRectangle(this);
        }
    }
    class Move : ITransform
    {
        override public void TransformCircle(Circle c) { }
        override public void TransformRectangle(Rectangle rect) { }
    }
    class Expand : ITransform
    {
        override public void TransformCircle(Circle c) { }
        override public void TransformRectangle(Rectangle rect) { }
    }

If we want to undo the transform, we can use Memento pattern, where we can store the state of the Shape object without exposing its internal state.

Collapse | Copy Code
//Memento--->IShape

interface IMemento
{
 void ResetState();
}
class IShape
{
 public abstract IMemento GetMemento();
}

If we have a shape which is comprised of collections of other shapes, we can use Composite pattern so that we may handle the complex shape the same way.

Collapse | Copy Code
/*        IShape
         / | \
    Circle | Rectangle
           |
    CompositeShape 1--->* IShape

*/

class CompositeShape : IShape
{
 List<IShape> list = new List<IShape>();
}

If you call MembewiseClone() on an object, you only get a shallow copy of the object. The book “C# 3.0 Design Patterns” has a solution for DeepCopy. It serializes the object into a MemoryStream, and then Deserializes it back to a cloned object.

Collapse | Copy Code
[Serializable]
class IShape
{
public IShape DeepCopy()
{
 using (MemoryStream m = new MemoryStream())
 {
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(m, this);
    m.Seek(0, SeekOrigin.Begin);
    IShape ret = (IShape)f.Deserialize(m);
    ret.Drawing = drawing;
    return ret;
 }
}
}

Design Pattern Examples in C# and .NET Libraries

There are many examples in C# and .NET libraries. For example:

Adapter Pattern

Streams are tools to read/write a sequence of bytes. If you need to read/write strings or characters, you would need to create a Reader/Writer class. Fortunately, all the Reader/Writer classes can be constructed from a stream object. So, I think that the Reader/Writer classes are adapters which convert a byte array interface to string/char interface.

Collapse | Copy Code
Reader/Writer-->Stream
BinaryReader/Writer{ReadChars,ReadString}
TextReader/Writer{ReadLine,ReadBlock}
|-StreamReader/Writer
|-StringReader/Writer
Stream{Read(byte[]), Write(byte[], Seek, Position)
|
|-NetworkStream(socket){DataAvailable}
|-FileStream(path){ Lock/Unlock/GetACL,IsAsync}
|-MemoryStream (byte[]){GetBuffer(), WriteTo(stream),ToArray()}

I think "boxing" is also an adapter. It converts a value type into a reference type.

Decorator Pattern

When you need encryption or compression, or need to add a buffer on the network stream, you can use Decorator pattern. The bufferedStream, CryptoStream, and DeflateStream are decorators to other streams. They attach additional functionalities to existing streams without changing the interface of the original streams.

Collapse | Copy Code
Stream
|
|- BufferedStream(stream,buffersize), for network
|- CryptoStream: for encryption
|- DeflateStream: for compression

Flyweight Pattern

To save space, String class holds a reference to an Intern object. So, if two strings have the same literal, they share the same storage space. It uses "sharing" to support a large number of fine grained objects efficiently so that it is using Flyweight pattern.

Collapse | Copy Code
String s3 = String.Intern(s2); 

Object Pool Pattern

Creating threads are expensive. You can call Threadpool.QueueUserWorkitem() which uses thread pool to better use the system resources. So, I think that threadpool is a good example of object pool pattern.

Observer Pattern

Observer pattern defines a one to many dependency so that when one object changes state, all its dependencies are notified. The event in C# is exactly for this purpose. An event can be subscribed:

Collapse | Copy Code
UnhandledExceptionEventHandler handler =
	(object sender, UnhandledExceptionEventArgs v) => {
Console.WriteLine(
  "sender={0}, arg={1}, exception={2}, v.IsTerminating={3}",
  sender, v, v.ExceptionObject, v.IsTerminating);
  };
AppDomain.CurrentDomain.UnhandledException += handler;
throw new Exception("hiii");

To unsubscribe, you just need to call event-=.

Collapse | Copy Code
AppDomain.CurrentDomain.UnhandledException -= handler;

You can also define your own events:

Collapse | Copy Code
static public event EventHandler<EventArgs> breakingNews;
if(breakingNews!=null)
breakingNews("NBC", EventArgs.Empty);

If you don't want to check whether the event is null, just add a dummy subscriber:

Collapse | Copy Code
breakingNews += delegate { }; 

Iterator Pattern

Iterator provides a way to access the elements inside an aggregate object. C# has foreach keyword which makes Iterator really easy. It is hard for me to understand what Enumerable and Enumerator are. It is even more confusing why I have to define GetEnumerator for both IEnumerable and IEnumerable<T>. So, I just try to remember this example:

Collapse | Copy Code
class IntEnumerable:IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
    yield return 1;
    yield return 2;
}
IEnumerator IEnumerable.GetEnumerator()
{
    return this.GetEnumerator();
}
}
//Then you use the iterator like this:
foreach(int i in new IntEnumerable())Console.WriteLine(i);

Singleton Pattern

The simplest way to create a singleton is to use a static variable in C#.

Collapse | Copy Code
class Singleton
{
    private static Singleton instance = new Singleton();
    public static Singleton GetInstance()
    {
        return instance;
    }
}

Some people use the double-checked-lock to create a thread safe lazy initialization singleton. However, it is so subtle to implement that some people consider it as Anti-pattern: [Read this].

Netobjectives has this method which I think is the best way to create a thread safe lazy init singleton. Note that the static constructor disables BeforeFieldInit flag (see this link). The inner class Nested avoids early init when other static fields or methods of Singleton are called.

Collapse | Copy Code
class Singleton
{
    private Singleton() { }
    public static Singleton GetInstance()
    {
        return Nested.instance;
    }
    private class Nested
    {
        internal static Singleton instance = new Singleton();
        //static constructor to prevent beforefieldInit
        // see http://www.yoda.arachsys.com/csharp/beforefieldinit.html
        static Nested() {}
    }
} 

Using the Code

The sample code is written in C# 3.0.

Conclusion

I am sure I missed many patterns and might have misunderstood some in the above examples. If so, please let me know so that they can be corrected.

I have benefited from the examples I got from the training in NetObjectives. I felt that the training is an eye opener and I really learnt a lot. After a couple years, the only thing I still remember is their example about Shape, Drawing, and Transform. If you are not familiar with design patterns, I hope that this example gets you interested in reading Wikipedia or a book, or taking the training from NetObjectives. If you have taken their training or are familiar with design patterns, then the examples might help you quickly refresh your memory of design patterns.
One thing I learned is that if my code has a lot of copy/paste, or has a lot of switch/case statements, then I might need to think about using some design patterns.

I think the idea of design pattern is similar to Database normalization. During database normalization, we break one big table into several smaller tables, so that the total number of rows in tables is much smaller, and modification in one small table won't affect other tables. If we can separate/isolate the concepts in our problem, then we are likely applying the ideas of design pattern already, even if we don't remember the pattern names.

History

  • 23rd February, 2009: Initial post
  • 6th March, 2009: Article updated
    • Fixed a broken link
    • Fixed the snippet compilation errors
    • Removed some samples

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

반응형

'Programming > Design Pattern' 카테고리의 다른 글

C# 디자인패턴  (0) 2010.12.15
Dependency를 관리하는 방법  (0) 2010.10.21
GoF의 디자인패턴  (0) 2010.07.23
FSM - 유한 상태 기계 (Finite State Machine)  (0) 2010.07.09
GoF Design Pattern 요약  (0) 2010.05.31
Posted by blueasa
, |



출처 : 기억안남..;;
반응형

'Programming > Design Pattern' 카테고리의 다른 글

C# 디자인패턴  (0) 2010.12.15
Dependency를 관리하는 방법  (0) 2010.10.21
Design Pattern Examples in C#  (0) 2010.07.23
FSM - 유한 상태 기계 (Finite State Machine)  (0) 2010.07.09
GoF Design Pattern 요약  (0) 2010.05.31
Posted by blueasa
, |


학원에서 강사님이 썼던 유한 상태기계 패턴를 정리해본다.

디자인패턴은 한눈에 볼수 있는게 좋아보여서 UML로 만들어 보았다.

강사님은 이 패턴으로 손쉽게 게임의 Scene를 바꾸는것에 썼다.

내가 이걸 았았다면 졸업작품때 만든 게임을 좀더 좋게 만들었을수도 있다는 생각이 든다.

 

여기서 추가로 볼것은 씬을 저장할때 Map를 이용했는데 이때 저장할때  쓰는  키값을 unsigned int 로 바꿔서 하는 것(해싱맵) 과 시간 프레임 클래스인 CFrameRate클래스를 추가적으로 보면 좋을것 같다.

 

 

main에서는 CSceneMgr 객체를 생성한후 사용할 씬(Cscene클래스를 상속받은) 클래스를 AddScene()함수로 CSceneMgr에 등록한후 ChangeScene()함수로 실행할 씬를 선택한다

그리루프에서는 Do()실행시키면 ChangeScene()에 의해 선택된 클래스의 것이 실행된다. 

반응형

'Programming > Design Pattern' 카테고리의 다른 글

C# 디자인패턴  (0) 2010.12.15
Dependency를 관리하는 방법  (0) 2010.10.21
Design Pattern Examples in C#  (0) 2010.07.23
GoF의 디자인패턴  (0) 2010.07.23
GoF Design Pattern 요약  (0) 2010.05.31
Posted by blueasa
, |
반응형

'Programming > Design Pattern' 카테고리의 다른 글

C# 디자인패턴  (0) 2010.12.15
Dependency를 관리하는 방법  (0) 2010.10.21
Design Pattern Examples in C#  (0) 2010.07.23
GoF의 디자인패턴  (0) 2010.07.23
FSM - 유한 상태 기계 (Finite State Machine)  (0) 2010.07.09
Posted by blueasa
, |