창설 형 디자인 모델 의 깊 은 복사 와 얕 은 복사 원형 모델

10946 단어 디자인 모드
정의
프로 토 타 입 모드 (Prototype Pattern) 는 생 성 형 디자인 모델 중 하나 로 대상 을 직접 만 드 는 대가 가 클 때 기 존 대상 을 복제 하여 성능 원 가 를 절약 하 는 데 사용 된다.예 를 들 어 한 대상 이 높 은 대가 의 IO 나 데이터 베 이 스 를 방문 해 야 만 들 수 있 습 니 다. 이러한 경우 초기 화 는 매우 많은 자원 을 소화 해 야 합 니 다. 그러면 우 리 는 이미 만 든 대상 을 원형 으로 캐 시 할 수 있 습 니 다. 다음 에 똑 같은 이미지 가 필요 할 때 이 를 복제 할 수 있 습 니 다. 복제 과정 에서 원래 의 구조 방법 은 실행 되 지 않 습 니 다.프로 토 타 입 모델 은 따로 나타 나 지 않 고 공장 모델 과 협조 하 며 먼저 프로 토 타 입 대상 을 캐 시 초기 화 한 다음 에 공장 을 통 해 호출 자 에 게 제공 합 니 다.
2 실현
우리 가 공장 모델 을 사용 할 때 예 를 들 어 원형 모델 은 한 핸드폰 업 체 가 스마트 폰 과 스마트 시계 두 가지 하드웨어 제품 을 생산 해 야 한다 고 가정 한다. 그 중에서 핸드폰 과 시 계 는 대상 을 만 들 때 초기 화 비용 이 매우 높 기 때문에 원형 모델 의 형식 으로 이미 존재 하 는 원형 대상 을 복제 했다.
제품 류, 핸드폰 과 시 계 는 모두 하드웨어 에 속 하기 때문에 이들 을 추상 화 시 켜 야 한다. 하드웨어 추상 류 는 Cloneable 을 계승 하고 clone 방법 을 다시 써 야 한다.
public abstract class Hardware implements Cloneable {
    protected int mId;
    protected String mName;
    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
    public abstract void showInfo();
}
public class Phone extends Hardware {
    public Phone(int id, String name) {
        //            
        mId = id;
        mName = name;
    }
    @Override
    public void showInfo() {
        System.out.println("  {" + mId + "," + mName + "}     !");
    }
}
public class Watch extends Hardware {
    public Watch(int id, String name) {
        //            
        mId = id;
        mName = name;
    }
    @Override
    public void showInfo() {
        System.out.println("  {" + mId + "," + mName + "}       !");
    }
}

제품 공장 (제품 캐 시) 은 원형 을 미리 초기 화하 여 캐 시 하 는 데 사 용 됩 니 다. 새로운 대상 을 만 들 려 면 캐 시 대상 을 호출 하 는 clone 방법 으로 새로운 대상 을 복제 해 야 합 니 다.
public class HardwareFactory {
    private static Map sHardwareMap = new HashMap<>();

    public static Hardware createHardware(String hardwareName) {
        Hardware hardware = sHardwareMap.get(hardwareName);
        if (hardware == null) {
            throw new UnsupportedOperationException("      ");
        }
        return (Hardware) hardware.clone();
    }

    public static void init() {
        Hardware phone = new Phone(1, "  1 ");
        sHardwareMap.put("  ", phone);
        Hardware watch = new Watch(2, "  2 ");
        sHardwareMap.put("  ", watch);
    }
}

호출 자: 먼저 하드웨어 공장 에서 제품 대상 의 원형 을 초기 화하 고 나중에 createHardware 방법 으로 복 제 된 새로운 대상 을 직접 가 져 옵 니 다.
HardwareFactory.init();

Hardware phone = HardwareFactory.createHardware("  ");
phone.showInfo();
Hardware phone2 = HardwareFactory.createHardware("  ");
phone2.showInfo();

Hardware watch = HardwareFactory.createHardware("  ");
watch.showInfo();
Hardware watch2 = HardwareFactory.createHardware("  ");
watch2.showInfo();

출력 실행:
  {1,  1 }     !
  {1,  1 }     !
  {2,  2 }       !
  {2,  2 }       !

