디자인 모델 의 아름다움 학습 - 리 식 교체 원칙 (4)

8395 단어
무엇이 리 식 교체 원칙 입 니까?
하위 클래스 대상 (object of subtype / derived class) 은 프로그램 (program) 의 부모 클래스 대상 (object of base / parent class) 이 나타 나 는 모든 곳 을 교체 할 수 있 으 며, 원래 프로그램의 논리 적 행위 (behavior) 가 변 하지 않 고 정확성 이 파괴 되 지 않도록 보장 합 니 다.
반 례
public class Transporter {
  private HttpClient httpClient;
  
  public Transporter(HttpClient httpClient) {
    this.httpClient = httpClient;
  }

  public Response sendRequest(Request request) {
    // ...use httpClient to send request
  }
}

public class SecurityTransporter extends Transporter {
  private String appId;
  private String appToken;

  public SecurityTransporter(HttpClient httpClient, String appId, String appToken) {
    super(httpClient);
    this.appId = appId;
    this.appToken = appToken;
  }

  @Override
  public Response sendRequest(Request request) {
    if (StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(appToken)) {
      request.addPayload("app-id", appId);
      request.addPayload("app-token", appToken);
    }
    return super.sendRequest(request);
  }
}

public class Demo {    
  public void demoFunction(Transporter transporter) {    
    Reuqest request = new Request();
    //...    request       ...
    Response response = transporter.sendRequest(request);
    //...      ...
  }
}

//       
Demo demo = new Demo();
demo.demofunction(new SecurityTransporter(/*    */););

하위 클래스 는 Transporter 를 계승 하여 sendRequest 를 재 작성 하여 전송 app - id 를 추 가 했 습 니 다.  app - token 은 원래 프로그램의 논 리 를 파괴 하지 않 았 습 니 다. Security Transporter 는 부류 가 나타 나 는 임의의 곳 을 교체 할 수 있 습 니 다.
반 례
//
public class SecurityTransporter extends Transporter {
  //...      ..
  @Override
  public Response sendRequest(Request request) {
    if (StringUtils.isNotBlank(appId) && StringUtils.isNotBlank(appToken)) {
      request.addPayload("app-id", appId);
      request.addPayload("app-token", appToken);
    }
    return super.sendRequest(request);
  }
}

//
public class SecurityTransporter extends Transporter {
  //...      ..
  @Override
  public Response sendRequest(Request request) {
    if (StringUtils.isBlank(appId) || StringUtils.isBlank(appToken)) {
      throw new NoAuthorizationRuntimeException(...);
    }
    request.addPayload("app-id", appId);
    request.addPayload("app-token", appToken);
    return super.sendRequest(request);
  }
}

여 기 는 리 식 교체 원칙 에 부합 되 지 않 는 다.  Security Transporter 는 부모 클래스 가 나타 나 는 임의의 곳 을 교체 할 수 없 기 때문에 원래 프로그램 이 appId 와 AppToken 을 전달 하지 않 았 거나 이상 처리 하지 않 았 다 면 이상 할 수 있 습 니 다.
리 식 교체 원칙 을 위반 한 몇 가지 상황
1. 하위 클래스 가 부모 성명 에 위배 되 는 기능
부모 클래스 에서 제공 하 는 sortOrders ByAmount () 주문 정렬 함 수 는 금액 에 따라 어 렸 을 때 부터 큰 것 으로 주문 에 정렬 되 었 으 며, 하위 클래스 는 이 sortOrders ByAmount () 주문 정렬 함 수 를 다시 쓴 후 생 성 날짜 에 따라 주문 에 정렬 되 었 습 니 다.그 부류 의 설 계 는 리 식 교체 원칙 에 위배 된다.
2. 하위 클래스 는 부모 클래스 의 입력, 출력, 이상 에 대한 약속 에 위배 된다.
부모 클래스 에서 어떤 함수 약속: 실행 오류 가 발생 했 을 때 null 로 돌아 가기;데이터 가 비어 있 을 때 빈 집합 (empty collection) 을 되 돌려 줍 니 다.하위 클래스 리 셋 함수 가 바 뀌 었 습 니 다. 오류 반환 이상 (exception) 을 실행 하여 데 이 터 를 가 져 오지 못 하고 null 로 돌아 갑 니 다.그 부류 의 설 계 는 리 식 교체 원칙 에 위배 된다.부모 클래스 에서 특정한 함수 가 데 이 터 를 입력 하 는 것 은 임 의 정수 일 수 있 지만 하위 클래스 가 실 현 될 때 입력 데이터 가 정수 이 고 마이너스 만 던 질 수 있다. 즉, 하위 클래스 가 입력 한 데이터 에 대한 검증 이 부모 클래스 보다 더욱 엄격 하고 그 하위 클래스 의 디자인 은 내부 교체 원칙 에 위배 된다 는 것 이다.부모 클래스 에서 어떤 함수 가 Argument Null Exception 이상 만 던 질 것 이 라 고 약 속 했 습 니 다. 그 하위 클래스 의 디자인 실현 에 서 는 Argument Null Exception 이상 만 던 질 수 있 고 다른 이상 한 던 지면 하위 클래스 가 내부 교체 원칙 에 어 긋 날 수 있 습 니 다.
3. 하위 클래스 는 부모 클래스 주석 에 나 열 된 모든 특수 설명 에 위배 된다.
부모 클래스 에서 정의 하 는 withdraw () 현금 인출 함수 에 대한 설명 은 이렇게 쓰 여 있 습 니 다. "사용자 의 현금 인출 금액 은 계 정 잔액 을 초과 해 서 는 안 됩 니 다." 그리고 하위 클래스 가 withdraw () 함 수 를 다시 쓴 후에 VIP 계 정 에 대해 당좌대월 현금 인출 기능 을 실 현 했 습 니 다. 즉, 현금 인출 금액 은 계 정 잔액 보다 클 수 있 습 니 다. 그러면 이 하위 클래스 의 디자인 도 내부 교체 원칙 에 부합 되 지 않 습 니 다.이상 은 바로 세 가지 전형 적 인 리 식 교체 원칙 에 어 긋 나 는 상황 이다.그 밖 에 서브 클래스 의 디자인 실현 이 리 식 교체 원칙 에 어 긋 나 는 지 판단 하 는 작은 비결 도 있다. 그것 은 바로 부모 류 의 단원 테스트 를 통 해 서브 클래스 의 코드 를 검증 하 는 것 이다.만약 에 일부 단원 의 테스트 운행 이 실패 하면 서브 클래스 의 디자인 이 부모 류 의 약속 을 완전히 지 키 지 않 았 고 서브 클래스 는 리 식 교체 원칙 에 어 긋 날 수 있다 는 것 을 설명 할 수 있다.실제로 당신 은 이 원칙 을 내부 적 으로 바 꾸 는 것 이 매우 느슨 하 다 는 것 을 발견 한 적 이 있 습 니까?일반적으로 우리 가 쓴 코드 는 그것 을 그다지 위배 하지 않 는 다.그래서 네가 내 가 오늘 말 한 이런 것들 을 이해 할 수만 있다 면 이 원칙 은 파악 하기 어렵 지도 않 고 응용 하기 어렵 지도 않다.

좋은 웹페이지 즐겨찾기