๋ฐ˜์‘ํ˜•

์˜ต์ €๋ฒ„ ํŒจํ„ด(Observer Pattern)

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๊ด€์ฐฐ์ž ํŒจํ„ด์ด๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์ด๋ฃจ๊ณ  ์žˆ์œผ๋ฉฐ, ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ๋ชจ๋“  ์˜ต์ €๋ฒ„๋“ค์—๊ฒŒ ์ •๋ณด๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ข€ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”? (์˜ˆ์ œ ์ฝ”๋“œ๋Š” ๋ณธ๋ฌธ ํ•˜๋‹จ์— ์ฒจ๋ถ€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.)

์˜ˆ์‹œ 1. ์œ ํŠœ๋ธŒ ๊ตฌ๋… ์•Œ๋žŒ

์ฒ ์ˆ˜(Observer)๊ฐ€ ์ฝ”๋”ฉ ๊ณต๋ถ€๋ฅผ ์œ„ํ•ด ์œ ํŠœ๋ธŒ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ด€๋ จ ์˜์ƒ์„ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Luckygg(Subject)๋ผ๋Š” ์‚ฌ๋žŒ์˜ ์ฑ„๋„์— ์ข‹์€ ์˜์ƒ๋“ค์ด ์žˆ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜ ๋‘˜ ๊ฐœ์ œ ๋œ ์˜์ƒ๋“ค์„ ๋ณด๊ฒŒ ๋˜๋‹ค๊ฐ€ ์–ด๋Š์ƒˆ ๋ชจ๋“  ์˜์ƒ๋“ค์„ ๋ณด๊ฒŒ ๋์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ƒˆ๋กœ์šด ์˜์ƒ์ด ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ์˜์ƒ์ด ์–ธ์ œ ์˜ฌ๋ผ์˜ฌ ์ค„ ์•Œ๊ณ  ๋งˆ๋ƒฅ ๊ธฐ๋‹ค๋ฆด๊นŒ์š”? ์ด๋•Œ, ์ฑ„๋„ ๊ตฌ๋…(Register)์„ ํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ์•Œ๋ฆผ(Notify)์„ ๋ฐ›๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ํŠœ๋ธŒ ์ฑ„๋„ ๊ด€๋ฆฌ์ž๊ฐ€ ์˜์ƒ์„ ์—…๋ฐ์ดํŠธํ•˜๋ฉด, ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ์•Œ๋ฆผ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์œ ํŠœ๋ธŒ ์ฑ„๋„ ์˜ต์ €๋ฒ„ ํŒจํ„ด ์˜ˆ์‹œ

์˜ˆ์‹œ 2. ์‹ ๋ฌธ์‚ฌ ๊ตฌ๋…

์š”์ฆ˜์—๋Š” ์ข…์ด ์‹ ๋ฌธ์„ ๋ณด๋Š” ์‚ฌ๋žŒ์ด ๊ฑฐ์˜ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ์‹ ๋ฌธ์‚ฌ๋“ค์ด ์ธํ„ฐ๋„ท์œผ๋กœ๋„ ์ œ๊ณต์„ ํ•˜๊ณ , ๋ฌด๋ฃŒ์ด๋ฉฐ ์–ธ์ œ ์–ด๋””์„œ๋“  ์Šค๋งˆํŠธํฐ์œผ๋กœ ๋‰ด์Šค๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ํ•˜์ง€๋งŒ ์ง€๊ธˆ์ฒ˜๋Ÿผ ์Šค๋งˆํŠธํฐ์ด ๋ณด๊ธ‰๋˜๊ธฐ ์ „์—๋Š” ์ข…์ด ์‹ ๋ฌธ์„ ์–ด๋–ป๊ฒŒ ๊ตฌ๋…ํ–ˆ์„๊นŒ์š”? ์‚ฌ์šฉ์ž(Observer)๊ฐ€ ์‹ ๋ฌธ์‚ฌ(Subject)์— ์‹ ๋ฌธ ๊ตฌ๋…์„ ์‹ ์ฒญ(Register)ํ•˜๋ฉด, ์‹ ๋ฌธ์‚ฌ์—์„œ๋Š” ํ•ด๋‹น ์ง‘์— ์‹ ๋ฌธ์„ ๋ฐฐ๋‹ฌํ•˜๋„๋ก ์ฃผ์†Œ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๋‚  ์ƒˆ๋ฒฝ์— ์‹ ๋ฌธ ๋ฐฐ๋‹ฌ๋ถ€๊ฐ€ ๊ตฌ๋…์ž ๋ชฉ๋ก์— ์žˆ๋Š” ๋ชจ๋“  ์ง‘์— ์‹ ๋ฌธ์„ ๋ฐฐ๋‹ฌ(Notify)ํ•˜๊ฒŒ ๋˜์ฃ . ๊ทธ๋Ÿฐ๋ฐ ํ•œ ๋‹ฌ ๋’ค, ํ•œ ๊ณ ๊ฐ์ด ์‹ ๋ฌธ์„ ์›ํ•˜์ง€ ์•Š์•„ ๊ตฌ๋…์„ ํ•ด์ง€(Remove)ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด ๊ณ ๊ฐ์€ ์‹ ๋ฌธ์‚ฌ์˜ ๊ตฌ๋…์ž ๋ชฉ๋ก์—์„œ ์ œ์™ธ๋˜๊ฒ ์ฃ . ๋‹ค์Œ๋‚  ์‹ ๋ฌธ ๋ฐฐ๋‹ฌ๋ถ€๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” ๋ชฉ๋ก์—๋Š” ์ด ๊ณ ๊ฐ์˜ ์ฃผ์†Œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ๋‹ฌํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์‹ ๋ฌธ์‚ฌ ์˜ต์ €๋ฒ„ ํŒจํ„ด ์˜ˆ์‹œ

