原型模式(Prototype Pattern)

原型模式(Prototype Pattern)

1.模式动机

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

2.模式定义

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。

3.模式结构

原型模式包含以下主要角色。

  1. 抽象原型类(Prototype):规定了具体原型对象必须实现的接口。
  2. 具体原型类(Button):实现抽象原型类的 clone() 方法,它是可被复制的对象。
  3. PrototypeRegistry:使用具体原型类中的 clone() 方法来复制新的对象。

4.代码分析

//具体原型类
class Button implements Cloneable
{
    Button()
    {
        System.out.println("Button原型创建成功!");
    }
    public Object clone() throws CloneNotSupportedException
    {
        System.out.println("Button原型复制成功!");
        return (Button) super.clone();
    }
}
//原型模式的测试类
public class PrototypeRegistry
{
    public static void main(String[] args)throws CloneNotSupportedException
    {
        Button obj1 = new Button();
        Button obj2 = (Button) obj1.clone();
        System.out.println("obj1==obj2?"+(obj1==obj2));
    }
}
具体原型创建成功!
具体原型复制成功!
obj1==obj2?false

5.模式分析

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

主要解决:在运行期建立和删除原型。

何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

6.实例

同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,属于相似对象的复制,同样可以用原型模式创建,然后再做简单修改就可以了。

7.优缺点

优点:
  • Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
缺点:
  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
适用环境:
  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
  • 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

Spring 中,原型模式应用的非常广泛,例如 scope='prototype'、JSON.parseObject() 等都是原型模式的具体应用。

8.模式扩展

深克隆和潜克隆

克隆可以分为深克隆浅克隆,本例中邮件的附件就是浅克隆。由于该原型模式使用的是浅克隆,因此附件其实是同一个附件,如果修改克隆中的附件,远邮件中附件也会改变,如果有需要,应当将其深克隆

浅克隆

在浅克隆中,被复制的对象所有的普通成员变量(值对象)都具有与原来的对象相同的值,而所有的对其他对象的引用(引用对象)仍然指向原来的对象。简单来说,浅克隆仅仅复制对象的值成员,而引用成员只复制引用,复制出来的引用对象还是指向相同的对象。大部分语言如C#,JAVA都有很好的支持。无需自己编写代码。

深克隆

深克隆不仅复制对象的值成员,对象包含的引用也被复制。深克隆可能需要编写复杂的代码,可以使用序列化对象的方式实现深克隆。

posted @ 2020-11-24 15:43  SSunSShine  阅读(87)  评论(0编辑  收藏  举报