본문 바로가기

IT Book Summary/Object: 객체지향설계

Appendix C 동적인 협력, 정적인 코드

객체는 동적이고 프로그램은 정적이다.

객체는 다른 객체와 협력하면서 젼하고 다양한 방식으로 행동한다.

 

프로그램의 실행 구조를 표현하는 동적 모델 dynamic model : 객체의 협력으로 구성

코드의 구조를 담는 정적모델 static model : 타입(동일한 타입 객체들이 수행할 수 있는 모든행동을 합축해 표현)과 관계로 구성

 

좋은 설계는 객체 사이의 협력과 행동을 표현하는 동적 모델을 기반으로 함

 


01 동적 모델과 정적 모델

 

행동이 코드를 결정한다.

 

행동을 고려해 상속계층을 구성

객체가 외부에 제공하는 행동을 고려해 타입계층 생성

ex) Bird - Penguin 

             - FlyingBird 

 

동적모델 (행동) 이 정적모델 (클래스 타입) 을 결정해야 함

 

 

변경을 고려하라

 

상속계층을 합성으로 변경

 

다양하게 조합하더라도 중복코드가 발생하지 않음.

ex) 11장 핸드폰 과금정책

요금 정책 변경을 위해 Phone 에 합성 관계로 연결하는 RatePolicy 인스턴스 종류를 변경하면 됨.


02 도메인 모델과 구현

 

도메인 모델 domain model 에 관하여 

- 사용자가 프로그램을 사용하는 대상 영역(도메인)에 대한 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태(모델)

 

 모델은 옳거나 틀린 것이 아니다. 모델은 유용하거나 유용하지 않은 정도의 차이만 있을 뿐이다.

 

도메인 안의 개념이 제공하는 틀에 맞춰서 소프트웨어를 구축해야 한다고 생각하는 것은 잘못되었다.

 

중요한 것은 소프트웨어의 기능과 객체의 책임, 협력을 지원하는 코드 구조. 주도하는것은 구조보다 행동

 

몬스터 설계하기

 

다양한 종류의 몬스터가 등장하는 게임을 설계하자

 

도메인 모델을 기반으로 원하는 협력을 지원하는 설계는 좋은 출발점.

 

public abstract class Monster {
    private int health;
    
    public Monster(int health) {
        this.health = health;       
    }
    
    abstract public String getAttack();
}

public class Dragon extends Monster {
    public Dragon() {
        super(230);
    }
    
    @Override
    public String getAttack() {
        return "용은 불을 내뿜는다";
    }
}

public class Troll extends Monster {
    public Troll() {
        super(48);
    }
    
    @Override
    public String getAttack() {
        return "트롤은 곤봉으로 때린다";
    }
}

 

몬스터가 품종을 가지도록 설개하면 새로운 몬스터를 추가하는 요구사항이 올 때, 클래스를 추가하는 대신 합성하여 구현할 수 있다.

 

public class Breed {
    private String name;
    private int health;
    private String attack;
    
    public Breed(String name, int health, String attack) {
        this.name = name;
        this.health = health;
        this.attack = attack;
    }
    
    public int getHealth() {
        return health;
    }
    
    public String getAttack() {
        return attack();
    }
}

public class Monster {
    private int health;
    private Breed breed;
    
    public Monster(Breed breed) {
        this.health = breed.getHealth();
    }
    
    public String getAttach() {
        return breed.getAttack();
    }
}


Monster dragon = new Monster(new Breed("용",230,"용은 불을 내뿜는다"));
Monster troll = new Monster(new Breed("트롤",48,"트롤은 곤봉으로 때린다"));

 

새로운 클래스를 추가하는 대신 새로운 인스턴스를 생성하는 것으로 타입 추가문제를 해결.

어떤 객체를 표현하는 별도의 객체를 이용해 타입을 구현. -> Type Object 패턴

Breed 인스턴스가 Monster 타입을 구현하는 Type Object 에 해당

 

 

행동과 변경을 고려한 도메인 모델 

 

행동과 변경을 고려하지 않는 도메인 모델을 그대로 따르는 건 코드의 유지보수를 방해한다.

 

도메인의 핵심을 간략하게 단순화해서 표현할 수 있는 모든 것이 도메인 모델

 

JSON 형식으로 서술해 역직렬화 구현하여 사용도 가능

{
    "breeds" : 
    [
        {"name" : "용", "health" : 230, "attack" : "용은 불을 내뿜는다"},
        {"name" : "트롤", "health" : 48, "attack" : "트롤은 곤봉으로 때린다"},
    ]
}

 

실행시점의 모습을 표현한 동적모델 그림 C.7

 

도메인 모델은 코드를 위한것. 

도메인 안에 존재하는 개념과 관계를 표현해야 하지만 최종모습은 객체의 행동과 변경에 기반하여 코드의 구조를 반영.

 

 

분석모델, 설계모델, 그리고 구현모델

 

분석모델 - 순수하게 문제 도메인을 설명하는 모델

설계모델 - 기술적인 관점에서 솔루션을 서울하는 모델

구현모델 - 위의 모델을 바탕으로 구현 모델을 만들고 코드화

 

-> 분석과 설계와 구현 동안 동일한 모델을 유지하는 것.

 

프로그래밍은 설계의 한 과정이며 설계는 프로그래밍을 통해 개선된다 

-> 도메인의 개념과 객체 사이 협력을 반영하는 코드를 작성하면서 동시에 분석과 설계와 구현에 대해 고민하는 것.

 

객체지향 언어 사용이 프로그램 코드를 설계문서로 간주 할수 있는 기반이 된다.

 

분석과 설계모델은 별개가 아니다.

 

도메인을 바라보는 관점을 소프트웨어에 반영하는 다양한 기법을 활용할 수 있다.

 

전체 개발 주기에 걸쳐 동일한 기법과 표현력을 유지할 수 있다는 것이 객체지향 패러다임의 강력한 점

-> 모든 단계에 걸쳐 행동과 변경에 초첨을 맞추라.