设计模式之原型模式与深拷贝、浅拷贝

原型模式

基本概念

使用一个已经创建的对象作为原型,通过复制该对象来创建一个新的该类型的对象。Java自带原型模式,通过实现Cloneable接口实现,这种创建对象的方式比new对象的效率更高。

原型模式通常用来保存对象某一过程中的状态,以实现在必要的时候撤销对对象的更改。

此方法的缺陷:

  1. 每一个类都需要实现clone()方法,而clone()方法位于类内部,当需要对类代码进行修改时,此方法也需要修改。
  2. 当需要深克隆时,此类中的每一个引用类型对象都需要支持深克隆,实现较麻烦。

模式的实现

  1. 创建原型类,实现Cloneable接口,并重写clone()方法

    原型类的引用类型属性

    public class Member implements Cloneable{
        private int age;
        private String name;
        private double length;
    
        public Member(int age, String name, double length) {
            this.age = age;
            this.name = name;
            this.length = length;
        }
    
        @Override
        protected Member clone() throws CloneNotSupportedException {
            Member res = (Member) super.clone();
            return res;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getLength() {
            return length;
        }
    
        public void setLength(double length) {
            this.length = length;
        }
    }
    

    原型类

    public class Collection implements Cloneable {
        private Member member;
        private int id;
    
        public Collection(Member member, int id) {
            this.member = member;
            this.id = id;
        }
    
        @Override
        protected Collection clone() throws CloneNotSupportedException {
            Collection res = (Collection) super.clone();
            //res.setMember(this.getMember().clone());
            return res;
        }
    
        public Member getMember() {
            return member;
        }
    
        public void setMember(Member member) {
            this.member = member;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    }
    
  2. 使用该类的clone()方法实现克隆

    public class ProtoDemo {
        public static void main(String[] args) throws CloneNotSupportedException {
            Member zhangf = new Member(12, "张飞", 12.33);
            Collection coll = new Collection(zhangf, 1);
            Collection coll2 = (Collection) coll.clone();
    
            String str1="collect01\tid="+coll.getId()+"\t"+coll.getMember()+"\tmem="+coll;
            String str2="collect02\tid="+coll2.getId()+"\t"+coll2.getMember()+"\tmem="+coll2;
    
            System.out.println(str1);
            System.out.println(str2);
          
            System.out.println("=============");
            coll.getMember().setName("刘备");
            System.out.println("coll1`s name is "+coll.getMember().getName());
            System.out.println("coll2`s name is "+coll2.getMember().getName());
        }
    }
    

以上代码实现类浅拷贝,打印结果如下:

collect01	id=1	cn.sunyog.prototype.Member@e73f9ac	mem=cn.sunyog.prototype.Collection@61064425
collect02	id=1	cn.sunyog.prototype.Member@e73f9ac	mem=cn.sunyog.prototype.Collection@7b1d7fff
=============
coll1`s name is 刘备
coll2`s name is 刘备

可以看出,当修改了coll对象中membername属性时,coll2对象中对应的次属性也跟着被修改了。如需要实现两个对象互不影响,需要实现深拷贝,即重写Collection类的clone()方法,手动修改它的所有引用类型属性。代码如下:

@Override
protected Collection clone() throws CloneNotSupportedException {
    Collection res = (Collection) super.clone();
  	//深拷贝
    res.setMember(this.getMember().clone());
    return res;
}

以上代码修改后,打印结果如下:

collect01	id=1	cn.sunyog.prototype.Member@5e2de80c	mem=cn.sunyog.prototype.Collection@1d44bcfa
collect02	id=1	cn.sunyog.prototype.Member@266474c2	mem=cn.sunyog.prototype.Collection@6f94fa3e
=============
coll1`s name is 刘备
coll2`s name is 张飞

可见两个对象的name属性互不影响,实现了深拷贝

posted @ 2021-02-26 11:03  李三幺  阅读(95)  评论(0编辑  收藏  举报