3 깊 은 복사 와 얕 은 복사
우 리 는 두 가지 개념, 얕 은 복사 와 깊 은 복사 등 을 이해한다.얕 은 복사 란 복사 대상 의 메모리 주소 입 니 다. 예 를 들 어 코드: obj A = obj B;그 중에서 이 두 개의 obj 는 어느 대상 의 속성 이 변화 하 더 라 도 다른 대상 에 게 영향 을 줄 수 있 습 니 다. 이 할당 과정 은 얕 은 복사 이 고 메모리 주소 만 복사 한 것 입 니 다. 즉, 실제 적 으로 같은 대상 을 가리 키 는 것 입 니 다.한편, 심 복 사 는 새로운 대상 을 만 드 는 것 으로 신 구 두 대상 은 그 중의 한 대상 의 변화 에 영향 을 주지 않 는 다.
그러면 우 리 는 상술 한 예 에서 얕 은 복사 입 니까? 깊 은 복사 입 니까?답 은 얕 은 복사 다.우 리 는 아래 에서 상술 한 제품 류 를 개선 하여 반 례 를 들 겠 다.
제품 종류: 이번 에는 하드웨어 추상 류 에 맵 과 사용자 정의 Cpu 류 를 추가 합 니 다.
public abstract class Hardware implements Cloneable {
    protected int mId;
    protected String mName;
    protected Map mScore;
    protected Cpu mCpu;

    public void setId(int id) {
        mId = id;
    }
    public int getId() {
        return mId;
    }
    public void setName(String name) {
        mName = name;
    }
    public void setScore(Map score) {
        mScore = score;
    }
    public void setCpuType(String type) {
        mCpu.setType(type);
    }
    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
    public abstract void showInfo();
}
public class Phone extends Hardware {
    public Phone(int id, String name, Map score, Cpu cpu) {
        mId = id;
        mName = name;
        mScore = score;
        mCpu = cpu;
    }
    @Override
    public void showInfo() {
        System.out.println("  {" + mId + "," + mName + "}     , CPU:" + mCpu.getType() + ",   :" + mScore);
    }
}
public class Cpu {
    private String mType;
    public Cpu(String type) {
        mType = type;
    }
    public void setType(String type) {
        this.mType = type;
    }
    public String getType() {
        return mType;
    }
}

호출 자:
Map score = new HashMap<>();
score.put("    ", 999);
score.put("    ", 888);
Map score2 = new HashMap<>();
score2.put("    ", 100);
score2.put("    ", 200);

Phone phone1 = new Phone(1, "  1 ", score, new Cpu("  865"));
phone1.showInfo();

Phone phone2 = (Phone)phone1.clone();

phone1.setId(2);
phone1.setName("  2 ");
phone1.setScore(score2);
phone1.setCpuType("  770");

phone2.showInfo();

출력 실행:
  {1,  1 }     , CPU:  865,   :{    =999,     =888}
  {1,  1 }     , CPU:  770,   :{    =999,     =888}

