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 = ▭ // ok
int* p2 = ▭ // error.
Shape* p3 = ▭ // 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 = ▭
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
- 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ํ ๋
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
- ์ํํธ์จ์ด ๊ฐ์ฒด(ํด๋์ค, ๋ชจ๋, ํจ์ ๋ฑ)๋ ํ์ฅ์ ๋ํด ์ด๋ ค ์์ด์ผ ํ๊ณ , ์์ ์ ๋ํด์๋ ๋ซํ ์์ด์ผ ํ๋ค.
์๋ก์ด ์์๊ฐ ์ถ๊ฐ๋์ด๋ ๊ธฐ์กด ์์๊ฐ ๋ณ๊ฒฝ๋์ง ์๊ฒ ์ค๊ณํด์ผ ํ๋ค๋ ์์น
#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 ์ ๊ธฐ ๊ท์ฐฎ์์)
- ๊ฐํ ๊ฒฐํฉ(tightly coupling)
-
- ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด์ ๊ฐํ๊ฒ ๊ฒฐํฉ๋์ด ์๋ ๊ฒ
- ๊ต์ฒด๊ฐ ๋ถ๊ฐ๋ฅํ๊ณ ํ์ฅ์ฑ ์๋ ๊ฒฝ์ง๋ ๋์์ธ
- ์ฝํ ๊ฒฐํฉ(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);
}
๊ธฐ๋ฐ ํด๋์ค ํ์ ํฌ์ธํฐ๋ก๋ ํ์ ํด๋์ค์ ๊ณ ์ ๋ฉค๋ฒ์ ์ ๊ทผํ ์๋ ์๋ค.
๊ธฐ๋ฐ ํด๋์ค์๋ 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๋ฒ์งธ ๋ํ์ ๋ณต์ฌ๋ณธ์ ๋ง๋๋ ๋ฐฉ๋ฒ
-
- dynamic_cast๋ก ํ์
์ ์กฐ์ฌ
- ์๋ก์ด ๋ํ์ด ์ถ๊ฐ๋๋ฉด ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํจ -> OCP ์๋ฐ
- dynamic_cast๋ก ํ์
์ ์กฐ์ฌ
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 );
}
}
}
}
- 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์์ ์ฌ์ ์ํ ์ ์๋ค.
- 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();
}
- ๋ณํ์ง ์์ ์ฝ๋ ๋ด๋ถ์ ์๋ ๋ณํด์ผ ํ๋ ์ฝ๋๋ฅผ ์ฐพ๋๋ค.
- ๋ณํด์ผ ํ๋ ์ฝ๋๋ฅผ ๊ฐ์ํจ์๋ก ๋ถ๋ฆฌํ๋ค.
- ํ์ ํด๋์ค๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฒ๋ฆฌ ๊ณผ์ ์ ๋ฌผ๋ ค ๋ฐ์ผ๋ฉด์ ๊ฐ์ํจ์๋ฅผ ์ฌ์ ์ํ์ฌ ๋ณ๊ฒฝ์ด ํ์ํ ๋ถ๋ถ๋ง ๋ค์ ๋ง๋ค ์ ์๋ค.
#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();
}
Strategy
- ํ์ ํจํด(Behavior Pattern)
- ์๋
๋ค์ํ ์๊ณ ๋ฆฌ์ฆ์ด ์กด์ฌํ๋ฉด ์ด๋ค ๊ฐ๊ฐ์ ํ๋์ ํด๋์ค๋ก ์บก์ํํ์ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋์ฒดํ ์ ์๋๋ก ํ๋ค.
Strategy ํจํด์ ์ด์ฉํ๋ฉด ํด๋ผ์ด์ธํธ์ ๋ ๋ฆฝ์ ์ผ๋ก ๋ค์ํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ณํํ ์ ์๋ค.
์๊ณ ๋ฆฌ์ฆ์ ๋ฐ๊พธ๋๋ผ๋ ํด๋ผ์ด์ธํธ๋ ์๋ฌด๋ฐ ๋ณ๊ฒฝ์ ํ ํ์๊ฐ ์๋ค.
#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 ์ ์ฑ ํด๋์ค ์ฌ์ฉ
#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
- NumEdit, AddressEdit ๋ฑ Edit์ ํ์ฅํด๊ฐ๋ฉด์ Validation์ ๋ฐ๋ก ์ฐ๊ฒ ๋๋ฏ๋ก ์ ์ฐ์ฑ์ด ๋จ์ด์ง
Validation #2 strategy
Edit ์์ ์ ๊ฒฝ์ฐ๋ strategy๊ฐ ์ ํฉํ์ง๋ง, template method๊ฐ ๋ ๋์ ๊ฒ์ด ์๋
์ฌ๊ฐํ์ ๊ทธ๋ฆฌ๋ ๋ฐฉ๋ฒ์
- ๋ค๋ฅธ ํด๋์ค์์ ์ฌ์ฉํด์ผ ํ ์ผ์ด ์๊ณ
- ์คํ ์๊ฐ์ ๊ต์ฒด๋์ด์ผ ํ ์ด์ ๋ ์์
- ๊ฐ์ ํจ์๋ก ๊ตฌํ๋๋ฉด ๋ฉค๋ฒํจ์์ด๋ฏ๋ก ๋ฉค๋ฒ ๋ฐ์ดํฐ ์ ๊ทผ๋ ํธํด์ง