java clone方法_[JAVA设计模式]-04-原型模式

Java中常见的设计模式

Java 中的 23 种设计模式:

Factory(工厂模式)、Builder(建造模式)、Factory Method (工厂方法模式)、
Prototype(原始模型模式)、Singleton(单例模式)、Facade(门面模式)、
Adapter(适配器模式)、Bridge(桥梁模式)、 Composite(合成 模式)、
Decorator(装饰模式)、Flyweight(享元模式)、Proxy(代理模式)、
Command(命令模式)、 Interpreter(解释器模式)、Visitor(访问者模式)、
Iterator(迭代子模式)、 Mediator(调停者模式)、Memento(备忘录模式)、
Observer(观察者模式)、State(状态模式)、Strategy(策略模式)、 
Template Method(模板方法模式)、Chain Of Responsibleity(责任链模式) 

IO 流使用的是装饰者模式、按钮监听观察者模式、forEach 遍历 List TreeSet 使用策略模式

原型模式

原型模式属于对象创建模式,GOF 给它的定义为:用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象。

在 Java 中提供了 clone()方法来实现对象的克隆,所以 Prototype 模式实现变得简单许 多。

使用克隆方式来创建对象与同样用来创建对象的工厂模式有什么不同?前面已经提过 工厂模式对新产品的适应能力比较弱:创建新的产品时,就必须修改或者增加工厂角色。而 且为了创建产品对象要先额外的创建一个工厂对象

原型模式结构:

  1. 客户角色:让一个原型克隆自己来得到一个新对象。
  2. 抽象原型角色:实现了自己的 clone 方法,扮演这种角色的类通常是抽象类,且它具有 许多具体的子类。
  3. 具体原型角色:被复制的对象,为抽象原型角色的具体子类。

类图如下:

fe3813f7f5d505e9fe2d04c728c8732e.png

按照定义客户角色不仅要负责使用对象,而且还要负责对象原型的生成和克隆。这样造 成客户角色分工就不是很明确,所以我们把对象原型生成和克隆功能单拿出来放到一个原型 管理器中。原型管理器维护了已有原型的清单。客户在使用时会向原型管理器发出请求,而 且可以修改原型管理器维护的清单。这样客户不需要编码就可以实现系统的扩展。

1cf2c312c107a2c6f426ae7aaa43f56a.png

对于抽象原型角色和具体原型角色,它们就是一个继承或者实现关系,没有什么好讲的, 记住实现好 clone 方法就好了。那么客户是怎么来使用这些角色的对象的呢?

//先 new 一个具体原型角色作为样本 

当然这只是简单的表述原型模式的运行过程。实际运用中,客户程序与原型角色之间往 往存在一个原型管理器(例子见下)。因此创建原型角色、拷贝原型角色就与客户程序分离 开来。这时才能真正的体会到原型模式带给我们的效果。

//使用原型管理器后,客户获得对象的方式

Prototype 

上面提到的原型管理器的实现,简单来说就是对原型清单的维护。可以考虑一下几点: 要保存一个原型对象的清单,我们可以使用一个 HashMap 来实现,使原型对象和它的名字 相对应;原型管理器只需要一个就够了,所以可以使用单例模式来实现控制;实现得到、注 册、删除原型对象的功能只是对 HashMap 的对应操作而已。

public 

这样当客户自定义新的产品对象时,同时向原型管理器注册一个原型对象,而使用的类 只需要根据客户的需要来从原型管理器中得到一个对象就可以了。这样就使得功能扩展变得 容易些。

原型模式与其它创建型模式有着相同的特点:它们都将具体产品的创建过程进行包装, 使得客户对创建不可知。就像上面例子中一样,客户程序仅仅知道一个抽象产品的接口。当 然它还有过人之处:

通过增加或者删除原型管理器中注册的对象,可以比其它创建型模式更方便的在运行时 增加或者删除产品。 如果一个对象的创建总是由几种固定组件不同方式组合而成;如果对象之间仅仅实例属性不同。将不同情况的对象缓存起来,直接克隆使用。也许这比采用传递参数重新 new 一 个对象要来的快一些。

你也许已经发现原型模式与工厂模式有着千丝万缕的联系:原型管理器不就是一个工厂 么。当然这个工厂经过了改进(例如上例采用了 java 的反射机制),去掉了像抽象工厂模式 或者工厂方法模式那样繁多的子类。因此可以说原型模式就是在工厂模式的基础上加入了克 隆方法。

原型模式使用 clone 能够动态的抽取当前对象运行时的状态并且克隆到新的对象中,新 对象就可以在此基础上进行操作而不损坏原有对象;而 new 只能得到一个刚初始化的对象, 而在实际应用中,这往往是不够的。 特别当你的系统需要良好的扩展性时,在设计中使用原型模式也是很必要的。比如说, 你的系统可以让客户自定义自己需要的类别,但是这种类别的初始化可能需要传递多于已有 类别的参数,而这使得用它的类将不知道怎么来初始化它(因为已经写死了),除非对类进 行修改。 可见 clone 方法是不能使用构造函数来代替的。

分析了这么多了,举一个使用原型模式较为经典的例子:绩效考核软件要对今年的各种 考核数据进行年度分析,而这一组数据是存放在数据库中的。一般我们会将这一组数据封装 在一个类中,然后将此类的一个实例作为参数传入分析算法中进行分析,得到的分析结果返 回到类中相应的变量中。假设我们决定对这组数据还要做另外一种分析以对分析结果进行比 较评定。这时对封装有这组数据的类进行 clone 要比再次连接数据库得到数据好的多。 任何模式都是存在缺陷的。原型模式主要的缺陷就是每个原型必须含有 clone 方法,在 已有类的基础上来添加 clone 操作是比较困难的;而且当内部包括一些不支持 copy 或者循 环引用的对象时,实现就更加困难了。

由于clone方法在java实现中有着一定的弊端和风险,所以clone方法是不建议使用的。 因此很少能在 java 应用中看到原型模式的使用。但是原型模式还是能够给我们一些启迪。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值