Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

DeFacto-Standard IT

피터 코드의 상속 규칙 본문

Design Pattern/References

피터 코드의 상속 규칙

defacto standard 2017. 10. 28. 18:13

피터 코드의 상속 규칙

상속의 오용을 막기 위해 상속의 사용을 제한하는 5가지 규칙. 어느 하나라도 만족하지 않는다면 상속을 사용해서는 안된다.

 

- 자식 클래스와 부모 클래스 사이는 '역할 수행(is role played by)'관계가 아니어야 한다.

- 한 클래스의 인스턴스는 다른 서브 클래스의 객체로 변환할 필요가 절대 없어야 한다.

- 자식 클래스가 부모 클래스의 책임을 무시하거나 재정의하지 않고 확장만 수행해야 한다.

- 자식 클래스가 단지 일부 기능을 재사용할 목적으로 유틸리티 역할을 수행하는 클래스를 상속하지 않아야 한다.

- 자식 클래스가 '역할', '트랜잭션', '디바이스' 등을 특수화해야 한다.

 

상속으로 표현한 역할 수행 관계

 


위 그림을 바탕으로 피터 코드의 5가지 규칙을 살펴본다.

 

 1번째 규칙. 자식 클래스가 부모 클래스의 역할 중 하나를 표현하는지를 점검

'운전자'는 어떤 순간에 '사람'이 수행하는 역할의 하나다. 마찬가지로 '회사원'도 사람이 어떤 순간에 수행하는 역할의 하나다.

따라서 사람과 운전자나, 사람과 회사원은 상속 관계로 표현되어서는 안 되므로 규칙에 위배.


 2번째 규칙. 자식 클래스의 인스턴스들 사이에 변환 관계가 필요한지를 점검

'운전자'는 어떤 시점에서 '회사원'이 될 필요가 있으며, '회사원'역시 '운전자'가 될 필요가 있다.

자신이 일하는 회사로 출퇴근 하는 동안에는 '운전자'로서의 역할을 수행하며, 회사에 있을 때는 '회사원'으로서의 역할을 수행한다.

이런 경우 객체의 변환 작업이 필요하므로 규칙에 위배된다.

평생 운전자 역할만 하던가 회사원 역할만 수행한다면 위 그림은 나쁘지 않다. 그러나 대부분의 사람은 한 역할에 고정되지 않고 시점에 따라 다른 역할을 수행하는 경우가 많다.


3번째 규칙. 점검 불가.

'사람', '운전자', '회사원' 클래스 등에 어떤 속성과 연산이 정의되었는지 정보가 없기 때문


4번째 규칙. 기능만 재사용할 목적으로 상속 관계를 표현하지는 않았으므로 규칙을 준수

 

5번째 규칙. 슈퍼 클래스가 열할, 트랜잭션, 디바이스를 표현하지 않았으므로 규칙에 위배


따라서 피터 코드의 규칙에 따라 이 클래스 다이어그램은 다음과 같이 상속을 사용하지 않고 집약(혹은 연관) 관계를 사용해 클래스 사이의 관계를 표현하는 편이 좋다.

이렇게 설계하면 사람은 종업원 역할과 운전자 역할을 수행한다는 사실이 자연스럽게 드러난다.

또한 어느 순간에는 두 역할도 수행하지 않을 수 있다는 다중성도 표현할 수 있다.

집약 관계를 이용한 역할 수행 표현

 


*맨 윗 그림과 다음 클래스 다이어그램의 차이점

맨 윗 그림의 클래스 다이어그램은 사람의 역할이 종업원과 운전자로 고정되어 있다.

따라서 사람에게 새로운 역할이 부가되면 '사람'클래스 코드도 변경되어야 한다.

 

그러나 위 클래스 다이어그램은 '역할'이라는 추상 클래스를 상속받는 구조로 구체적인 역할 클래스들을 캡슐화하기 때문에 새로운 역할이 추가되더라도 기존의 코드는 영향을 받지 않는다.

 

기존 코드에 전혀 영향을 주지 않고 '축구 선수'라는 역할을 추가할 수 있다. 개방-폐쇄의 원칙, Open-Closed Priciple(OCP) 라고 한다.

 

*회사에 도착했을 때 운전자에서 종업원으로 역할이 변경되어 회사에서 업무를 수행하는 상황을 코드로 작성

 

public class Person {
private Role r;

public void setRole(Role r) {
this.r = r;
}

public Role getRole() {
r.doIt();
}
}
public abstract class Role {
public abstract void doIt();
}
public class Driver extends Role {
@Override
public void doIt() {
System.out.println("Driving");
}
}
public class Worker extends Role {
@Override
public void doIt() {
System.out.println("Working");
}
}
public class Main {

public static void main(String[] args) {
Person p = new Person();
p.setRole(new Driver()); // 운전자로 역할 변경
p.doIt(); // 운전자 역할 수행
p.setRole(new Worker()); // 종업원으로 역할 변경
p.doIt(); // 종업원 역할 수행
}
}



'Design Pattern > References' 카테고리의 다른 글

SOLID (2) - 개방-폐쇄 원칙, OCP  (0) 2017.10.28
SOLID (1) - 단일 책임 원칙, SRP  (0) 2017.10.28
일반화 관계, 다형성  (0) 2017.10.28
추상화, 캡슐화  (0) 2017.10.28
인터페이스, 실체화 관계  (0) 2017.10.28
Comments