java设计模式中—原型模式

原型介绍

举个栗子:大话西游里,孙悟空对战牛魔王,孙悟空拔了一个猴毛一吹,变出了一堆“孙悟空”,这些悟空是孙悟空的副本,这就是原型模式,从一个原型中复制出N个副本。

实现

通过java 提供Object 类提供的clone(克隆)方法实现的。克隆把一个类的所有成员变量,包括变量和方法都被复制到一个新的实例中。原型对象需要实现 Cloneable 接口

原型模式

  • 代码
public class WuKong implements Serializable, Cloneable{

    private String name;
    private int age;

    public void skill(){
        System.out.println("72变,火眼金睛");
    }
   	get/set...
   	
    @Override
    public String toString() {
        return "WuKong{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  • 测试
public class MainTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        WuKong wuKong = new WuKong();
        wuKong.setName("齐天大圣");
        wuKong.setAge(500);
		wuKong.skill();
		
        WuKong wuKong1 = (WuKong) wuKong.clone();
        wuKong1.skill();

        System.out.println(wuKong + " " + wuKong.hashCode());
        System.out.println(wuKong1 + " " + wuKong1.hashCode());
        System.out.println(wuKong == wuKong1);
    }
}

在这里插入图片描述
克隆产生的新的对象

原型中拷贝

以上是原型的基本实现,但是在原型对象中都是基本数据类型,没有引用类型,Object 的克隆只能进行浅拷贝,也就是不会对引用类型之心拷贝,以上原型是不完整,继续改进

浅拷贝

原型类调整下,增加一个引用对象

  • 原型类
public class WuKong implements Serializable, Cloneable{

    private String name;
    private int age;
    private GlodenCudgel glodenCudgel;

    public void skill(){
        System.out.println("72变,火眼金睛");
    }

  	get/set...
    @Override
    public String toString() {
        return "WuKong{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", glodenCudgel=" + glodenCudgel +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

  • 引用对象
public class GlodenCudgel implements Serializable, Cloneable{

    private String g_name;
    private long wget;
    
	get/set...
	
    @Override
    public String toString() {
        return "GlodenCudgel{" +
                "g_name='" + g_name + '\'' +
                ", wget=" + wget +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  • 测试浅拷贝
public class MainTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        WuKong wuKong = new WuKong();

        GlodenCudgel glodenCudgel = new GlodenCudgel();
        glodenCudgel.setG_name("如意金箍棒");
        glodenCudgel.setWget(1888);
        wuKong.setName("齐天大圣");
        wuKong.setAge(500);
        wuKong.setGlodenCudgel(glodenCudgel);
        
        WuKong wuKong1 = (WuKong) wuKong.clone();
        wuKong.skill();
        wuKong1.skill();

        System.out.println("原型:"+wuKong + " " + wuKong.hashCode()+" 金箍棒:"+wuKong.getGlodenCudgel().hashCode());
        System.out.println("克隆:"+wuKong1 + " " + wuKong1.hashCode()+" 金箍棒:"+wuKong1.getGlodenCudgel().hashCode());
        System.out.println("原型==克隆:"+(wuKong == wuKong1));
    }
}

在这里插入图片描述
原型方法与复制类引种对象hashcode 相同,是同一对象,修改原型中引用对象会修改克隆对象,显然不是我们所希望的,证明了 Clone 是浅拷贝,如何实现深拷贝,两种方式

深拷贝

使用clone 方式

在原型中重写clone 方法,主要是在克隆中对引应用类型进行重新赋值,其他不变


@Override
   protected Object clone() throws CloneNotSupportedException {
       WuKong wuKong = (WuKong) super.clone();
       glodenCudgel = (GlodenCudgel)getGlodenCudgel().clone();
       return wuKong;
   }

重新执行测试方法,实现了深拷贝
在这里插入图片描述
通过克隆方式实现深拷贝,有弊端,如果有多个引用,需要每个引用类型都需要重新赋值,比较麻烦。另外原型模式需要实现 Cloneable 接口,违背了OCP 原则。

序列化方式

修改原形类,clone 方法不需要,添加一个深度拷贝方法, 其他方法属性保持不变


 public Object deepCopy() {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;

        try {
            //序列化
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            //反序列化
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Object o = objectInputStream.readObject();

            return o;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                byteArrayInputStream.close();
                objectInputStream.close();
                byteArrayOutputStream.close();
                objectOutputStream.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return null;
    }
  • 运行测试
    序列化深度拷贝测试结果

总结

原型模式涉及到深拷贝和浅拷贝,尤其是使用到引用类型时,建议使用深度拷贝,深度拷贝使用序列化方式比较简单,推荐使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值