본문 바로가기
NC University/Design Pattern with C++

1일차 - 추상 클래스(Abstract class)

by 날쑤 2021. 6. 11.

Review - abstract class

  • 순수 가상함수(pure virtual function)를 하나 이상을 가지는 클래스로서 객체를 생성할 수 없음
  • 파생 클래스에서 특정 함수를 반드시 구현하도록 지시함
    #include <iostream>
    using namespace std;
    
    // 추상 클래스
    class Shape 
    {
    public:
        virtual void Draw () = 0; // 순수 가상함수
    };
    
    // 순수 가상함수를 모두 구현한 파생 클래스, 객체 생성 가능
    class Circle : public Shape
    {
    public:
        void Draw () override { cout << "Draw a Circle" << endl; }
    };
    
    // Draw를 구현하지 않으면 역시 추상 클래스임, 객체 생성 불가
    class Rect : public Shape {};  ​

Open-Closed Principle (OCP)

  • 기능 확장에는 열려 있고(open), 코드 수정에는 닫혀 있어야(closed) 한다는 이론
  • 미래에 새로운 클래스가 추가되어도 과거의 코드는 수정되면 안된다.

  아래의 예제 코드를 살펴보자.

#include <iostream>
using namespace std;

class Camera 
{
public:
    void Take () { cout << "take picture with Camera" << endl; }
};

class People 
{
public:
    void UseCamera (Camera* p) { p->Take(); }
};

int main (int argc, char* argv[])
{
    Camera c1;

    People p;
    p.UseCamera(&c1);
    
    return 0;
}

  여기에 새로운 종류의 카메라(Camera2)가 추가되었다고 해보자.

class Camera2 
{
public:
    void Take () { cout << "take picture with Camera2" << endl; }
};

  Camera2를 People 객체가 사용하려면 People 객체도 아래와 같이 수정되어야 한다.

class People 
{
public:
    void UseCamera (Camera* p) { p->Take(); }
    void UseCamera (Camera2* p) { p->Take(); }  // function overloading
};

  Camera2 클래스가 추가됨에 따라 기존 클래스인 People에 새로운 함수 하나가 추가되었다. 현재 구조로는 새로운 카메라 타입이 추가될 때마다 동일한 작업이 필요하게 될 것이다.

  이제는 위의 코드를 OCP를 만족하도록 수정해보자. 우선 카메라 제작자와 카메라 사용자 사이에 지켜야하는 규칙을 추상 클래스를 이용해서 만들자.

// 카메라 제작자가 지켜야 할 규칙(약속, 인터페이스)
// 모든 카메라는 아래의 인터페이스를 구현해야 한다.
class ICamera 
{
public:
    virtual ~ICamera () {}
    virtual void Take () = 0;
};

// 실제 카메라는 없지만 규칙이 존재한다. 사용자는 규칙대로만 사용하면 된다.
// 새로운 카메라가 추가되더라도 People 클래스는 수정하지 않아도 된다.
class People
{
public:
    void UseCamera (ICamera* p) { p->Take(); }
};

  이제는 새로운 카메라 클래스를 추가할 때에는 ICamera에서 정의한 인터페이스를 따르기만 하면 기존 코드인 People 클래스는 수정하지 않아도 된다.

#include <iostream>
using namespace std;

// 모든 카메라 제작자는 규칙을 지켜야 한다.
// People과 Camera, Camera2는 약한 결합(loosely coupling) 상태
class Camera : public ICamera 
{
public:
    void Take () override { cout << "take picture with Camera" << endl; }
};

class Camera2 : public ICamera 
{
public:
    void Take () override { cout << "take picture with Camera2" << endl; }
};

int main (int argc, char* argv[])
{  
    People p;

    // 이제 UseCamera는 함수 오버로딩이 아닌 하나의 함수이다.
    // 즉, 카메라의 종류에 상관없이 하나의 인터페이스를 사용한다.
    Camera c1; p.UseCamera(&c1);
    Camera2 c2; p.UseCamera(&c2);
    
    return 0;
}

'NC University > Design Pattern with C++' 카테고리의 다른 글

1일차 - 상속(inheritance)  (0) 2016.05.24
1일차 - thiscall  (0) 2016.05.19