관심사 분리

  • 관심이 같은 것 끼리는 하나의 객체 안으로 또는 친한 객체로 모이게하고,
    관심이 다른 것은 가능한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것

템플릿 메서드 패턴

  • 슈퍼클래스에 기본적인 로직의 흐름을 만들고,
    그 기능의 일부를 추상 메서드나 오버라이딩 가능한 protected 메서드 등으로 만든 뒤 서브클래스에서 이런 메서드를 필요에 맞게 구현해서 사용하도록 하는 방법

팩토리 메서드 패턴

  • 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것

중요한 건 디자인 패턴이 아닌 상속구조를 통해 성격이 다른 관심사항을
분리한 코드를 만들어내고, 서로 영향을 덜 주도록 했는지를 이해하는 것


상속을 통한 확장의 문제점

  1. 만약 다른 목적을 위해 이미 상속을 사용하고 있다면?

  2. 상속을 통한 상하위 클래스의 관계는 생각보다 밀접

  3. 서브클래스는 슈퍼클래스의 기능을 직접 사용할 수 있음
    그래서 슈퍼클래스 내부의 변경이 있을 때 모든 서브클래스를 함께 수정하거나 다시 개발해야 할 수도 있음
    반대로 그런 변화에 따른 불편을 주지 않기 위해 슈퍼클래스가 더 이상 변화하지 않도록 제약을 가해야 할지도 모름

추상 클래스를 만들고 이를 상속한 서브클래스에서
변화가 필요한 부분을 바꿔서 쓸수 있게 만든 이유는
변화의 성격이 다른 것을 분리해서 서로 영향을 주지 않은 채로
각각 필요한 시점에 독립적으로 변경할 수 있게 하기 위해서

그렇다면 아예 클래스로 따로 때 버린다면?

  • 코드로 새로 만든 클래스에 종속되어 버림
  • 상속 했을 때 처럼 코드 수정없이 기능을 변경할 방법이 없음

클래스를 통한 확장의 문제점

  1. 현재 a 메서드를 사용해 기능을 제공하고 있는데
    만약 a 메서드 대신 b 메서드를 사용하도록 수정 된다면
    일일이 a 메서드를 사용한 수십 수백개의 메서드를 수정해야 함

  2. 기능을 제공하는 클래스가 어떤 것인지 클라이언트가 구체적으로 알고 있어야 함
    만약 다른 클래스를 구현하면 또 클라이언트 자체를 수정해야 함

  3. 근본적인 원인은 클라이언트가 바뀔 수 있는 정보(db 커넥션 등)을 가져오는 클래스에 대해 너무 많이 알고 있기 때문

해결

  • 두 클래스가 서로 긴밀하게 연결되지 않도록 중간에 추상적인 연결고리를 만드는 것(java의 interface)

  • 클라이언트 입장에서는 인터페이스를 상속 받는 클래스의 오브젝트라면 어떤 클래스로 만들었건
    메서드를 호출하기만 하면 약속된 오브젝트를 만들어서 돌려줄 것으로 기대함


Interface를 통한 확장의 문제점

  1. 아직도 클래스의 생성자를 호출해서 오브젝트를 생성하는 코드가 남아있음

    • 초기에 한번 어떤 클래스의 오브젝트를 사용할지를 결정하는 생성자의 코드는 남아 있음
    • ex) conntion = new DConnectionMaker();
  2. 결국 클라이언트가 어떤 구현 클래스의 오브젝트를 이용하게 할지 결정하는 관심사가 남아 있음

해결

  • 오브젝트와 오브젝트 사이에 관계를 설정해야함

  • 오브젝트 사이의 관계는 런타임 시에 한쪽이 다른 오브젝트의 레퍼런스를 갖고 잇는 방식으로 만들어짐(보통 알고 있는 인스턴스 생성 방식)

    • ex)conntion = new DConnectionMaker();
    • DConnectionMaker의 오브젝트의 레퍼런스를 클라이언트의 connection 변수에 넣어서 사용하게 함

클래스 사이의 관계는 코드에 다른 클래스 이름이 나타나기 때문에 만들어지는 것

오브젝트 사이의 관계는 코드에서는 특정한 클래스를 전혀 알지 못하더라도 해당 클래스가 구현한 인터페이스를 사용했다면, 그 클래스의 오브젝트를 인터페이스 타입을 받아서 사용 할 수 있음

이것이 객체지향의 다형성


개방 폐쇄 원칙

  • 클래스나 모듈은 확장에는 열려 있어야하고 변경에는 닫혀 있어야 함

높은 응집도와 낮은 결합도

높은 응집도

  • 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있음
  • 작업은 항상 전체적으로 일어나고 무엇을 변경할지 명확하며, 그것이 클라이언트의 다른 로직에 수정을 요구하지 않을 뿐더라
    기능에 영향을 주지 않음
  • 변경이 일어난 경우에 이를 검증하려고 하면 변경한 구현 클래스만 직접 테스트 해보는 것으로 충분하기 때문
  • 응집도를 높인 덕분

낮은 결합도

  • 하나의 오브젝트가 변경이 일어날 떄에 관계를 맺고 잇는 다른 오브젝트에게 변화를 요구하는 정도
  • 하나의 변경이 발생할 때 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태
  • 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도를 유지해야 함
  • 느슨하게 연결된 형태를 유지하는 것이 바람직
  • 꼭 필요한 최소한의 방법만 제공
  • 결합도가 낮아지면 대응하는 속도가 높아지고 구성이 깔금해짐

전략패턴

  • 자신의 기능 맥락(context)에서 필요에 따라 변경이 필요한 알고리즘을 인터페스를 통해 통째로 외부로 분리시키고 이률 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔 사용할 수 있게 하는 디자인 패턴