자바 학습 노트 - 디자인 모델: 리 씨 교체 원칙

11976 단어 디자인 모드
리 스 교체 원칙 정의:
  • 정의 1: 각 유형 이 T1 인 대상 o1 이면 T2 인 대상 o2 가 있어 T1 유형의 프로그램 P 에서 모든 T1 유형의 대상 o1 을 T2 유형의 대상 o2 로 교체 한 후 프로그램 P 의 행위 (기능) 에 변화 가 없 으 면 유형 T2 는 유형 T1 의 하위 유형 입 니 다.
  • 정의 2: 모든 인용 기본 클래스 는 하위 클래스 대상 을 투명 하 게 인용 해 야 합 니 다.
  • 이해:
  • 자 류 는 하나의 부류 로 부류 가 나타 날 수 있 는 지방 자 류 는 반드시 나타 날 수 있다.
  • 부류 가 완성 할 수 있 는 기능 하위 클래스 도 완성 할 수 있다.
  • 리 스 교체 원칙 의 내 적 의미:
  • 의미 1: 자 류 는 부류 의 추상 적 인 방법 을 실현 할 수 있 으 나 부류 의 비 추상 적 인 방법 을 덮어 서 는 안 된다. [핵심 관념]
  • 의미 2: 자 류 에서 자신 만 의 독특한 방법 을 증가 시 킬 수 있다.
  • 의 미 는 세 가지 가 있다. 선행 조건 이 확대 되 고 자 류 는 부 류 를 다시 싣 는 실현 방법 이 있 을 때 방법의 선행 조건 (형 삼) 범 위 는 부 류 보다 더욱 넓 어야 한다.
  • 의미 4: 후장 조건 이 축소 되 고 자 류 가 부계 의 추상 적 인 방법 을 실현 할 때 방법의 후장 조건 (반환 값) 범 위 는 부계 보다 더욱 엄격 하거나 같 아야 한다.
  • 이해 1: 1, 하위 클래스 에 대해 부모 클래스 를 수정 하거나 덮어 쓰 지 않 는 것 이 좋 은 방법 입 니 다.
    문제: 왜 하위 클래스 는 부모 클래스 가 이미 실 현 된 방법 을 수정 하거나 덮어 쓰 지 않 습 니까?
    리 씨 교체 원칙 의 정의 위반 리 씨 교체 원칙 에 위반 하여 '자 류 는 하나의 아버지 류 이 고 아버지 류 가 나타 날 수 있 는 곳 의 자 류 는 반드시 나타 날 수 있다' 는 정 의 를 내 렸 다. 자 류 와 아버지 류 의 실현 방법 기능 이 다 르 면 자 류 는 반드시 아버지 류 를 완전히 교체 할 수 있 는 것 이 아니다 (기능 이 일치 하지 않 음).
  • 계승 시스템 에서 중복 코드 를 추출 하 는 목적 에 이 르 지 못 한다.
  • 우리 가 계승 을 사용 하 는 많은 이 유 는 재 활용 가능 한 중복 코드 를 추출 하여 같은 '유형' 에서 코드 의 중복 정 의 를 줄 이기 위해 서 입 니 다.상속 시스템 에서 대부분의 하위 클래스 가 부모 클래스 를 덮어 쓰 는 방법 이 필요 하 다 면 중복 코드 를 줄 이 는 역할 을 하지 못 할 것 이다.
  • 방법 호출 의 혼란:
  • 부모 류 에서 이미 실 현 된 방법 은 일련의 구체 적 인 행위 규칙 (인터페이스 와 달리 인 터 페 이 스 는 행위 가 끈기 있 는 추상 적 인 정의 이 고 실현 류 는 반드시 실현 해 야 한다) 을 정의 하 는 것 과 같다. 비록 부모 류 는 모든 하위 류 가 반드시 이런 규칙 을 지 켜 야 한다 고 요구 하지 않 지만 하위 류 가 부모 류 의 이런 '규칙' 을 임의로 수정 하면전체 상속 체계의 혼란 을 초래 할 것 이다.
    만약 에 아버지 류 에서 이미 실 현 된 방법 이 여러 개의 하위 클래스 에 의 해 임의로 덮어 쓰 이 고 다시 쓰 면 이 계승 체계 에서 같은 방법 이 여러 개의 서로 다른 실현 에 대응 하 게 될 것 이다.즉, 서로 다른 하위 유형의 다 형 유형 을 사용 할 때 같은 방법 으로 성명 하면 서도 서로 다른 실현 (기능) 장면 에 직면 하 게 된다. 그러면 전체 계승 체계 가 혼 란 스 럽 고 모호 해 질 것 이다. 특히 이 계승 체계의 다 형 을 자주 사용 할 때 오류 가 발생 할 가능성 이 커진다. 예 를 들 어:
    //   
    public class Parent {
    
        //            :     
        public int function(int a, int b) {
            return (a + b);
        }
    
    }
    
    
    //   1
    public class Son1 extends Parent {
    
        //         getSum()  :     
        @Override
        public int function(int a, int b) {
            return (a - b);
        }
    
    }
    
    //   2
    public class Son2 extends Parent {
    
        //         getSum()  :     
        @Override
        public int function(int a, int b) {
            return (a / b);
        }
    
    }
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            // 2:   
            int num = son1.function(1, 2);
        
        }
    
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son1 son1 = new Son1();
            
            // 2:            ,              。
            int num = son1.function(1, 2);
        
        }
    
    }

    다시 말 하면 하나의 계승 체계 에서 아버지 류 의 일부 방법 이 빈번 한 이불 류 의 실현 이 필요 하 다 면 각 하위 류 에서 해당 하 는 방법 을 각각 정의 하 는 것 이 바람 직 하 다.중복 코드 에 속 하지 않 으 며, 해당 하위 클래스 에서 서로 다른 기능 의 코드 로 '이름 을 보고 의 미 를 안다' 는 방법 으로 서명 할 수 있 기 때문이다.
    이해 2: 2 에 대해 자 류 는 자신의 '특색' 을 가 질 수 있다.
    자 류 는 부 류 를 바탕 으로 자신 만 의 독특한 기능 을 증가 시 킬 수 있다.이런 종 류 는 더 많은 기능 을 완성 할 수 있 고 부 류 를 완전히 투명 하 게 교체 할 수 있다.
    이해 3: 3, 방법 재 업로드 규칙
    1. 방법의 선행 조건 과 선행 조건 은 무엇 입 니까?
    방법, 즉 어떤 행위 나 기능 을 가 진 코드 를 봉인 하 는 것 이다.선행 조건, 즉 방법의 형 삼 은 방법 기능 의 실현 을 위해 필요 한 데 이 터 를 전달 하 는 것 이다.후장 조건, 즉 방법의 반환 값 으로 기능 방법의 최종 결 과 를 얻는다.
    2. 왜 방법의 형 삼 과 반환 값 을 '조건' 이 라 고 부 릅 니까?
    방법의 매개 변수 와 반환 값 은 이 방법의 '실현 규칙', 즉 실현 방법의 기능 에 필요 한 전제 조건 과 최종 적 으로 어떤 유형의 결 과 를 얻 는 지 정의 하 는 것 이다.구체 적 으로 어떻게 실현 하 든 간 에 방법의 전제 와 결과 제약 만 만족 시 키 면 된다.통속 적 인 것 은 '어떤 일 을 완성 하려 면 먼저 무엇 을 가 져 야 하고, 마지막 에 무엇 을 가 져 야 하 는가' 이다.
    3. 방법의 재 업로드 와 재 작성 은 무엇 입 니까?
    (1) 하위 클래스 덮어 쓰기 부모 클래스 방법 규칙: 방법 명 이 같 고 매개 변수 가 같 으 며 이상 축소, 권한 확대, 반환 값 이 같 거나 축소 합 니 다.만족 하지 않 으 면 덮어 쓰 기 를 하지 않 습 니 다 [방법 조건 이 같 고 구체 적 인 실현 방식 이 다 릅 니 다].다시 쓴 방법 으로 원래 의 방법 을 바 꾸 고 원래 의 방법 은 바 뀌 었 다.
                  이상 축소: 하위 클래스 방법 에서 던 진 이상 은 부모 클래스 성명 의 이상 과 같 거나 하위 클래스 이상 이 어야 합 니 다.하위 클래스 방법 이 부모 클래스 보다 이상 하 다 고 밝 히 면 하위 클래스 는 부모 클래스 를 완전히 투명 하 게 교체 할 수 없습니다.예 를 들 어 부모 클래스 성명 은 빈 포인터 이상 을 던 졌 고 하위 클래스 는 Exception 이상 을 던 졌 습 니 다. 그러면 하위 클래스 를 사용 하여 부모 클래스 를 교체 할 때 기 존 프로그램의 이상 캡 처 체 제 는 하위 클래스 방법 으로 던 지 는 이상 을 제어 할 수 없습니다.
    //   
    public class Parent {
    
        //       ,       
        public int function(int a, int b) throws NullPointerException {
            return (a + b);
        }
    
    }
    
    
    //   
    public class Son extends Parent {
    
        //         ,      :  Exception  
        @Override
        public int function(int a, int b) throws Exception {
            return (a - b);
        }
    
    }
    
    
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            try {
                //                    
                int sum = parent.function(1, 2);
    	} catch (NullPointerException e) {
    			e.printStackTrace();
    	}
        }
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son son = new Son();
            
           
            try {
                //           ,                       
                int sum = son.function(1, 2);
    	} catch (NullPointerException e) {
    			e.printStackTrace();
    	}
        
        }
    
    }

                  반환 값 이 같 거나 축소 되 었 습 니 다. 하위 클래스 가 실현 하 는 방법 은 반환 값 유형 이 부모 클래스 와 같 거나 축소 되 어야 합 니 다.아버지 가 과일 류 가 실현 하 는 반환 치가 아버지 류 보다 크 면 자 류 는 아버지 류 를 완전히 투명 하 게 교체 할 수 없 을 것 이다.예 를 들 어 부모 클래스 의 반환 값 은 List 이 고, 하위 클래스 는 Collection 을 되 돌려 줍 니 다. 그러면 원래 프로그램 은 하위 클래스 의 반환 값 을 사용 할 수 없습니다.이때 하위 클래스 는 부모 클래스 를 완전히 투명 하 게 교체 하지 못 할 수 있 습 니 다. 즉, 하위 클래스 가 부모 클래스 를 교체 한 후에 원래 프로그램의 운행 상황 에 영향 을 줄 수 있 고 원래 방법의 사후 조건 제약 을 깨 뜨 릴 수 있 습 니 다.
    //   
    public class Parent {
    
        //       ,  List  
        public List function() {
            return new ArrayList();
        }
    
    }
    
    
    //   
    public class Son extends Parent {
    
        //         ,      :  Set  
        @Override
        public Collection function(int a, int b) {
            return new LinkedHashSet<>();
        }
    
    }
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            // 2:   List  
            List list = parent.function();
        
        }
    
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son son = new Son();
            
            // 2:        List  ,          Set  。
            List list = son.function();
        
        }
    
    }

       매개 변수 가 같 습 니 다. 부모 류 의 방법 정 의 는 '규칙 계약' 을 정의 하 는 것 입 니 다. 이 기능 이나 행 위 를 실현 하려 면 반드시 만족 해 야 합 니 다.
     
    (2) 방법 재 부팅 의 규칙: 방법 명 이 같 고 매개 변수 목록 이 다 릅 니 다 - > 매개 변수 목록 에 따라 그 방법 을 실행 합 니 다.기 존 방법의 매개 변수 범 위 는 비교적 단일 하 므 로 이 방법의 조건 수용 범 위 를 늘 려 야 하 며, 과부하 되 는 원래 방법 과 새로운 방법 이 모두 존재 하여 호출 할 수 있다.[서로 다른 조건, 서로 다른 실현]
     
    4. 다시 싣 고 다시 쓰 는 의미?
  • 과부하: 기 존의 방법의 실현 방식 은 이미 적합 하지 않 습 니 다. 기 존의 조건 에 따라 다시 실현 해 야 합 니 다. 기 존의 방법 은 더 이상 사용 하지 않 습 니 다.
  • 재 작성: 기 존 방법의 매개 변수 조건 이 '광범 위' 하지 않 기 때문에 더 많은 조건 과 일치 해 야 하지만 기 존 방법 은 사용 할 수 있 습 니 다.

  • 5. 재 업로드 와 재 작성 으로 인 한 결과?
  • 재 작성: 기 존의 방법 은 새로운 방법 으로 덮어 씁 니 다 [이 하위 클래스 만 을 대상 으로 합 니 다].
  • 리 셋: 기 존의 방법 과 새로운 방법 이 공존 하고 매개 변수 목록 에 따라 그 방법 을 판단 합 니 다.

  • 6. 왜 하위 클래스 는 부모 클래스 를 다시 불 러 올 때 선행 조건 의 확대 가 필요 합 니까?[중요 한 장면]
    하위 클래스 방법 과 부모 클래스 의 방법 매개 변 수 는 다음 과 같은 세 가지 상황 이 존재 할 수 있 습 니 다.
  • 매개 변 수 는 같 습 니 다. 재 작성 에 속 합 니 다. 하위 클래스 방법 은 부모 클래스 를 덮어 쓰 는 방법 으로 하위 클래스 의 방법 만 실행 할 수 있 고 방법 재 업로드 규정 에 부합 되 지 않 습 니 다.
  • 매개 변수 범위 축소: 과부하 에 속 하지만 하위 매개 변수 범위 가 부모 매개 변수 범위 보다 작 기 때문에 다음 과 같은 가능성 이 발생 할 수 있 습 니 다.
  • //   
    public class Parent {
    
        //       ,  Collection      
        public String function(Collection coll) {
            return "  ";
        }
    
    }
    
    
    //   
    public class Son extends Parent {
    
        //         ,      :  Set      
        @Override
        public String function(List list) {
            return "  ";
        }
    
    }
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            // 2:   List  
            List list = new ArrayList<>();
            String str = parent.function(list); //       
            ......
            // 3:     Set  
            Set set = new LinkedHashSet<>();
            String str = parent.function(set); //       
        
        }
    
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son son = new Son(); 
    
            // 2:   List  ,
            List list = new ArrayList<>();
            String str = son.function(list); //       
            ......
            // 3:     Set  
            Set set = new LinkedHashSet<>();
            String str = son.function(set); //       
        
        }
    
    }

    매개 변 수 를 입력 할 때 매개 변수 범위 가 하위 클래스 방법의 범위 안에 있 으 면 하위 클래스 방법 을 실행 합 니 다.만약 에 매개 변수 범위 가 하위 클래스 방법의 범위 보다 크 고 부모 클래스 방법의 매개 변수 범위 보다 작다 면 이때 실행 하 는 것 은 부모 클래스 의 방법 이다.
    따라서 하위 클래스 를 사용 하여 부모 클래스 를 교체 한 후 같은 대상 을 사용 하여 같은 방법 을 호출 하면 다른 결과 가 나온다.이때 하위 클래스 는 부모 클래스 를 완전히 투명 하 게 교체 하지 못 할 수 있 습 니 다. 즉, 하위 클래스 가 부모 클래스 를 교체 한 후에 원래 프로그램의 운행 상황 에 영향 을 줄 수 있 습 니 다.
  • 확대: 다시 불 러 옵 니 다. 부모 클래스 를 사용 하 는 원 프로그램 에서 매개 변수의 범 위 는 부모 클래스 매개 변수 가 받 아들 이 는 최대 범위 보다 클 수 없습니다. 따라서 하위 클래스 를 사용 하여 부모 클래스 를 교체 한 후에 실 행 된 것 은 부모 클래스 방법 입 니 다. 하위 클래스 는 부모 클래스 를 완전히 투명 하 게 교체 할 수 있 고 원 프로그램의 운행 상태 에 영향 을 주지 않 습 니 다.
  • //   
    public class Parent {
    
        //       ,  Collection      
        public String function(Collection coll) {
            return "  ";
        }
    
    }
    
    
    //   
    public class Son extends Parent {
    
        //         ,      :  Object    
        @Override
        public String function(Object obj) {
            return "  ";
        }
    
    }
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            // 2:   List  
            List list = new ArrayList<>();
            String str = parent.function(list); //       
            ......
            // 3:     Set  
            Set set = new LinkedHashSet<>();
            String str = parent.function(set); //       
        
        }
    
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son son = new Son(); 
    
            // 2:   List  ,
            List list = new ArrayList<>();
            String str = son.function(list); //       
            ......
            // 3:     Set  
            Set set = new LinkedHashSet<>();
            String str = son.function(set); //       
        
        }
    
    }

     
    이해 3: 4, 방법 재 작성 규칙
    하위 클래스 에서 부모 클래스 방법 을 다시 쓸 때 하위 클래스 방법의 반환 값 이 부모 클래스 보다 크 면 하위 클래스 는 부모 클래스 를 완전히 교체 하지 못 할 수 있 습 니 다. 부모 클래스 를 교체 하면 원래 프로그램의 운행 에 영향 을 줄 수 있 습 니 다.
    //   
    public class Parent {
    
        //       ,  List  
        public List function() {
            return new ArrayList();
        }
    
    }
    
    
    //   
    public class Son extends Parent {
    
        //         ,      :  Set  
        @Override
        public Collection function(int a, int b) {
            return new LinkedHashSet<>();
        }
    
    }
    
    
    //    :         
    public class Test1 {
    
        public static void main(String[] args) {
    
            // 1:     
            Parent parent = new Parent(); 
    
            // 2:   List  
            List list = parent.function();
        
        }
    
    }
    
    
    //    :             
    public class Test2 {
    
        public static void main(String[] args) {
    
            // 1:          
            Son son = new Son();
            
            // 2:        List  ,          Set  。
            List list = son.function();
        
        }
    
    }

    리 씨 교체 원칙 은 본질 적 으로 '자 류 는 부 류 를 교체 한 후에 원래 프로그램의 운행 상태 에 영향 을 주어 서 는 안 된다' 는 말 이다.
    실제 개발 에 서 는 확장 가능 한 기능 을 달성 하기 위해 다 형 을 자주 사용한다.하위 클래스 의 기능 확장 에 있어 서 리 씨 교체 원칙 을 지 키 지 않 으 면 확 장 된 하위 클래스 를 사용 하여 기 존의 부모 클래스 를 교체 할 때 원래 프로그램의 운행 상태 에 영향 을 줄 수 있 습 니 다.

    좋은 웹페이지 즐겨찾기