티스토리 뷰

728x90
반응형

 


좋은 부분이 너무 많아서 책을 많이 옮겨왔는데 혹시 문제가 된다면 말씀해주세요-!

제가 조금 재구성한 부분이 있기때문에 꼭 책을 읽어보시는 것을 추천드립니다.


[1] 캡슐화

 

[ 캡슐화에 대한 오해 ]

 

많은 사람들이 객체의 캡슐화에 관한 이야기를 들으면 데이터 은닉(data hiding)을 떠올린다.

데이터 은닉이란 클래스의 모든 인스턴스 변수는 private으로 선언해야하고 오직 해당 클래스의 메서드 만이 인스턴스 변수에 접근 할 수있어야하다는 것이다.

 

그러나 캡슐화는 데이터 은닉 이상이다.

캡슐화란 단순히 데이터를 감추는 것이 아니다. 소프트웨어에서 변할 수 있는 모든 개념을 감추는 것이다.

 

코드 수정으로 인한 파급효과를 제어할 수 있는 모든 기법이 캡슐화의 일종이다.

 

 

[ 캡슐화의 여러 종류 ]

 

- 데이터 캡슐화

- 메서드 캡슐화

- 객체 캡슐화

- 서브타입 캡슐화

 

가 있다.

 

아래의 예제를 보면서 살펴보자.

 

 

1) 개별 객체에 대한 변경을 관리하기 위해

 

1.1 데이터 캡슐화

 

Movie 클래스의 인스턴스 변수 title의 가시성은 private이기 때문에 외부에서 직접 접근할 수 없다.

클래스는 내부에 관리하는 데이터를 캡슐화한다.

 

1.2 메서드 캡슐화

 

DiscountPolicy 클래스에 정의돼 있는 getDiscountAmount 메서드의 가시성은 protected이다.

외부에서는 이 메서드에 직접 접근할 수 없고 클래스 내부와 서브클래스에서만 접근 가능하다.

따라서 클래스 외부에 영향을 미치지 않고 메서드를 수정할 수 있다.

다시 말해 클래스의 내부 행동을 캡슐화하고 있는 것이다. 

 

 

2) 협력에 참여하는 객체들의 관계에 대한 변경을 관리하기 위해

 

2.1 객체 캡슐화 (합성)

 

Movie 클래스는 DiscounPolicy 타입의 인스턴스 변수 discountPolicy를 포함한다.

이 변수는 private 가시성을 가지기 때문에 Movie와 DiscountPolicy 관계를 변경하더라도 외부에는 영향을 미치지 않는다.

다시 말해서 객체와 객체 사이의 관계를 캡슐화한다. 

객체 캡슐화는 합성(composition)을 의미한다.

 

2.2 서브타입 캡슐화 (인터페이스 상속)

 

Movie는 DiscountPolicy에 대해서는 알고 있지만 AmountDiscountPolicy와 PercentDiscountPolicy에 대해서는 알지 못한다.

그러나 실제로 실행 시점에는 이 클래스들의 인스턴스와 협력할 수 있다.

이것은 기반 클래스의 DiscountPolicy와의 추상적인 관계가 AmountDiscountPolicy와 PercentDiscountPolicy의 존재를 감추고 있기 때문이다.

다시 말해 서브타입의 종류를 캡슐화하고 있다.

서브타입 캡슐화는 다형성의 기반이 된다. 

 

 

[2] 도메인 모델

 

[ 도메인 모델에 대한 오해 ]

 

불행은 도메인 안의 개념이 제공하는 틀에 맞춰서 소프트웨어를 구축해야한다고 생각할 때 부터 시작된다.

 

도메인 모델을 작성하는 것은 목표가 아니라 출발점이다.

도메인 모델은 소프트웨어를 만드는데 필요한 개념의 이름과 의미, 관계에 대한 힌트를 제공하는 역할로 끝나야한다.

 

도메인 모델에 지나치게 집착하거나 도메인 모델의 초기 구조를 맹목적으로 따르는 코드를 작성하고 있다면 변경하기 어려운 소프트웨어가 만들어질 확률이 높다. 

 

코드의 구조를 이끄는 것은 도메인 안에 정립된 개념의 분류 체계가 아니라 객체들의 협력이다.

 

 

 

[ 예제 ]

 

주인공 캐릭터를 공격하는 다양한 종류의 몬스터가 등장하는 게임을 설계해야한다고 해보자.

현재의 요구사항에 따르면 몬스터로는 용, 트롤이 존재하고 앞으로 몬스터의 종류를 확장할 수 있어야한다. 

초기 도메인 모델을 이렇게 그렸다. 

 

 

설계를 작성할 수 있는 훌륭한 출발점이다.

이 도메인 모델에 따라서 코드를 이렇게 구현했다. 

 

public abstract class Monster { ... }

public class Dragon extends Monster { ... }

public class Troll extends Monster { ... }

 

 

여기까지는 깔끔하지만 이후 새로운 몬스터를 수백가지를 추가해달라는 요청이 들어왔다고 해보자.

몬스터별로 하나의 클래스를 추가하고 getAttack 메서드를 오버라이딩하는 것은 지루한 작업일 것이다. 

 

새로운 클래스를 추가하지 않고도 새로운 몬스터를 추가할 수 있는 방법이 더 좋은 방법이다.

몬스터 종류 별로 새로운 서브클래스를 추가하는 대신 몬스터가 품종을 가지도록 설계를 개선할 수 있다.

 

Monster 클래스가 Breed 클래스를 합성관계로 포함하는 설계로..!

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 attackl
  }
}


public class Monster {
   private Breed breed;
   
   public Monster(Breed breed) {
      this.breed = bree;
   } 
   
   public String getAttack {
      return breed.getAttack();
   }
}

 

이제 새로운 몬스터의 종류를 추가하는 것은 새로운 클래스를 추가하는 것이 아니라

새로운 Breed 인스턴스를 생성하고 Monster 인스턴스에 연결하는 작업으로 바뀐다.

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

 

 

 

초기의 도메인 모델은 그저 작업을 시작하기 위한 거친 아이디어 덩어리일 뿐이다.

객체지향의 핵심은 객체사이의 협력이며 설계는 변경을 위한 것이다. 

 

 

여기서 한 걸음 더 나아가면 

위의 그림과 JSON 데이터의 조합이 우리 게임 안에서의 도메인 모델이 되는 것이다. (🤭🤭)

 

 

도메인 모델은 단순히 클래스 다이어그램이 아니다.

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

그리고 그렇게 작성된 개념이 여러분의 코드에 대한 구조와 행동을 드러낸다면 그것은 더없이 훌륭한 도메인 모델이다.

형식은 중요하지 않다.

중요한 것은 전달하려는 의미다. 

728x90
반응형
댓글
댓글쓰기 폼