๋‘ ์˜ˆ์‹œ์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ๋ณด๋ฉด ๊ตฌ์กฐ๊ฐ€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์•„์ฃผ ์ „ํ˜•์ ์ด๊ณ  ๊ธฐ๋ณธ์ ์ธ ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํŠน์ • ์ •๋ณด๋ฅผ ์—ฌ๋Ÿฌ ๋ทฐ์—์„œ ๋™์‹œ์— ์–ป๊ธฐ ์œ„ํ•ด ์ฃผ์ œ์ž(Subject)์— ๊ตฌ๋…์ž(Observer)๋ฅผ ๋“ฑ๋ก(Register)ํ•˜์—ฌ ์ •๋ณด๋ฅผ ๋ฐ›๋Š”(๊ฐฑ์‹ , Notify) ๊ฒƒ์„ ์˜ต์ €๋ฒ„ ํŒจํ„ด(Observer pattern)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋“ฑ๋ก์„ ํ–ˆ์œผ๋‹ˆ ํ•ด์ง€(Remove)๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ •์˜ ๋ฐ ๊ตฌ์กฐ

Head First Design Pattern์—์„œ๋Š” ์˜ต์ €๋ฒ„ ํŒจํ„ด์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ทธ ๊ฐ์ฒด์— ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์—๊ฒŒ ์ •๋ณด๊ฐ€ ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์ผ๋Œ€๋‹ค(one-to-many) ์˜์กด์„ฑ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ต์ €๋ฒ„ ํŒจํ„ด์—์„œ ์ฃผ์ œ์ž๋Š” ์˜ต์ €๋ฒ„์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์˜ค์ง ์˜ต์ €๋ฒ„๊ฐ€ ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค(Interface)๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๊ฒƒ ๋งŒ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์˜ต์ €๋ฒ„๊ฐ€ ๋ฌด์Šจ ๋™์ž‘์„ ํ•˜๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์˜ต์ €๋ฒ„๋Š” ์–ธ์ œ๋“ ์ง€ ์ƒˆ๋กœ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ƒˆ๋กœ์šด ํ˜•์‹์˜ ์˜ต์ €๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ์—๋„ ์ฃผ์ œ์— ์ „ํ˜€ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ด€๊ณ„๋ฅผ ๋Š์Šจํ•œ ๊ฒฐํ•ฉ(Loose coupling)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ํŠน์ง•์ด ์žˆ์„๊นŒ์š”? ์•„๋ž˜ UML์„ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Subject interface๋Š” ๋“ฑ๋ก, ํ•ด์ œ, ๊ฐฑ์‹ ์„ ์œ„ํ•œ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ์ƒ์†๋ฐ›๋Š” concrete Subject Class๋Š” ๋“ฑ๋ก, ํ•ด์ œ, ๊ฐฑ์‹ ์„ ๊ตฌํ˜„ํ•˜๊ณ  ๊ธฐํƒ€ ํ•จ์ˆ˜๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Observer interface๋Š” Subject์—์„œ ๊ฐฑ์‹ ํ•  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” update API๋งŒ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ Observer interface๋ฅผ ์ƒ์†๋ฐ›๋Š” A, B, C Class์— update๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

์˜ต์ €๋ฒ„ ํŒจํ„ด ๊ตฌ์กฐ

์ฝ”๋“œ ์˜ˆ์ œ

๊ทธ๋Ÿผ ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ณด์—ฌ๋“œ๋ฆด ์˜ˆ์‹œ๋Š” Concrete Subject class์—์„œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋“ฑ๋ก๋œ ๋ชจ๋“  Observer๋“ค์—๊ฒŒ ๊ฐฑ์‹ ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

Subject interface์ž…๋‹ˆ๋‹ค. Observer๋ฅผ ๋“ฑ๋ก, ํ•ด์ œ, ๊ฐฑ์‹ ํ•˜๊ธฐ ์œ„ํ•œ API๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

public interface Subject
{
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

Observer interface์ž…๋‹ˆ๋‹ค. update ํ•จ์ˆ˜์— ์ธ์ž๋กœ value๊ฐ€ ๋„˜์–ด์˜ต๋‹ˆ๋‹ค.

public interface Observer
{
    void update(int value);
}

ConcreteSubject๋Š” Subject interface๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ArrayList๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ observer ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 

public class ConcreteSubject : Subject
{
	IList _observers = new ArrayList();
	int _value;
	public ConcreteSubject()
	{
		_value = 0;
	}
	public void notifyObservers()
	{
		foreach (Observer o in _observers)
			o.update(_value);
	}

	public void registerObserver(Observer o)
	{
		_observers.Add(o);
	}

	public void removeObserver(Observer o)
	{
		_observers.Remove(o);
	}
	public void setValue(int value)
	{
		_value = value;
		notifyObservers();
	}
}

์•„๋ž˜๋Š” ๊ฐ Observer interface๋ฅผ ์ƒ์†๋ฐ›๋Š” A, B, C class์ž…๋‹ˆ๋‹ค. ๋˜‘๊ฐ™์€ ํด๋ž˜์Šค๊ฐ€ ์ค‘๋ณต๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ ํด๋ž˜์Šค ์ƒ์„ฑ์ž์—์„œ ConcreteSubject๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ณ , registerObserver๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž์‹ ์„ ์˜ต์ €๋ฒ„๋กœ์„œ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

public class A : Observer
{
	ConcreteSubject _subject;
	public A(ConcreteSubject subject)
	{
		_subject = subject;
		subject.registerObserver(this);
	}
	public void update(int value)
	{
		Console.WriteLine(String.Format("A Class update, value: {0}", value));
	}
}

public class B : Observer
{
	ConcreteSubject _subject;
	public B(ConcreteSubject subject)
	{
		_subject = subject;
		subject.registerObserver(this);
	}
	public void update(int value)
	{
		Console.WriteLine(String.Format("B Class update, value: {0}", value));
	}
}

public class C : Observer
{
	ConcreteSubject _subject;
	public C(ConcreteSubject subject)
	{
		_subject = subject;
		subject.registerObserver(this);
	}
	public void update(int value)
	{
		Console.WriteLine(String.Format("C Class update, value: {0}", value));
	}
}

์ด์ œ ๋ฉ”์ธ ํ”„๋กœ๊ทธ๋žจ ์ž…๋‹ˆ๋‹ค. ConcreteSubject ๋ฐ A, B, C ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ A, B, C ๊ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ์˜ต์ €๋ฒ„๋กœ์„œ ConcreteSubject ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ์ค„์ธ setValue(10)์„ ํ˜ธ์ถœํ•˜๋ฉด ๋ชจ๋“  ์˜ต์ €๋ฒ„์˜ update๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

class Program
{
	static void Main(string[] args)
	{
		ConcreteSubject concreteSubject = new ConcreteSubject();

		A observerA = new A(concreteSubject);
		B observerB = new B(concreteSubject);
		C observerC = new C(concreteSubject);

		concreteSubject.setValue(10);
	}
}

๊ฒฐ๊ณผ ํ™”๋ฉด์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ ๊ฒฐ๊ณผ ํ™”๋ฉด

์—ฌ๊ธฐ๊นŒ์ง€ ์„ค๋ช…ํ•œ ๋‚ด์šฉ์€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๋™์ž‘์ž…๋‹ˆ๋‹ค. ConcreteSubject์—์„œ ๊ฐ’์„ ์„ค์ •ํ•ด์•ผ ๋ชจ๋“  ์˜ต์ €๋ฒ„๋Š” ๊ฐฑ์‹ ๋งŒ ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ์‘์šฉํ•˜๋ฉด ๊ฐ ์˜ต์ €๋ฒ„์—์„œ๋„ ๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ ๋ชจ๋“  ์˜ต์ €๋ฒ„์— ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ  MVC ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ์ดˆ ๊ฐœ๋…์ด๋‹ˆ ๊ผญ ์ตํ˜€๋‘์‹œ๊ธธ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

ExamObserverPattern.zip
0.18MB

๋ฐ˜์‘ํ˜•