자바 디자인 모델-원형 모델 상세 설명

예 를 들다
질문:
현재 양 한 마리(속성 포함:이름 Dolly,나이 2)가 있 습 니 다.속성 이 똑 같은 양 10 마 리 를 복제 해 야 합 니 다.
일반 해법:
구조 기,getter(),toString()을 포함 하여 Sheep 류 를 정의 합 니 다.

public class Sheep {
    private String name;
    private int age;
    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
클 라 이언 트 에서 도 리 를 예화 한 다음 에 도리 의 속성 에 따라 10 마리 의 양 을 예화 한다.

public class Client {
    public static void main(String[] args) {
        Sheep sheepDolly=new Sheep("Dolly",2);
        Sheep sheep1 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        Sheep sheep2 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        Sheep sheep3 = new Sheep(sheepDolly.getName(), sheepDolly.getAge());
        //....
        System.out.println(sheep1+",hashCode:"+sheep1.hashCode());
        System.out.println(sheep2+",hashCode:"+sheep2.hashCode());
        System.out.println(sheep3+",hashCode:"+sheep3.hashCode());
        //...
    }
}
실행 결과
在这里插入图片描述
장단 점:
이런 방법 은 우리 가 먼저 쉽게 생각 할 수 있 는 것 이자 절대 다수의 첫 번 째 방법 이다.
그러나 단점 도 뚜렷 하 다.새로운 대상 을 만 들 때마다 원시 대상 의 속성 을 얻어 야 하고 대상 이 복잡 할 때 효율 이 낮다.또한 대상 이 실 행 될 때의 상 태 를 동적 으로 얻 을 수 없 으 며,클래스 증감 속성 은 코드 를 변경 해 야 합 니 다.
다음은 원형 모델 의 해법 을 살 펴 보 자.
원형 모드
프로 토 타 입 모드(Prototype Pattern)는 생 성 형 디자인 모델 로 한 대상 이 다른 맞 춤 형 대상 을 만 들 수 있 도록 합 니 다.어떻게 만 드 는 지 알 필요 가 없습니다.즉,프로 토 타 입 인 스 턴 스 로 생 성 대상 의 종 류 를 지정 하고 이 프로 토 타 입 을 복사 하여 새로운 대상 을 만 드 는 것 입 니 다.
작업 원리:프로 토 타 입 대상 을 만 들 대상 에 게 전달 합 니 다.만 들 대상 은 프로 토 타 입 대상 에 게 복사 요청 을 통 해 직접 만 듭 니 다.기본 Object 의 clone()방법 이나 직렬 화 를 사용 하 는 것 이다.
UML 도표:
在这里插入图片描述
  • Prototype:원형 류,자신 을 복제 하 는 인터페이스 성명
  • Concrete Prototype:구체 적 인 원형 류 로 자신 을 복제 하 는 작업 을 실현 합 니 다
  • Client:클 라 이언 트 가 원형 대상 에 게 자신 을 복제 하여 새로운 대상 을 만 듭 니 다
  • 원형 모드 는 얕 은 복사 와 깊 은 복사 로 나 눌 수 있 습 니 다.데이터 형식 을 참조 하 는 구성원 변 수 를 복사 하 는 것 과 차이 가 있 습 니 다.어린이 에 게 물음표 가 많 습 니까?급 하지 않 아,이 두 가지 방법 을 보고 실현 하면 너 는 알 게 될 거 야.
    얕 은 복사
    기 존 Sheep 류 를 바탕 으로 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 다시 씁 니 다.
    
    public class Sheep implements Cloneable{
        private String name;
        private int age;
        @Override
        protected Object clone()  {//     ,     clone     
            Sheep sheep = null;
            try {
                sheep = (Sheep)super.clone();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            return sheep;
        }
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    클 라 이언 트 호출
    
    public class Client {
        public static void main(String[] args) {
            Sheep sheepDolly=new Sheep("Dolly",2);
            Sheep sheep1 = (Sheep)sheepDolly.clone();
            Sheep sheep2 = (Sheep)sheepDolly.clone();
            Sheep sheep3 = (Sheep)sheepDolly.clone();
            //....
            System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
            System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode());
            System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode());
            //...
        }
    }
    