설명:
시범 을 보이 기 위해 서, 우 리 는 이번에 제품 공장 (제품 캐 시) 의 역할 을 생략 하고, 직접 호출 자 에 게 제품 대상 을 복제 하도록 했다.호출 자 중 먼저 phone 1 대상 을 원형 으로 만 든 다음 에 phone 2 대상 을 복제 한 다음 에 원형 phone 1 에 대해 4 가지 서로 다른 유형의 속성 을 수정 합 니 다. 각각 int, String, Map 과 사용자 정의 CPU 입 니 다.출력 매듭 을 보면 CPU 클래스 가 수 정 된 것 을 제외 하고 나머지 속성 은 원형 수정 으로 수정 되 지 않 았 습 니 다.
그 이 유 는 Cloneable 의 clone 방법 이 옅 은 복사 방법 을 제공 하기 때 문 입 니 다. 그리고 이 복사 방법 은 선택성 이 있 습 니 다. 예 를 들 어 기본 적 인 유형, 예 를 들 어 int, float, double 등 은 모두 그 값 을 복사 하 는 것 이 고 String, Integer, Float, Double 등 과 집합 은 인용 유형 이지 만 비교적 특수 한 것 도 그 값 을 복사 하 는 것 이 고 사용자 정의 유형 은 안 됩 니 다.주소 만 복사 해서 아이 폰 1 뒤에서 수정 하면 아이 폰 2 의 값 에 도 영향 을 줄 수 있 습 니 다.
3.1 딥 복사 개선 실현
제품 클래스 에서 인 용 된 클래스 도 Cloneable 에 계승 하고 clone 방법 을 실현 합 니 다.
public class Cpu implements Cloneable {
    private String mType;
    public Cpu(String type) {
        mType = type;
    }
    public void setType(String type) {
        this.mType = type;
    }
    public String getType() {
        return mType;
    }
    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

제품 추상 클래스 의 clone 방법 에 대해 클래스 내 다른 사용자 정의 클래스 에 대한 복 제 를 추가 합 니 다. 여기에 코드 를 추가 합 니 다: mCpu = (Cpu) mCpu. clone ();
public abstract class Hardware implements Cloneable {
    protected int mId;
    protected String mName;
    protected Map mScore;
    protected Cpu mCpu;
    public void setId(int id) {
        mId = id;
    }
    public int getId() {
        return mId;
    }
    public void setName(String name) {
        mName = name;
    }
    public void setScore(Map score) {
        mScore = score;
    }
    public void setCpuType(String type) {
        mCpu.setType(type);
    }
    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
            mCpu = (Cpu)mCpu.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
    public abstract void showInfo();
}

수정 후 출력 실행:
  {1,  1 }     , CPU:  865,   :{    =999,     =888}
  {1,  1 }     , CPU:  865,   :{    =999,     =888}

3.2 Serializable 를 사용 하여 깊 은 복사 실현
위 에서 말 한 산 구 류 에서 인용 한 모든 종 류 를 Cloneable 을 계승 하여 clone 을 실현 하 는 것 외 에 serializable 인 터 페 이 스 를 사용 하여 바 이 너 리 흐름 의 직렬 화 를 읽 는 방식 으로 대상 의 깊 은 복 제 를 실현 할 수 있다.
제품 클래스 에서 인용 한 클래스 를 Serializable 로 직접 계승 하면 됩 니 다.
public class Cpu implements Serializable {
    private String mType;
    public Cpu(String type) {
        mType = type;
    }
    public void setType(String type) {
        this.mType = type;
    }
    public String getType() {
        return mType;
    }
}

제품 추상 류 에 대해 서도 Serializable 을 계승 하고 clone 방법 을 수정 합 니 다. 코드 는 다음 과 같 습 니 다.
public abstract class Hardware implements Cloneable, Serializable {
    protected int mId;
    protected String mName;
    protected Map mScore;
    protected Cpu mCpu;
    public void setId(int id) {
        mId = id;
    }
    public int getId() {
        return mId;
    }
    public void setName(String name) {
        mName = name;
    }
    public void setScore(Map score) {
        mScore = score;
    }
    public void setCpuType(String type) {
        mCpu.setType(type);
    }
    @Override
    public Object clone() {
//        Object clone = null;
//        try {
//            clone = super.clone();
//            mCpu = (Cpu)mCpu.clone();
//        } catch (CloneNotSupportedException e) {
//            e.printStackTrace();
//        }
//        return clone;
        Object clone = null;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(this);

            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

            clone = objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clone;
    }
    public abstract void showInfo();
}

수정 후 출력 실행:
  {1,  1 }     , CPU:  865,   :{    =999,     =888}
  {1,  1 }     , CPU:  865,   :{    =999,     =888}

총화
원형 모델 의 실현 원 리 는 매우 간단 하 다.성능 최 적 화 를 위해 생 겨 났 기 때문에 사용 장면 도 명확 하 다. 초기 화 류 의 원가 가 캐 시 기 존 대상 의 원형 보다 높 을 때 원형 모델 을 사용 하 는 것 을 권장 한 다 는 것 이다.사용 에 있어 서 주의해 야 할 것 은 복제 대상 일 때 원래 의 구조 방법 은 실행 되 지 않 을 것 이다. 또한 클래스 의 필드 가 깊 은 복사 에 만족 하 는 지 를 고려 하고 만족 하지 않 으 면 개선 을 지원 해 야 한다.지원 방식 은 인 용 된 클래스 도 Cloneable 인 터 페 이 스 를 계승 하여 clone 방법 을 실현 하거나 serializable 인 터 페 이 스 를 사용 하여 바 이 너 리 흐름 을 읽 고 직렬 화 하 는 방식 으로 대상 의 깊 은 복 제 를 실현 할 수 있 습 니 다.
 

좋은 웹페이지 즐겨찾기