Java基础

设计模式2.7 原始模型模式

2018-11-30  本文已影响3人  卢卡斯哔哔哔

点击进入我的博客

原始模型模式通过给一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

2.7.1 原型模式结构

原型模式

这种模式涉及到三个角色:

  1. 客户(Client)角色:客户类提出创建对象的请求
  2. 抽象原型(Prototype)角色:这是一个抽象角色,此角色给出所以的具体原型类所需的接口。
  3. 具体原型(Concrete Prototype):被复制的对象。

2.7.2 原型模式细节

主要目的

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用环境
  1. 创建新对象成本较大(例如初始化时间长,占用CPU多或占太多网络资源),新对象可以通过复制已有对象来获得,如果相似对象,则可以对其成员变量稍作修改。
  2. 系统要保存对象的状态,而对象的状态很小。
  3. 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的组合状态,通过复制原型对象得到新实例可以比使用构造函数创建一个新实例更加方便。
优点
  1. 当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。
  2. 扩展性好,由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。
  3. 原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式不需要这样,圆形模式中产品的复制是通过封装在类中的克隆方法实现的,无需专门的工厂类来创建产品。
  4. 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
缺点
  1. 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
  2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

2.7.3 Java的Clone

Object.clone()

clone()方法返回的对象叫做原始对象的克隆体。一个克隆对象的基本特性必须是:

  1. a.clone()!=a,这也就意味着克隆对象和原始对象在java中是两个不同的对象。
  2. a.clone().getClass == a.getClass(),克隆对象与原对象类型相同
  3. a.clone.equals(a),也就是说克隆对象完完全全是原始对象的一个拷贝。此条件是非必需的
Cloneable接口

Object类没有实现该接口,所以用户如果没有主动实现该接口时,调用clone()方法会报错CloneNotSupportedException

Java实现步骤
  1. 实现Cloneable接口,这是步骤的关键之处。
  2. 重写clone()方法,并声明为public,因为Object的该方法是protected的。
  3. 调用super.clone()来获取新的克隆对象。在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
class A implements Cloneable {
    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

2.7.4 深复制和浅复制

浅复制
深复制
利用串行化进行深复制
    public Object deepClone() throws Exception {
        //将对象写到流里
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(this);

        //从流里读出来
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return(oi.readObject());
    }
上一篇 下一篇

猜你喜欢

热点阅读