设计模式(五)原型模式

一 . 模式动机

  • 在软件系统中,有些对象的创建过程比较复杂,而且需要频繁创建,消耗资源多,原型模式就是通过给出一个原型对象来指明要创建对象的类型,然后复制这个原型对象,创建更多这个类型的对象,就相当于给一个原物品,然后复制很多此物品,这样来降低创建多个同种复杂对象的资源。

二 . 定义

  • 原型模式(Prototype Pattern):是一种对象型创建模式,用原型实列指定要克隆的对象的类型,通过克隆原型对象创建新的对象。原型模式允许一个对象再创建另一个可定制的对象,无需知道任何创建的细节。

三 . 模式结构

在这里插入图片描述
(图片来源于网络)

Prototype:抽象原型类
ConcretePrototype:具体原型类

四 . 模式分析

  • 这个模式的结构非常简单,最主要的是这个clone()方法,怎么去实现克隆一个对象。实现这个方法也很简单,因为java中所有的类都继承自java.lang.Object,而Object类提供了一个clone()方法。
  • 要适用clone()方法必须实现一个标识接口Cloneable空接口(接口里面没有方法),表示这个java类支持复制。如果没有实现这个接口就调用了clone(),java编译器就会抛出一个CloneNotSupportedException异常。
  • 克隆模式还可以分为浅克隆和深克隆,浅克隆是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深克隆不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
  • 浅克隆
    在这里插入图片描述
  • 深克隆
    在这里插入图片描述

五 . 实例

import java.io.*;

//原型类必须实现Cloneable接口
public class Sheep implements Cloneable,Serializable {
    String name;
    int age;
    Sheep sheep;

    public void setSheep(Sheep sheep) {
        this.sheep = sheep;
    }

    public Sheep getSheep() {
        return sheep;
    }

    public Sheep(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //通过调用Object的clone()方法返回一个克隆对象
    public Object clone() throws CloneNotSupportedException {
        Object object = super.clone();
        return object;
    }

    public String display() {
        return (this.name+this.age+"   引用对象属性:"+this.getSheep().name+this.getSheep().age);
    }
}
class Client{
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Sheep s = new Sheep("羊",12);
        Sheep sheep = new Sheep("多利",8);
        sheep.setSheep(s);
        //sheep1是浅克隆
        //通过调用sheep这个原型对象的clone()方法克隆一个sheep1
        Sheep sheep1 =(Sheep) sheep.clone();
        //通过序列化反序列化深克隆出sheep2

        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(sheep);
        ByteArrayInputStream bio = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bio);
        Sheep sheep2 = (Sheep) ois.readObject();
		System.out.println("判断原型的引用对象和浅克隆的引用对象是否是同一个对象");
        System.out.println(sheep1.getSheep()==sheep.getSheep());
        System.out.println("判断原型的引用对象和深克隆的引用对象是否是同一个对象");
        System.out.println(sheep2.getSheep()==sheep.getSheep());
        System.out.println("原型"+sheep.display()+"\n"+"浅克隆"+sheep1.display()+"\n"+"深克隆"+sheep2.display()+"\n");
        //这里改变原型对象的引用属性的属性和基本属性,基本属性不会变,深克隆的引用属性的属性不会变
        sheep.getSheep().name = "小肥羊";
        sheep.age = 19;
        System.out.println("原型"+sheep.display()+"\n"+"浅克隆"+sheep1.display()+"\n"+"深克隆"+sheep2.display());

    }
}
  • 运行结果
E:\Java\jdk1.8.0_171\bin\java.exe "-javaagent:E:\idea\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar=60831:E:\idea\IntelliJ IDEA 2019.1.3\bin" -Dfile.encoding=UTF-8 -classpath "E:\Java\jdk1.8.0_171\jre\lib\charsets.jar;E:\Java\jdk1.8.0_171\jre\lib\deploy.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;E:\Java\jdk1.8.0_171\jre\lib\javaws.jar;E:\Java\jdk1.8.0_171\jre\lib\jce.jar;E:\Java\jdk1.8.0_171\jre\lib\jfr.jar;E:\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;E:\Java\jdk1.8.0_171\jre\lib\jsse.jar;E:\Java\jdk1.8.0_171\jre\lib\management-agent.jar;E:\Java\jdk1.8.0_171\jre\lib\plugin.jar;E:\Java\jdk1.8.0_171\jre\lib\resources.jar;E:\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Design pattern\out\production\Design pattern" Prototype原型模式.Client
判断原型的引用对象和浅克隆的引用对象是否是同一个对象
true
判断原型的引用对象和深克隆的引用对象是否是同一个对象
false
原型多利8   引用对象属性:羊12
浅克隆多利8   引用对象属性:羊12
深克隆多利8   引用对象属性:羊12

原型多利19   引用对象属性:小肥羊12
浅克隆多利8   引用对象属性:小肥羊12
深克隆多利8   引用对象属性:羊12

Process finished with exit code 0
  • 结果分析:可以看到,浅克隆的引用对象与原型的引用对象为同一个对象,而与深克隆则不是同一个对象,深克隆出来的对象的引用对象是一个新的对象,我们改变了原型多利的基础属性age=19但浅克隆和深克隆的age属性都没有改变,但改变引用对象的属性后,浅克隆和原型的引用对象其实是同一个,因此也会改变,而深克隆的类的引用对象则完全是一个新的对象,不会改变

六 . 模式优缺点

  • 优点:当创建对象实例比较复杂是,原型模式可以简化对象的创建过程,提高效率。可以保存对象状态。
  • 缺点:需要为每个类配备一个克隆方法,而且克隆方法需要对类的功能进行通盘考虑,对全新类不是很难,但对已有类进行改造是,必须修改其源代码,违背了“开闭原则”。

七 . 适用环境

  • 创建新对象成本较大时。
    个类配备一个克隆方法,而且克隆方法需要对类的功能进行通盘考虑,对全新类不是很难,但对已有类进行改造是,必须修改其源代码,违背了“开闭原则”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值