7. Observer Pattern ( 옵져버 패턴 C# )

Unity3D 2014. 3. 21. 11:52
반응형
http://hongjinhyeon.tistory.com/47

 

[읽기전에]

UML 다이어그램이 이해가 가지 않으시면 다음의 포스팅을 보고오세요 : UML클래스 다이어그램 기본상식 http://hongjinhyeon.tistory.com/25

포스팅되는 디자인 패턴의 예는 스타크래프트를 기본으로 하였습니다 : 디자인 패턴을 시작하며 http://hongjinhyeon.tistory.com/24



<기본 정의 >


1. Observer Pattern 정의

 

-한 객체의 상태가 바뀌면 그 책체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로

일대다(one-to-many) 의존성을 정의한다.

(Define a one-to-many dependency between objects so that when one object changes state,

all its dependents are notified and updated automatically.)


-한 객체의 상태가 변경되면 그 객체에 의존하는 모든 객체에 연락을 한다.

 


2. UML Diagram


 



3. 사용용도 및 장점


-옵져버 패턴은 MVC 모델에서 View단( 사용자에게 보여주는 단계)에서 많이 나타날수가 있다, 객체의 상태에대한

참조를 여러군데에서 하고 있을시에 ( 특히 여러개의 창에서 참조가 될시에 ) 사용될 수 있다.


-객체의 상태를 참조하는 대상에 일관성을 보장한다.


-객체의 상태가 변경될 시에 참조를 하고있는 대상들은 자동으로 상태가 업데이트가 된다.



4. 소스


 
001.using System;
002.using System.Collections.Generic;
003.
004.namespace DoFactory.GangOfFour.Observer.Structural
005.{
006. /// <summary>
007. /// MainApp startup class for Structural
008. /// Observer Design Pattern.
009. /// </summary>
010. class MainApp
011. {
012. /// <summary>
013. /// Entry point into console application.
014. /// </summary>
015. static void Main()
016. {
017. // Configure Observer pattern
018. ConcreteSubject s = new ConcreteSubject();
019.
020. s.Attach(new ConcreteObserver(s, "X"));
021. s.Attach(new ConcreteObserver(s, "Y"));
022. s.Attach(new ConcreteObserver(s, "Z"));
023.
024. // Change subject and notify observers
025. s.SubjectState = "ABC";
026. s.Notify();
027.
028. // Wait for user
029. Console.ReadKey();
030. }
031. }
032.
033. /// <summary>
034. /// The 'Subject' abstract class
035. /// </summary>
036. abstract class Subject
037. {
038. private List<Observer> _observers = new List<Observer>();
039.
040. public void Attach(Observer observer)
041. {
042. _observers.Add(observer);
043. }
044.
045. public void Detach(Observer observer)
046. {
047. _observers.Remove(observer);
048. }
049.
050. public void Notify()
051. {
052. foreach (Observer o in _observers)
053. {
054. o.Update();
055. }
056. }
057. }
058.
059. /// <summary>
060. /// The 'ConcreteSubject' class
061. /// </summary>
062. class ConcreteSubject : Subject
063. {
064. private string _subjectState;
065.
066. // Gets or sets subject state
067. public string SubjectState
068. {
069. get { return _subjectState; }
070. set { _subjectState = value; }
071. }
072. }
073.
074. /// <summary>
075. /// The 'Observer' abstract class
076. /// </summary>
077. abstract class Observer
078. {
079. public abstract void Update();
080. }
081.
082. /// <summary>
083. /// The 'ConcreteObserver' class
084. /// </summary>
085. class ConcreteObserver : Observer
086. {
087. private string _name;
088. private string _observerState;
089. private ConcreteSubject _subject;
090.
091. // Constructor
092. public ConcreteObserver(
093. ConcreteSubject subject, string name)
094. {
095. this._subject = subject;
096. this._name = name;
097. }
098.
099. public override void Update()
100. {
101. _observerState = _subject.SubjectState;
102. Console.WriteLine("Observer {0}'s new state is {1}",
103. _name, _observerState);
104. }
105.
106. // Gets or sets subject
107. public ConcreteSubject Subject
108. {
109. get { return _subject; }
110. set { _subject = value; }
111. }
112. }
113.}


 


5. 실행결과


 

Observer X's new state is ABC

Observer Y's new state is ABC

Observer Z's new state is ABC

 




< 실제 적용 >


1. UML Diagram






2. 사용용도 및 장점


-옵저버의 패턴은 스타크래프트에서 필수적인 요소입니다. 사용되는 곳은 여러곳이 있는데 여기서 예를 드는것은 유닛의 상태입니다.

마린의 체력 상태를 모니터링하는 곳은 메인화면( 케릭터의 에너지바가 칸수로 나옴 ), 상태창(캐릭터의상태가 숫자 표시 및 색으로 표현),

적의 화면 ( 상대편의 화면 및 케릭터 상태창에서의 체력 표시 )이 있습니다.


-아군 마린이 적의 마린의 공격으로 체력이 깍였다면 위의 3군데 모두 동일하게 남은 체력이 보여야 할 것입니다. 이럴때에 옵져버 패턴을

사용하면 동일한 시점에 동일한 상태를 나타내게 됩니다.


 


3. 소스


001.using System;
002.using System.Collections.Generic;
003.using System.Linq;
004.using System.Text;
005.
006.namespace Observer
007.{
008. class Program
009. {
010. static void Main(string[] args)
011. {
012.
013. Marine ourMarine = new Marine("아군 마린", 100);
014. ourMarine.Attach(new MainScreen());
015. ourMarine.Attach(new StatusScreen());
016. ourMarine.Attach(new EnemyScreen());
017.
018. ourMarine.Health = 60;
019. ourMarine.Health = 40;
020.
021. Console.ReadKey();
022. }
023.
024. abstract class Unit
025. {
026. private string name;
027. private int health;
028. private List<UnitViewer> unitViewers = new List<UnitViewer>();
029.
030. public Unit(string name, int health)
031. {
032. this.name = name;
033. this.health = health;
034. }
035.
036. public void Attach(UnitViewer investor)
037. {
038. unitViewers.Add(investor);
039. }
040.
041. public void Detach(UnitViewer investor)
042. {
043. unitViewers.Remove(investor);
044. }
045.
046. public void Notify()
047. {
048. foreach (UnitViewer unitviewr in unitViewers)
049. {
050. unitviewr.Update(this);
051. }
052. }
053.
054.
055. public int Health
056. {
057. get { return health; }
058. set
059. {
060. health = value;
061. Notify();
062. }
063. }
064.
065. public string Name
066. {
067. get { return name; }
068. }
069. }
070.
071. class Marine : Unit
072. {
073. public Marine(string name, int health)
074. : base(name, health)
075. {
076. }
077. }
078.
079.
080. interface UnitViewer
081. {
082. void Update(Unit unit);
083. }
084.
085.
086. class MainScreen : UnitViewer
087. {
088. private Unit unit;
089.
090. public void Update(Unit _unit)
091. {
092. this.unit = _unit;
093. Console.WriteLine("메인화면 {0} 상태 변경 : 체력 {1}", this.unit.Name, this.unit.Health.ToString());
094. }
095.
096. public Unit Unit
097. {
098. get { return unit; }
099. set { unit = value; }
100. }
101. }
102.
103. class StatusScreen : UnitViewer
104. {
105. private Unit unit;
106.
107. public void Update(Unit _unit)
108. {
109. this.unit = _unit;
110. Console.WriteLine("상태창 {0} 상태 변경 : 체력 {1}", this.unit.Name, this.unit.Health.ToString());
111. }
112.
113. public Unit Unit
114. {
115. get { return unit; }
116. set { unit = value; }
117. }
118. }
119.
120. class EnemyScreen : UnitViewer
121. {
122. private Unit unit;
123.
124. public void Update(Unit _unit)
125. {
126. this.unit = _unit;
127. Console.WriteLine("적 상태창 {0} 상태 변경 : 체력 {1}", this.unit.Name, this.unit.Health.ToString());
128. }
129.
130. public Unit Unit
131. {
132. get { return unit; }
133. set { unit = value; }
134. }
135. }
136. }
137.}

-UnitViewer를 인터페이스로 선언한 것은 참조되는 클래스들이 연관성이 많이 없을 때 유용하다.

굳이 UnitViewer를 상속해야하는 제한에서 벗어나서 마린의 객체를 참조하고자 하는 클래스들은 옵저버 인터페이스를 구현만 하면

상속받은 객체가 아니라도 마린의 상태를 볼 수 있게된다. (즉 더 유연한 구현을 할수가 있게된다.)



4. 실행결과





5. 피드백


-옵져버 패턴은 현업에서도 자주 사용될 수있는 패턴인듯하다. 특히 사용자에게 자료를 여러군데에서 보여줄때, 자료가 수정되면

열려진 창에서 모두데이터가 수정되게 하는 부분에서 유용할 듯 하다.




[참조]

-http://www.dofactory.com

-Head First Design Patterns

반응형

'Unity3D' 카테고리의 다른 글

OnApplicationQuit  (0) 2014.03.25
monodevelop line endings policy  (0) 2014.03.24
[Unity] Basic Character Customization Tutorial  (0) 2014.03.20
I18N.CJK.dll  (0) 2014.03.20
Unity3d + Node.js 연동 테스트  (0) 2014.03.17
: