[E-Z] Design Pattern๐Ÿง

Design Pattern

C++ ๋ฌธ๋ฒ• ์ •๋ฆฌ

constructor

์ƒ์†๊ณผ ์ƒ์„ฑ์ž

  • ํŒŒ์ƒ ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋Š” ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•จ
  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ถ”๊ฐ€ํ•จ
  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋งŒ๋“ค๋ฉด ํ•ญ์ƒ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์˜ ๋””ํดํŠธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•จ

Base() Derived(int) ~Derived() ~Base()

#include <iostream>

class Base
{
public:
	Base()     { std::cout << "Base()"    << std::endl; }
	Base(int a){ std::cout << "Base(int)" << std::endl; }
	~Base()    { std::cout << "~Base()"   << std::endl; }
};

class Derived : public Base
{
public:		
	Derived()		// ==> Derived() : Base()
	{ 
		std::cout << "Derived()" << std::endl; 
	}
	Derived(int a)	// ==> Derived(int a) : Base()
	{ 
		std::cout << "Derived(int)" << std::endl;
	}
	~Derived()		
	{ 
		std::cout << "~Derived()" << std::endl; 

		// ~Base()
	}
};

int main()
{
//	Derived d1;		
	Derived d2(5);	// call Derived::Derived(int)

}

Base์— ๋””ํดํŠธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์„ ๋•Œ

ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•จ

#include <iostream>

class Base
{
public:
	// ํ•ต์‹ฌ : Base์— ๋””ํดํŠธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์Œ.
	Base(int a){ }
};
class Derived : public Base
{
public:		
//	Derived() { }     // Derived() : Base(){ }
//	Derived(int a) { }// Derived(int a) : Base() { }

	Derived()      : Base(0) { }
	Derived(int a) : Base(a) { }
};
int main()
{

}
#include <string>

class People
{
	std::string name;
	int age;
public:
	People(const std::string& name, int age) : name(name), age(age) {}
};

class Student : public People
{
	int id;
public:
//	Student(int id) : id(id) {} // Student(int id) : People(),  id(id) {} //


	Student(const std::string& name, int age, int id) 
		: People(name, age),  id(id) {}
};

int main()
{
	Student s("kim", 20, 15);
}

protected์˜ ์˜๋ฏธ

  • ์ž์‹ ์˜ ๊ฐ์ฒด๋Š” ์ƒ์„ฑํ•  ์ˆ˜ ์—†์ง€๋งŒ(์ถ”์ƒ์  ์กด์žฌ)
  • ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋Š” ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋„
class Animal
{
//public:		// A, B ๋ชจ๋‘ ok
//private:		// A, B ๋ชจ๋‘ error
protected:
	Animal() {}
};

class Dog : public Animal
{
public:
	Dog() {}	// Dog() : Animal() {}
};

int main()
{
	// ๋‹ค์Œ์ค‘ ์—๋Ÿฌ๋ฅผ ๋ชจ๋‘ ๊ณจ๋ผ ๋ณด์„ธ์š”
	Animal a;	// A error // ์ถ”์ƒ์  ๊ฐœ๋…
	Dog    d;	// B ok // ํ˜„์‹ค ์„ธ๊ณ„ ๊ฐœ๋…
}

upcasting

  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์—์„œ ์ƒ์†๋ฐ›์€ ๋ฉค๋ฒ„๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ layout ์ƒ๋‹จ์— ๋†“์ž„
upcasting
๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํฌ์ธํ„ฐ๋กœ ํŒŒ์ƒ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
class Shape
{
public:
    int color;
};

class Rect : public Shape
{
public:
    int x, y, w, h;
};

int main()
{
    Rect rect;
    
    Rect*  p1 = &rect; // ok
    int*   p2 = &rect; // error. 
    Shape* p3 = &rect; // ok  
    
    Shape& r = rect;   // ok. 
    
}
  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํฌ์ธํ„ฐ๋กœ๋Š” ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ
  • ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๊ณ ์œ  ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ static_cast ํ•ด์•ผ ํ•จ
class Shape
{
public:
    int color;
};
class Rect : public Shape
{
public:
    int x, y, w, h;
};

int main()
{
    Rect rect;

    Shape* p = &rect; 
    
    p->color = 0; // ok
    p->x = 0;     // error
    static_cast<Rect*>(p)->x = 0; // ok
    
}

ํ™œ์šฉ

  • ๋™์ข…(๋™์ผ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋œ ํด๋ž˜์Šค)์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
  • ๋™์ข… ๋ณด๊ด€ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ
class Shape
{
public:
    int color;
};
class Rect : public Shape
{
public:
    int x, y, w, h;
};

// ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ๋„ํ˜•์„ ๊ฒ€์ •์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜
void changeBlack(Shape* p)
{
    p->color = 0;
}
/*
void changeBlack(Triangle* p)
{
    p->color = 0;
}
*/
int main()
{
    Rect r;
    changeBlack(&r); // ์‚ผ๊ฐํ˜• ์ƒ‰์„ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜์— ์‚ฌ๊ฐํ˜•์„ ๋„ฃ์„ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ -> Shape ์‚ฌ์šฉ
    
    Rect* buffer[10]; // ์‚ฌ๊ฐํ˜•๋งŒ ๋ณด๊ด€
    Shape* buffer[10]; // ๋ชจ๋“  ๋„ํ˜• ๋ณด๊ด€
}

dynamic_cast

Image

downcasting
๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํฌ์ธํ„ฐ(์ฐธ์กฐ) ํƒ€์ž…์„ ํŒŒ์ƒ ํด๋ž˜์Šค ํฌ์ธํ„ฐ(์ฐธ์กฐ) ํƒ€์ž…์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ฒƒ
  • ์•”์‹œ์ ์œผ๋กœ ๋  ์ˆ˜ ์—†์Œ
  • ๋ฐ˜๋“œ์‹œ ๋ช…์‹œ์  ์บ์ŠคํŒ…์„ ํ•ด์•ผ ํ•จ
#include <print>

class Animal
{
public:
	virtual ~Animal() {}
};
class Dog : public Animal {};
class Cat : public Animal {};

int main()
{
	Animal* pa = new Dog;
//	Animal* pa = new Cat;

//	Dog* pd = pa; // error
//	Dog* pd = static_cast<Dog*>(pa); 
	Dog* pd = dynamic_cast<Dog*>(pa); 

	std::println("{}", 
				 reinterpret_cast<void*>(pd));
}

Cat์„ Dog๋กœ static_castํ•  ๋•Œ

Image

int main()
{
	Animal* pa = new Cat;
	Dog* pd = static_cast<Dog*>(pa); // ๋ถ„๋ช…ํžˆ ์ž˜๋ชป๋์ง€๋งŒ ์„ฑ๊ณต์€ ํ•จ

	std::println("{}", 
				 reinterpret_cast<void*>(pd));
}
static_cast
  • ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ์บ์ŠคํŒ…
  • runtime ์˜ค๋ฒ„ํ—ค๋“œ ์—†์Œ
  • ์ปดํŒŒ์ผ ์‹œ๊ฐ„์—๋Š” pa๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์กฐ์‚ฌํ•  ์ˆ˜ ์—†์Œ -> ์ž˜๋ชป๋œ downcasting์„ ์กฐ์‚ฌํ•  ์ˆ˜ ์—†์Œ
  • ์ƒ์† ๊ด€๊ณ„์—์„œ๋Š” ํ•ญ์ƒ ์บ์ŠคํŒ… ์„ฑ๊ณต(์ฃผ์†Œ ๋ฐ˜ํ™˜)

ํ•ด๊ฒฐ์ฑ…์€ dynamic_cast์ด๋‹ค.

dynamic_cast
  • runtime ์บ์ŠคํŒ…
  • runtime ์˜ค๋ฒ„ํ—ค๋“œ ์žˆ์Œ
  • runtime์— pa๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ณณ์„ ์กฐ์‚ฌ ํ›„ ์ž˜๋ชป๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋งŒ ์ฃผ์†Œ ๋ฐ˜ํ™˜
  • ์ž˜๋ชป๋œ downcasting ์‚ฌ์šฉ ์‹œ 0์„ ๋ฐ˜ํ™˜
  • polymorphic type์— ๋Œ€ํ•ด์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•จ -> ๊ฐ€์ƒ ํ•จ์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋Š” ์ปดํŒŒ์ผ ์—๋Ÿฌ
class Animal
{
public:
//	virtual ~Animal() {}
};
class Dog : public Animal {};
class Cat : public Animal {};

int main()
{
	Animal* pa = new Cat;
	Dog* pd = dynamic_cast<Dog*>(pa); // 0

	std::println("{}", 
				 reinterpret_cast<void*>(pd));
}
ํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋กœ Animal* ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€
  • ๋ชจ๋“  ๋™๋ฌผ์˜ ๊ณตํ†ต ์ž‘์—…๋งŒ ํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ
  • ํ•จ์ˆ˜ ์•ˆ์—์„œ ์–ด๋–ค ๋™๋ฌผ์ธ์ง€ ์กฐ์‚ฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ์•„๋‹˜
class Animal
{
public:
	virtual ~Animal() {}
};
class Cat : public Animal {};
class Dog : public Animal 
{
public:
	void run() {}
};
void foo(Animal* p)
{
	// p๊ฐ€ Dog๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค๋ฉด run() ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ๋‹ค
	// p->run(); // error

	Dog* pdog = dynamic_cast<Dog*>(p);

	if ( pdog != nullptr )
	{
		pdog->run();
	}

}
int main()
{
	Dog d; foo(&d);
	Cat c; foo(&c);
}
dynamic_cast์™€ ๋””์ž์ธ
  • dynamic_cast ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋ณด๋‹ค๋Š” ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ
  • ๋””์ž์ธ ๊ด€์ ์—์„œ๋Š” dynamic_cast๋ฅผ ๋˜๋„๋ก์ด๋ฉด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Œ
void foo(Animal* p)
{
	// ๋ชจ๋“  ๋™๋ฌผ์˜ ๊ณตํ†ต์˜ ์ž‘์—…
}

void foo(Dog* p)
{
	foo(static_cast<Animal*>(p));
	p->run();
}

int main()
{
	Dog d; foo(&d);
	Cat c; foo(&c);
}

Abstract class

์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜(pure virtual function)
๊ตฌํ˜„์ด ์—†๊ณ  =0 ์œผ๋กœ ๋๋‚˜๋Š” ๊ฐ€์ƒํ•จ์ˆ˜
์ถ”์ƒ ํด๋ž˜์Šค(abstract class)
์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๊ฐ€ 1๊ฐœ ์ด์ƒ์ธ ํด๋ž˜์Šค
  • ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.
  • ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๋Š” ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
class Shape
{
public:
	virtual ~Shape() {}	

	virtual void draw() = 0;
};

int main()
{
//	Shape  s;	// error	
	Shape* p;	// ok
}

์ถ”์ƒ ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋œ ํด๋ž˜์Šค

  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค(์ถ”์ƒ ํด๋ž˜์Šค)๊ฐ€ ๊ฐ€์ง„ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜์˜ ๊ตฌํ˜„๋ถ€๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด ์—ญ์‹œ ์ถ”์ƒํด๋ž˜์Šค์ด๋‹ค.
  • ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ overrideํ•ด์„œ ๊ตฌํ˜„๋ถ€๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.
class Shape
{
public:
	virtual ~Shape() {}	

	virtual void draw() = 0;	
};

class Rect : public Shape
{
public:
	virtual void draw() {} // ๊ฐ์ฒด ์ƒ์„ฑ ๋ถˆ๊ฐ€
};

int main()
{
	Rect r; // ??
}

์ถ”์ƒํด๋ž˜์Šค์˜ ์˜๋„ :

  • ํŒŒ์ƒ ํด๋ž˜์Šค์—๊ฒŒ ํŠน์ • ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋“œ์‹œ ๋งŒ๋“ค๋ผ๊ณ  ์ง€์‹œํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ

๋„ํ˜•(Shape)์„ ๊ทธ๋ฆด ์ˆ˜ (draw) ์žˆ์„๊นŒ?

  • ์‚ฌ๊ฐํ˜•(Rect)์€ ์‹ค์ œ ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด์ด๋ฏ€๋กœ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์Œ
  • ๋„ํ˜•(Shape)์€ ์ถ”์ƒ์ ์ธ ๊ฐœ๋…์ด๋ฏ€๋กœ ๊ทธ๋ฆด ์ˆ˜๋Š” ์—†์Œ
#include <print>

class Shape
{
public:
	virtual ~Shape() {}

//	virtual void draw() { std::println("draw Shape"); }
	virtual void draw() = 0;
};

class Rect : public Shape 
{
public:
	void draw() override { std::println("draw Rect"); }

    // draw ๊ฐ€ ๊ฐ€์ƒ ํ•จ์ˆ˜์ผ ๋•Œ,
    // Rect๊ฐ€ draw๋ฅผ overrideํ•˜์ง€ ์•Š์œผ๋ฉด
    // Shape์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ๋ฌผ๋ ค ๋ฐ›๊ฒŒ ๋œ๋‹ค.
    // ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋งž๋‚˜?
};

int main()
{
	Rect r;
	r.draw();
}

๊ฐ€์ƒ ํ•จ์ˆ˜ vs ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜

ํ•จ์ˆ˜ ์ข…๋ฅ˜ ํŠน์ง•
๊ฐ€์ƒ ํ•จ์ˆ˜ ํŒŒ์ƒ ํด๋ž˜์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ํ•  ํ•„์š” ์—†์Œ, ์žฌ์ •์˜ ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ ๊ตฌํ˜„ ์ œ๊ณต
์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜ ํŒŒ์ƒ ํด๋ž˜์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„์„ ์ œ๊ณตํ•ด์•ผ ํ•จ, ๋ชจ๋“  ๋„ํ˜•์ด ์ง€์ผœ์•ผ ํ•˜๋Š” ๊ทœ์น™

interface

OCP, Open-Closed Principle
์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ์ฒด(ํด๋ž˜์Šค, ๋ชจ๋“ˆ, ํ•จ์ˆ˜ ๋“ฑ)๋Š” ํ™•์žฅ์— ๋Œ€ํ•ด ์—ด๋ ค ์žˆ์–ด์•ผ ํ•˜๊ณ , ์ˆ˜์ •์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ƒˆ๋กœ์šด ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด๋„ ๊ธฐ์กด ์š”์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ฒŒ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์›์น™

Image

#include <print>

class Camera
{
public:
	void take() { std::println("take picture"); }
};

class HDCamera
{
public:
	void take() { std::println("take HD picture"); }
};

class People
{
public:
	void use_camera(Camera* p) { p->take(); }
	void use_camera(HDCamera* p) { p->take(); }
};

int main()
{
	People p;
	Camera c;
	p.use_camera(&c);

	HDCamera hc;
	p.use_camera(&hc); // ?
}
์นด๋ฉ”๋ผ ์‚ฌ์šฉ์ž์™€ ์ œ์ž‘์ž ์‚ฌ์ด์—์„œ ์ง€์ผœ์•ผํ•˜๋Š” ์„ค๊ณ„ ๊ทœ์น™
์ถ”์ƒ ํด๋ž˜์Šค ์‚ฌ์šฉ

ํŒŒ์ƒ์ด๋ผ๋Š” ๋‹จ์–ด๋ณด๋‹ค๋Š” โ€œ๋ชจ๋“  ์นด๋ฉ”๋ผ๋Š” ICamera ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.โ€๋Š” ํ‘œํ˜„์ด ๋” ์ •ํ™•ํ•จ

#include <print>



// ๊ทœ์น™ : ๋ชจ๋“  ์นด๋ฉ”๋ผ๋Š” ICamera ๋กœ ๋ถ€ํ„ฐ ํŒŒ์ƒ ๋˜์–ด์•ผ ํ•œ๋‹ค.
// ๊ทœ์น™ : ๋ชจ๋“  ์นด๋ฉ”๋ผ๋Š” ICamera ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
//class ICamera
struct ICamera
{	
//public:
	virtual ~ICamera() {}

	virtual void take() = 0;	
};
์นด๋ฉ”๋ผ ์‚ฌ์šฉ์ž(People)
ํŠน์ • ์ œํ’ˆ์ด ์•„๋‹Œ ๊ทœ์น™์˜ ์ด๋ฆ„(์ถ”์ƒ ํด๋ž˜์Šค)๋งŒ ์‚ฌ์šฉ
class People
{
public:
	void use_camera(ICamera* p) { p->take(); }
};

๋‹ค์–‘ํ•œ ์นด๋ฉ”๋ผ ์ œํ’ˆ
  • ๋ฐ˜๋“œ์‹œ ๊ทœ์น™์„ ์ง€์ผœ์•ผ ํ•จ
  • ๊ทœ์น™์„ ๋‹ด์€ ์ถ”์ƒ ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒํ•ด์•ผ ํ•จ
class Camera : public ICamera
{
public:
	void take() { std::println("take picture"); }
};

class HDCamera : public ICamera
{
public:
	void take() { std::println("take HD picture"); }
};

class UHDCamera : public ICamera
{
public:
	void take() { std::println("take UHD picture"); }
};

int main()
{
	People p;
	Camera c;
	p.use_camera(&c);

	HDCamera hc;
	p.use_camera(&hc); // ok

	UHDCamera uhc;
	p.use_camera(&uhc); // ok
}

์ถ”์ƒ ํด๋ž˜์Šค vs ์ธํ„ฐํŽ˜์ด์Šค

์ข…๋ฅ˜ ํŠน์ง•
์ถ”์ƒ ํด๋ž˜์Šค ์ง€์ผœ์•ผ ํ•˜๋Š” ๊ทœ์น™ + ๋‹ค๋ฅธ ๋ฉค๋ฒ„๋„ ์žˆ๋Š” ๊ฒฝ์šฐ
์ธํ„ฐํŽ˜์ด์Šค ์ง€์ผœ์•ผํ•˜๋Š” ๊ทœ์น™(์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜)๋งŒ ๊ฐ€์ง„ ๊ฒƒ
์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ
  • ๊ฒฐ๊ตญ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๋กœ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ ๋ฐ˜๋“œ์‹œ ๊ฐ€์ƒ ์†Œ๋ฉธ์ž ์‚ฌ์šฉ
  • class ๋Œ€์‹  struct๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋„ ๋งŽ์Œ (public ์ ๊ธฐ ๊ท€์ฐฎ์•„์„œ)

Image

๊ฐ•ํ•œ ๊ฒฐํ•ฉ(tightly coupling)
  • ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด์™€ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๋Š” ๊ฒƒ
  • ๊ต์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ํ™•์žฅ์„ฑ ์—†๋Š” ๊ฒฝ์ง๋œ ๋””์ž์ธ

Image

์•ฝํ•œ ๊ฒฐํ•ฉ(loosely coupling)
  • ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด์™€ ์•ฝํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๋Š” ๊ฒƒ(์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด์„œ ํ†ต์‹ )
  • ๊ต์ฒด๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ  ํ™•์žฅ์„ฑ ์žˆ๋Š” ์œ ์—ฐํ•œ ๋””์ž์ธ

Shape ์˜ˆ์‹œ

  • ๋ชจ๋“  ๋„ํ˜•์„ ํƒ€์ž…์œผ๋กœ ์„ค๊ณ„ํ•œ๋‹ค.
  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ชจ๋“  ๋„ํ˜•์„ ํ•˜๋‚˜์˜ ์ปจํ…Œ์ด๋„ˆ์— ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋‹ค.
#include <iostream>
#include <vector>

class Shape
{
public:
	virtual ~Shape() {}
};

class Rect : public Shape
{
public:
	void draw() { std::cout << "draw Rect" << std::endl; }
};

class Circle : public Shape
{
public:
	void draw() { std::cout << "draw Circle" << std::endl; }
};

int main()
{
	Rect* r1 = new Rect;
	Circle* c1 = new Circle;

	std::vector<Shape*> v;

	v.push_back( new Rect);
	v.push_back( new Circle);
	
}

Image

๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํƒ€์ž… ํฌ์ธํ„ฐ๋กœ๋Š” ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๊ณ ์œ  ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜๋Š” ์—†๋‹ค.

๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์—๋„ draw()๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

#include <iostream>
#include <vector>

class Shape
{
public:
	virtual ~Shape() {}
};
class Rect : public Shape
{
public:
	void draw() { std::cout << "draw Rect" << std::endl; }
};
class Circle : public Shape
{
public:
	void draw() { std::cout << "draw Circle" << std::endl; }
};

int main()
{
	std::vector<Shape*> v;

	while (1)
	{
		int cmd;
		std::cin >> cmd;

		if      ( cmd == 1 ) v.push_back(new Rect);
		else if ( cmd == 2 ) v.push_back(new Circle);
		else if ( cmd == 9 )
		{
			for (auto p : v) 
				p->draw(); // error	 
		}
	}
}
  • ๋ชจ๋“  ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ๊ณตํ†ต์˜ ํŠน์ง•์€ ๋ฐ˜๋“œ์‹œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์—๋„ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๋ฌธ๋ฒ•์ ์ธ ๊ทœ์น™์ด ์•„๋‹ˆ๋ผ ๋””์ž์ธ์ ์ธ ๊ด€์ ์ด๋‹ค.

class Shape
{
public:
	virtual void draw() { std::cout << "draw Shape" << std::endl; }

	virtual ~Shape() {}
};
  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํ•จ์ˆ˜ ์ค‘ ํŒŒ์ƒ ํด๋ž˜์Šค๊ฐ€ ์žฌ์ •์˜ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์€ ๋ฐ˜๋“œ์‹œ ๊ฐ€์ƒํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด๋ผ

๊ฐ€์ƒ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉด ์žฌ์ •์˜ํ•˜์ง€ ๋ง๋ผ

class Rect : public Shape
{
public:
	void draw() override  { std::cout << "draw Rect" << std::endl; }
};
class Circle : public Shape
{
public:
	void draw() override { std::cout << "draw Circle" << std::endl; }
};
๋‹คํ˜•์„ฑ(polymorphism)
  • ๋™์ผํ•œ ํ‘œํ˜„์‹์ด ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ
  • p->draw()๋Š” ์ƒํ™ฉ(์‹ค์ œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด์˜ ์ข…๋ฅ˜)์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•จ
k๋ฒˆ์งธ ๋„ํ˜•์˜ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•
  1. dynamic_cast๋กœ ํƒ€์ž…์„ ์กฐ์‚ฌ
    • ์ƒˆ๋กœ์šด ๋„ํ˜•์ด ์ถ”๊ฐ€๋˜๋ฉด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•จ -> OCP ์œ„๋ฐ˜
		else if (cmd == 8)
		{
			std::cout << "๋ช‡๋ฒˆ์งธ ๋„ํ˜•์„ ๋ณต์ œ ํ• ๊นŒ์š” >> ";
			int k;
			std::cin >> k;

			if ( dynamic_cast<Rect*>(v[k]) != nullptr )
			{
				v.push_back( new Rect );
			}
			else if ( dynamic_cast<Circle*>(v[k]) != nullptr )
			{
				v.push_back( new Circle );
			}

		}
	}
}

  1. clone() ๊ฐ€์ƒํ•จ์ˆ˜
    • ์ƒˆ๋กœ์šด ๋„ํ˜•์ด ์ถ”๊ฐ€๋ผ๋„ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„๋„ ๋จ
#include <iostream>
#include <vector>

class Shape
{
public:
	virtual void draw() { std::cout << "draw Shape" << std::endl; }

	virtual ~Shape() {}

	virtual Shape* clone() const 
	{
		return new Shape(*this);
	}
};


class Rect : public Shape
{
public:
	void draw() override  { std::cout << "draw Rect" << std::endl; }

	Shape* clone() const override
	{
		return new Rect(*this);
	}
};

class Circle : public Shape
{
public:
	void draw() override { std::cout << "draw Circle" << std::endl; }

	Shape* clone() const override
	{
		return new Circle(*this);
	}
};


int main()
{
	std::vector<Shape*> v;

	while (1)
	{
		int cmd;
		std::cin >> cmd;

		if      ( cmd == 1 ) v.push_back(new Rect);
		else if ( cmd == 2 ) v.push_back(new Circle);
		else if ( cmd == 9 )
		{
			for (auto p : v) 
				p->draw(); 
		}

		else if (cmd == 8)
		{
			std::cout << "๋ช‡๋ฒˆ์งธ ๋„ํ˜•์„ ๋ณต์ œ ํ• ๊นŒ์š” >> ";
			int k;
			std::cin >> k;

			v.push_back( v[k]->clone() );
			
		}
	}
}

OCP๋ฅผ ์œ„ํ•ด์„œ ์ œ์–ด๋ฌธ์ด ์•„๋‹ˆ๋ผ ๋‹คํ˜•์„ฑ์„ ์‚ฌ์šฉํ•˜๋ผ

๋””์ž์ธ ํŒจํ„ด
ํŠน์ • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ์ฝ”๋”ฉ๋•Œ๋ฌธ์— ์ด๋ฆ„์„ ๋ถ€์—ฌํ•œ ๊ฒƒ
prototype ํŒจํ„ด
๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ํŒจํ„ด

// 1. ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ์ •์„ OCP๋ฅผ ๋งŒ์กฑํ•˜๊ฒŒ ํ• ์ˆ˜ ์—†์„๊นŒ ? // 2. Undo/Redo ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ ?

๊ณตํ†ต์„ฑ๊ณผ ๊ฐ€๋ณ€์„ฑ์˜ ๋ถ„๋ฆฌ

Template method

  • ํ–‰์œ„ ํŒจํ„ด(Behavior Pattern)
  • ์˜๋„

์˜คํผ๋ ˆ์ด์…˜์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ฒ˜๋ฆฌ ๊ณผ์ •๋งŒ์„ ์ •์˜ํ•˜๊ณ  ๊ฐ ๋‹จ๊ณ„์—์„œ ์ˆ˜ํ–‰ํ•  ๊ตฌ์ฒด์ ์ธ ์ฒ˜๋ฆฌ๋Š” sub class์—์„œ ์ •์˜ํ•œ๋‹ค.

์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ฒ˜๋ฆฌ๊ณผ์ •์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฐ ๋‹จ๊ณ„์˜ ์ฒ˜๋ฆฌ๋ฅผ sub class์—์„œ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

Image

GUI ํ™˜๊ฒฝ์—์„œ ์œˆ๋„์šฐ์— ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๊ธฐ
  • ๋Œ€๋ถ€๋ถ„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•จ
  • ํ™”๋ฉด ๊นœ๋นก์ž„์„ ๋ฐฉ์ง€(flicker free)ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณต(๋”๋ธ” ๋ฒ„ํผ๋ง ๋“ฑ)

ํ˜„์žฌ ํŒŒ์ƒ ํด๋ž˜์Šค๋“ค๋ผ๋ฆฌ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๊ฑฐ์˜ ๋™์ผํ•ด์„œ ์ค‘๋ณต๋˜๊ณ  ์žˆ์Œ

#include <iostream>
#include "Painter.h"

class Shape
{
public:
	virtual ~Shape() {}
	virtual void draw() = 0;
};

class Rect : public Shape
{
public:
	void draw() override
	{
		PainterPath path;
		path.begin();

		// path ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฐ๋‹ค.
		path.draw_rect();

		path.end();

		Painter surface;
		surface.draw_path(path);
	}
};


class Circle : public Shape
{
public:
	void draw() override
	{
		PainterPath path;
		path.begin();

		// path ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฐ๋‹ค.
		path.draw_circle();
		
		path.end();

		Painter surface;
		surface.draw_path(path);
	}
};

int main()
{
	Shape* s1 = new Rect;
	Shape* s2 = new Circle;

	s1->draw();
	s2->draw();
}

Image

  • ๋ณ€ํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ณ€ํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ฐพ๋Š”๋‹ค.
  • ๋ณ€ํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐ€์ƒํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค.
  • ํŒŒ์ƒ ํด๋ž˜์Šค๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ฒ˜๋ฆฌ ๊ณผ์ •์„ ๋ฌผ๋ ค ๋ฐ›์œผ๋ฉด์„œ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•˜์—ฌ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋‹ค์‹œ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
#include <iostream>
#include "Painter.h"

class Shape
{
public:
	virtual ~Shape() {}

	void draw() 
	{
		PainterPath path;
		path.begin();

		// path ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฐ๋‹ค.
		draw_imp(path);

		path.end();

		Painter surface;
		surface.draw_path(path);		
	}

protected:
	virtual void draw_imp(PainterPath& path) = 0;
};



class Rect : public Shape
{
protected:
	void draw_imp(PainterPath& path) override
	{
		path.draw_rect();
	}
};


class Circle : public Shape
{
protected:
	void draw_imp(PainterPath& path) override
	{
		path.draw_circle();
	}
};

int main()
{
	Shape* s1 = new Rect;
	Shape* s2 = new Circle;

	s1->draw();
	s2->draw();
}

Image

Strategy

  • ํ–‰์œ„ ํŒจํ„ด(Behavior Pattern)
  • ์˜๋„

๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์กด์žฌํ•˜๋ฉด ์ด๋“ค ๊ฐ๊ฐ์„ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋กœ ์บก์Аํ™”ํ•˜์—ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

Strategy ํŒจํ„ด์„ ์ด์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋ณ€ํ˜•ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐ”๊พธ๋”๋ผ๋„ ํด๋ผ์ด์–ธํŠธ๋Š” ์•„๋ฌด๋Ÿฐ ๋ณ€๊ฒฝ์„ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

Image

#include <iostream>
#include <string>
#include <conio.h>

class Edit
{
	std::string data;
public:
	std::string get_text()
	{
		std::cin >> data;
		return data;
	}
};

int main()
{
	Edit edit;
	while (1)
	{
		std::string s = edit.get_text();
		std::cout << s << std::endl;
	}
}

Edit ์„ ํ†ตํ•ด์„œ ๋‚˜์ด๋ฅผ ์ž…๋ ฅ๋ฐ›๊ณ  ์‹ถ๋‹ค.

์ˆซ์ž๋งŒ ์ž…๋ ฅํ•˜๋„๋ก ์ œํ•œํ•ด์•ผ ํ•œ๋‹ค.

class Edit
{
	std::string data;
public:

	std::string get_text()
	{
		data.clear();

		while (1)
		{
			char c = _getch();

			if (c == 13) break; // enter ํ‚ค

			if (isdigit(c))
			{
				data.push_back(c);
				std::cout << c;
			}
		}
		std::cout << "\n";
		return data;
	}
};

Edit์˜ Validation ์ •์ฑ…์€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

Validation ์ •์ฑ… #1 ๋ณ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐ€์ƒํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌ

template method ํŒจํ„ด

class Edit
{
	std::string data;
public:

	std::string get_text()
	{
		data.clear();

		while (1)
		{
			char c = _getch();

			if (c == 13 && iscomplete(data) ) break;

			if (validate(data, c))
			{
				data.push_back(c);
				std::cout << c;
			}
		}
		std::cout << "\n";
		return data;
	}
	virtual bool validate(const std::string& data, char c)
	{
		return true;
	}
	virtual bool iscomplete(const std::string& data) // ์ž…๋ ฅ ๊ฐ’์ด ์™„์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•จ
	{
		return true;
	}
};
class NumEdit : public Edit
{	
	int count;
public:
	NumEdit(int count = 9999) : count(count) {}

	bool validate(const std::string& data, char c) override
	{		
		return data.size() < count && isdigit(c); 
	}
	bool iscomplete(const std::string& data) override
	{
		return count != 9999 && data.size() == count;
	}
};

int main()
{
//	Edit edit;
	NumEdit edit(5); // 5์ž๋ฆฌ ์ˆซ์ž๋งŒ, 5์ž๋ฆฌ ์ž…๋ ฅ ๋˜์–ด์•ผ๋งŒ enter ๊ฐ€๋Šฅ
	
//	AddressEdit edit2;
	while (1)
	{
		std::string s = edit.get_text();
		std::cout << s << std::endl;
	}
}

Validation ์ •์ฑ… #2 ๋ณ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌ

strategy

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋จผ์ € ๋งŒ๋“ค๊ณ , Edit์—์„œ ์•ฝํ•œ ๊ฒฐํ•ฉ์œผ๋กœ ๋‹ค์–‘ํ•œ Validation ์ •์ฑ… ํด๋ž˜์Šค ์‚ฌ์šฉ

Image

#include <iostream>
#include <string>
#include <conio.h>

struct IValidator
{
	virtual bool validate(const std::string& data, char c) = 0;
	virtual bool iscomplete(const std::string& data) { return true;}
	virtual ~IValidator() {}
};



class Edit
{
	std::string data;

	IValidator* val = nullptr;
public:
	void set_validator(IValidator* p) { val = p;}

	std::string get_text()
	{
		data.clear();

		while (1)
		{
			char c = _getch();

			if (c == 13 && ( val == nullptr || val->iscomplete(data)    )  ) break;
			
			if (val == nullptr || val->validate(data, c))
			{
				data.push_back(c);
				std::cout << c;
			}
		}
		std::cout << "\n";
		return data;
	}
};


int main()
{
	Edit edit;
	while (1)
	{
		std::string s = edit.get_text();
		std::cout << s << std::endl;
	}
}
class DigitValidator : public IValidator
{
	int count;
public:
	DigitValidator(int count = 9999) : count(count) {}

	bool validate(const std::string& data, char c) override 
	{
		return data.size() < count && isdigit(c);
	}
	bool iscomplete(const std::string& data) override 
	{
		return count != 9999 && data.size() == count;
	}
};


int main()
{
	Edit edit;
	DigitValidator v(5);
	edit.set_validator(&v);
	
//	DigitValidator v2(15);
//	edit.set_validator(&v2);

	while (1)
	{
		std::string s = edit.get_text();
		std::cout << s << std::endl;
	}
}

Validation ๋ฐฉ์‹ 2๊ฐ€์ง€ ๋น„๊ต

Validation #1 template method

Image

  • NumEdit, AddressEdit ๋“ฑ Edit์„ ํ™•์žฅํ•ด๊ฐ€๋ฉด์„œ Validation์„ ๋”ฐ๋กœ ์“ฐ๊ฒŒ ๋˜๋ฏ€๋กœ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง

Validation #2 strategy

Image

Edit ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ๋Š” strategy๊ฐ€ ์ ํ•ฉํ•˜์ง€๋งŒ, template method๊ฐ€ ๋” ๋‚˜์œ ๊ฒƒ์ด ์•„๋‹˜

์‚ฌ๊ฐํ˜•์„ ๊ทธ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์€

  • ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•  ์ผ์ด ์—†๊ณ 
  • ์‹คํ–‰ ์‹œ๊ฐ„์— ๊ต์ฒด๋˜์–ด์•ผ ํ•  ์ด์œ ๋„ ์—†์Œ
  • ๊ฐ€์ƒ ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„๋˜๋ฉด ๋ฉค๋ฒ„ํ•จ์ˆ˜์ด๋ฏ€๋กœ ๋ฉค๋ฒ„ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ๋„ ํŽธํ•ด์ง