개발/Architecture & Design Pattern

C++ - 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)

피로물든딸기 2024. 2. 12. 20:31
반응형

C, C++ 전체 링크

Architecture & Design Pattern 전체 링크

 

참고

- 전략, 스트래티지 패턴

 

인터페이스 분리 원칙 (ISP, Interface Segregation Principle)

- 클라이언트는 자신이 사용하지 않는 인터페이스에 의존하지 않아야 한다.

- 일반적인 인터페이스들은 더 작고, 구체적인 인터페이스들로 분리해야 한다.


아래의 인터페이스 분리 원칙 위반 사례를 보자.

 

흔히 노동자들은 일을 하지만, 밥도 먹어야 하고 잠도 자야 한다.

class Worker 
{
public:
	virtual void work() = 0;
	virtual void eat() = 0;
	virtual void sleep() = 0;
};

 

예를 들어 프로그래머는 다음과 같이 work / eat / sleep을 구현할 수 있다.

class Programmer : public Worker 
{
public:
	void work() override { cout << "Writing code..." << endl; }
	void eat() override { cout << "Eating pizza..." << endl; }
	void sleep() override { cout << "Sleeping on keyboard..." << endl; }
};

 

그런데 최신 기술로 인해 로봇이 노동자들을 대체하게 되었다.

어쨌든 로봇도 노동을 하기 때문에 Worker를 상속받아야 하고, 아래와 같이 강제로 구현해야 한다.

class Robot : public Worker 
{
public:
	void work() override { cout << "Executing tasks..." << endl; }
	void eat() override { cout << "I don't need to eat." << endl; }
	void sleep() override { cout << "I don't need to sleep." << endl; }
};

 

로봇은 먹지도 않고 잠들지도 않기 때문에 eat / sleep을 구현할 필요가 없는데도 메서드가 포함되고 있다.

#include <iostream>

using namespace std;

class Worker 
{
public:
	virtual void work() = 0;
	virtual void eat() = 0;
	virtual void sleep() = 0;
};

class Programmer : public Worker 
{
public:
	void work() override { cout << "Writing code..." << endl; }
	void eat() override { cout << "Eating pizza..." << endl; }
	void sleep() override { cout << "Sleeping on keyboard..." << endl; }
};

class Robot : public Worker 
{
public:
	void work() override { cout << "Executing tasks..." << endl; }
	void eat() override { cout << "I don't need to eat." << endl; }
	void sleep() override { cout << "I don't need to sleep." << endl; }
};

int main() 
{
	Programmer* programmer = new Programmer();
	programmer->work();
	programmer->eat();
	programmer->sleep();

	Robot* robot = new Robot();
	robot->work();
	robot->eat();
	robot->sleep();

	return 0;
}


인터페이스 분리 원칙 적용

 

Worker는 공통된 work만 제외하고 모두 삭제한다.

class Worker 
{
public:
	virtual void work() = 0;
};

 

삭제된 eat / sleep은 다음과 같이 인터페이스를 따로 만들면 된다.

class EatableWorker 
{
public:
	virtual void eat() = 0;
};

class SleepableWorker 
{
public:
	virtual void sleep() = 0;
};

 

그러면 ProgrammerWorker이면서 eat / sleep을 구현해야 하는 노동자가 된다.

class Programmer : public Worker, public EatableWorker, public SleepableWorker 
{
public:
	void work() override { cout << "Writing code..." << endl; }
	void eat() override { cout << "Eating pizza..." << endl; }
	void sleep() override { cout << "Sleeping on keyboard..." << endl; }
};

 

로봇일만 하는 Worker가 된다.

즉, 이전과 달리 불필요한 eat / sleep을 구현하지 않아도 된다.

class Robot : public Worker 
{
public:
	void work() override { cout << "Executing tasks..." << endl; }
};

 

전체 코드는 다음과 같다.

#include <iostream>

using namespace std;

class Worker 
{
public:
	virtual void work() = 0;
};

class EatableWorker 
{
public:
	virtual void eat() = 0;
};

class SleepableWorker 
{
public:
	virtual void sleep() = 0;
};

class Programmer : public Worker, public EatableWorker, public SleepableWorker 
{
public:
	void work() override { cout << "Writing code..." << endl; }
	void eat() override { cout << "Eating pizza..." << endl; }
	void sleep() override { cout << "Sleeping on keyboard..." << endl; }
};

class Robot : public Worker 
{
public:
	void work() override { cout << "Executing tasks..." << endl; }
};

int main()
{
	Programmer* programmer = new Programmer();
	programmer->work();
	programmer->eat();
	programmer->sleep();

	Robot* robot = new Robot();
	robot->work();

	return 0;
}

 

참고로 행동을 인터페이스캡슐화하는 것은 주로 전략 패턴에서 쓰인다.

반응형