본문 바로가기

개발공부

객체 지향 설계 - SOLID(2)

3.  LSP(리스코프 치환 원칙)

  LSP는 프로그램 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다는 원리이다. 위반할 경우 사용자가 의도되지 않는 기능을 불러다가 사용할 수 있다.

 

  1) 위배되는 코드

     - 하위 클래스의 인스턴스가 정확성을 깨뜨리는 경우

     - 타조는 날수 없는 새이기 때문에 상위 인터페이스 Bird의 fly를 수행 하지 못함 (정확성 깨짐)

 

static void Main {
   Bird bird = new Ostrich();
   bird.fly();
}

public interface Bird{
    public void fly();
}

public class Pigeon implement Bird{
    public void fly(){
       구현
    }
}

public class Ostrich implemnet Bird{
    public void fly(){
       구현
    }
}

 

  2) LSP를 적용한 코드

     - 날수 있는 새와 날수 없는 새로 interface 분리하여 LSP 적용

 

 public interface FlyBird{
     public void eat();
     public void fly();
 }

 public interface NoneFlyBird{
     public void eat();
 }

 public class Pigeon implement FlyBird{
     public void eat(){}
     public void fly(){
        구현
    }
 }

 public class Ostrich implement NoneFlyBird{
     public void eat(){
        구현
    }
 }

 

4. ISP(인터페이 분리 원칙)

  ISP특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다는 원칙이다. 범용 인터페이스를 상속받는 하위 클래스에 필요 없는 기능까지 포함될 수 있다. 또한 추가 및 수정할 때 모두 범용 인터페이스를 변경해야 한다.

 

  1) 위배되는 코드

     - 두개 이상으로 분리될 수 있는 인터페이스를 범용 인터페이스 하나로 만드는 경우

     - 비행기 인터페이스와 자동차 인터페이스를 하나의 범용 Vehicle 인터페이스로 구성

 

public interface Vehicle() {
    public void drive()
    public void fly()
    public void ride()
}

public class Flight implement Vehicle{
    public void fly()
}

public class Car implement Vehicle{
    public void drive()
}

 

  2) ISP를 적용한 코드

     - 범용 인터페이스 Vehicle를 Flight와 Car 인터페이스로 분리하여 ISP 적용

 

public interface Flight {
    public void fly()
}

public interface Car {
    public void drive()
}

 

5. DIP(의존관계 역전 원칙)

  DIP구체적인 클래스추상적인 클래스에 의존해야한다는 원칙이다. 인터페이스나 추상 클래스를 구체적 클래스가 의존하게 구성해야 한다. 위배되는 경우 구체적 클래스가 추가적으로 생길 때마다 추상 클래스의 변경이 이루어지게 된다.

 

  1) 위배되는 코드

     - 추상적인 클래스가 구체적인 클래스를 의존하는 경우

     - PayService(추상) 클래스가 SamsungPay(구체) 클래스에 의존

     - IphonePay(구체)를 새로 생성할 경우 PayService(추상) 클래스 변경이나 새로운 클래스 하나 생성해야 한다

 

public class SamsungPay {
    String payment() {
        구현
    }
}

public class PayService {
    private SamsungPay pay;

    public String payment() {
        return pay.payment();
    }
}

 

  2) DIP를 적용한 코드

     - PayService를 인터페이스로 SaumsungPay(구체) 및 IphonePay(구체)를 하위 클래스로 구성함으로 DIP 적용

 

  public interface PayService {
      public payment(){
  }

  public class SamsungPay implement PayService {
      public payment(){
        구현
    }
  }

  public class IphonePay implement PayService {
      public payment(){
        구현
    }
  }

 

  SOLID 모든 구성 요소가 위반되는 경우와 각 원칙을 적용한 코드를 살펴봤다. 이번 기회를 통해 배운 것을 코드를 작성을 하거나 리팩토링할 때 적용할 수 있도록 노력해야겠다.