    실행 결과
    在这里插入图片描述
    이로써 원형 모델 의 얕 은 복사 도 세 대상 을 복제 하 는 데 성 공 했 지만 진 도 를 보면 쉽 지 않다.
    현재 새끼 양 에 게 친구 송아지 가 생 겼 습 니 다.Sheep 류 는 인용 속성 Cow 를 추 가 했 습 니 다.우 리 는 똑 같이 다시 복제 합 니 다.
    Sheep 류
    
    public class Sheep implements Cloneable{
        private String name;
        private int age;
        public Cow friend;//   Cow  ,    
        @Override
        protected Object clone()  {
            Sheep sheep = null;
            try {
                sheep = (Sheep)super.clone();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            return sheep;
        }
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    새로 추 가 된 Cow 클래스
    
    public class Cow {
        private String name;
        private int age;
        public Cow(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Cow{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    클 라 이언 트 호출 클론
    
    public class Client {
        public static void main(String[] args) {
            Sheep sheepDolly=new Sheep("Dolly",2);
            sheepDolly.friend=new Cow("Tom",1); //      
            Sheep sheep1 = (Sheep)sheepDolly.clone();
            Sheep sheep2 = (Sheep)sheepDolly.clone();
            Sheep sheep3 = (Sheep)sheepDolly.clone();
            //....
            System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
            System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'
    '); System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode()); System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'
    '); System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode()); System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'
    '); //... } }
    실행 결과
    在这里插入图片描述
    실행 결 과 를 통 해 알 수 있 듯 이 얕 은 복사 본 은 Object 의 clone()을 통 해 세 개의 새로운 대상 을 성공 적 으로 복제 하 였 으 나,복제 실례 화 대상 중의 인용 속성,즉 복제 친구 대상(세트 금지)이 없 었 다.세 개의 새로운 복제 대상 의 friend 는 원래 복제 전의 friend,즉 같은 대상 을 가리킨다.
    이렇게 되면 그들 네 명의 friend 는 같은 것 을 인용 합 니 다.만약 에 한 대상 이 friend 속성 을 수정 하면 다른 세 대상 의 이 구성원 변수 값 에 영향 을 줄 것 입 니 다.
    소결:
  • 얕 은 복 사 는 기본 clone()방법 으로 이 루어 집 니 다
  • 기본 데이터 형식의 구성원 변 수 는 얕 은 복사 가 직접 값 전달(속성 값 을 새 대상 에 게 복사)합 니 다.
  • 데이터 형식의 구성원 변 수 를 참조 하고 얕 은 복사 본 은 인용 전달(참조 값(메모리 주소)을 새 대상 에 게 복사 합 니 다).
  • 딥 카피
    방법 1:
    영리 한 사람 은 다시 한 번 cow 를 복제 하면 되 지 않 겠 습 니까?하지만 수 동 으로 돌아 가 는 것 은 추천 하지 않 습 니 다.
    1.Cow 클래스 도 Cloneable 인터페이스 구현
    
    public class Cow implements Cloneable{
        private String name;
        private int age;
        public Cow(String name, int age) {
            this.name = name;
            this.age = age;
        }
        //     ,  clone  
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); //     ,  try-catch
        }
        @Override
        public String toString() {
            return "Cow{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    Sheep 류 의 clone 에 cow 를 호출 하 는 clone 을 추가 합 니 다.
    
    public class Sheep implements Cloneable{
        private String name;
        private int age;
        public Cow friend;//   Cow  ,    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Object deep = null;
            //         (  ) String   
            deep = super.clone();
            //        ,    clone
            Sheep sheep = (Sheep)deep;
            sheep.friend  = (Cow)friend.clone();
            return sheep;
        }
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    클 라 이언 트 호출
    
    public class Client {
        public static void main(String[] args) throws CloneNotSupportedException {
            Sheep sheepDolly=new Sheep("Dolly",2);
            sheepDolly.friend=new Cow("Tom",1); //      
            Sheep sheep1 = (Sheep)sheepDolly.clone();
            Sheep sheep2 = (Sheep)sheepDolly.clone();
            Sheep sheep3 = (Sheep)sheepDolly.clone();
            //....
            System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
            System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'
    '); System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode()); System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'
    '); System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode()); System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'
    '); //... } }
    실행 결과
    在这里插入图片描述
    방법 2:
    대상 직렬 화 를 통 해 딥 복사 실현(추천)
    1.Cow 류 는 직렬 화 인 터 페 이 스 를 실현 하고 Cloneable 인 터 페 이 스 를 실현 할 필요 가 없다.
    
    public class Cow implements Serializable {
        private String name;
        private int age;
        public Cow(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Cow{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    2.Sheep 류 에서 직렬 화 인터페이스 구현
    
    public class Sheep implements Serializable { //       
        private String name;
        private int age;
        public Cow friend;
    
        public Sheep(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
        public Object deepClone() { //   
            //     
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;
            try {
                //   
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);
                oos.writeObject(this); //               
                //    
                bis = new ByteArrayInputStream(bos.toByteArray());
                ois = new ObjectInputStream(bis);
                Sheep sheep = (Sheep) ois.readObject();
                return sheep;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                //   
                try {
                    bos.close();
                    oos.close();
                    bis.close();
                    ois.close();
                } catch (Exception e2) {
                    System.out.println(e2.getMessage());
                }
            }
        }
    }
    
    3.클 라 이언 트 호출
    
    public class Client {
        public static void main(String[] args) throws CloneNotSupportedException {
            Sheep sheepDolly=new Sheep("Dolly",2);
            sheepDolly.friend=new Cow("Tom",1); //      
            Sheep sheep1 = (Sheep)sheepDolly.deepClone();
            Sheep sheep2 = (Sheep)sheepDolly.deepClone();
            Sheep sheep3 = (Sheep)sheepDolly.deepClone();
            //....
            System.out.println("sheep1:"+sheep1+",hashCode:" + sheep1.hashCode());
            System.out.println("sheep1.friend:"+sheep1.friend+",hashCode:" + sheep1.friend.hashCode()+'
    '); System.out.println("sheep2:"+sheep2+",hashCode:" + sheep2.hashCode()); System.out.println("sheep2.friend:"+sheep2.friend+",hashCode:" + sheep2.friend.hashCode()+'
    '); System.out.println("sheep3:"+sheep3+",hashCode:" + sheep3.hashCode()); System.out.println("sheep3.friend:"+sheep3.friend+",hashCode:" + sheep3.friend.hashCode()+'
    '); //... } }
    실행 결과
    在这里插入图片描述
    원형 모드 요약:
  • 새로운 대상 을 만 드 는 것 이 복잡 할 때 원형 모델 을 이용 하여 대상 의 생 성 과정 을 간소화 할 수 있 고 효율 도 높 일 수 있다
  • 대상 을 다시 초기 화하 지 않 고 대상 이 실 행 될 때의 상 태 를 동적 으로 얻 을 수 있 습 니 다.
  • 원본 대상 에 변화(속성 증가 또는 감소)가 발생 하면 다른 복제 대상 에 도 해당 하 는 변화 가 발생 하여 코드 를 수정 할 필요 가 없다
  • 만약 에 구성원 변수 가 인용 유형 이 없 으 면 클론 을 간단하게 복사 하면 됩 니 다.인용 형식의 구성원 변수 가 적 으 면 클 라 이언 트 를 재 귀적 으로 실현 하 는 것 을 고려 할 수 있 습 니 다.그렇지 않 으 면 직렬 화 를 추천 합 니 다.
  • 총결산
    이 글 은 여기까지 입 니 다.당신 에 게 도움 을 줄 수 있 기 를 바 랍 니 다.또한 당신 이 우리 의 더 많은 내용 에 관심 을 가 져 주 실 수 있 기 를 바 랍 니 다!

    좋은 웹페이지 즐겨찾기