设计模式之原型模式

一、引例

原型模式是GoF23种设计模式的一种,属于创建型模式,用来解决复杂对象的创建问题。《西游记》中,孙悟空拔毛变小猴的故事几乎人人皆知,孙悟空可以用猴毛根据自己的形象,复制出很多个根自己长得一模一样的“身外身”来。我们在使用电脑的时候,对文件最常用的操作有两种,一种是复制,另一种是粘贴,这就是原型模式的应用。在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。

二、定义

原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

Specify the kind of objects to create using a prototypical instance,and create new objects by copying this prototype

原型模式的基本工作原理是通过将一个原型对象传给那个发动创建的对象,这个要发动创建的对象通过请求原型对象复制原型来实现创建过程。

三、结构

在这里插入图片描述
1.Prototype(抽象原型类)
抽象原型类是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口。
2.ConcretePrototype(具体原型类)
具体原型类实现具体的克隆方法,在克隆方法中返回自己的一个克隆对象。
3.Client(客户类)
客户类让一个原型克隆自身,从而创建一个新的对象。在客户类中只需要直接实例化或通过工厂方法等方式创建一个对象,再通过调用该对象的克隆方法复制得到多个相同的对象。
Java语言为原型模式提供了天然的支持,Java的API中定义了一个Cloneable接口,这个接口是一个标识接口,是一个空的接口,表示实现了这个接口的Java类支持复制。
如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常。
浅克隆
在浅克隆中,被复制的对象的所有普通成员变量都具有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅克隆仅仅复制所考虑的对象,而不复制它所引用的成员对象,也就是其中的成员对象并不复制。在浅克隆中,当对象被复制时它所包含的成员对象却没有被复制。
在对象复制的时候,只关注被复制的对象,将被复制的对象复制一份存放在堆内存中,新对象的引用指向新创建的对象,但是该对象的成员变量的引用还是指向原来的对象所指向的引用。
深克隆
在深克隆中,被复制对象的所有普通成员变量也都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深克隆把要复制的对象所引用的对象都复制了一遍。在深克隆中,除了对象本身被复制外,对象包含的引用也被复制,也就是其中的成员变量也将被复制。
在对象复制的时候,不仅关注被复制的对象,将被复制的对象的成员变量也复制一份,新创建的对象的成员变量指向新复制的对象。

四、效果与应用

优缺点

优点
1.当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。
2.可以动态增加或减少产品类。由于创建产品类实例的方法是产品类(具体原型类)内部具有的,因此增加新产品对整个结构没有影响。在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。
3.原型模式提供了简化的创建结构。工厂方法模式常常需要有一个与产品类等级结构相同的等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的clone()方法实现的,无须专门的工厂类来创建产品。
4.可以使用深克隆的方式保存对象的状态。使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态)。
缺点
1.需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事情,必须修改其源代码,违背了“开闭原则”。
2.在实现深克隆时需要编写较为复杂的代码。

适应环境

1.创建新对象成本较大(如初始化需要占用较长的时间,占用CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其属性稍作修改。
2.如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。
3.需要避免使用分层次的工厂类,来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

应用

1.原型模式应用于很多软件中,如果每次创建一个对象要花大量时间,原型模式是最好的解决方案。
2.Struts是常用的Java EE框架之一,在Struts2中为了保证线程的安全性,Action对象的创建使用了原型模式。
3.在主流的Java EE框架Spring中,用户也可以采用原型模式来创建新的bean实例,从而实现每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响。

五、扩展

带原型管理器的原型模式

原型管理器(Prototype Manager)角色创建具体原型类的对象,并记录每个被创建的对象。原型管理器的作用与工厂类似,其中定义了一个集合用于存储原型对象,如果需要某个对象的一个克隆,可以通过复制集合中对应的原型对象来获得。在原型管理器中针对抽象原型类进行编程,以便扩展。

import java.util.*;
public interface MyColor extends Cloneable {
	public Object clone();
	public void display();
}
public class Red implements MyColor {
	public Object clone() {
		Red r = null;
		try {
			r = (Red)super.clone();
		} catch(ClassNotSupportedException e) {
			
		}
		return r;
	}
	
	public void display() {
		System.out.println("This is Red!");
	}
}
public class Blue implements MyColor {
	public Object clone() {
		Blue b = null;
		try {
			b = (Blue)super.clone();
		} catch(ClassNotSupportedException e) {
			
		}
		return b;
	}
	
	public void display() {
		System.out.println("This is Blue!");
	}
}
import java.util.*;
public class PrototypeManager {
	private Hashtable ht = new Hashtable();
	
	public PrototypeManager() {
		ht.put("red", new Red());
		ht.put("blue", new Blue());
	}
	
	public void addColor(String key, MyColor obj) {
		ht.put(key, obj);
	}
	public MyColor getColor(String key) {
		return (MyColor)((MyColor)ht.get(key)).clone();
	}
}

在PrototypeManager中定义了一个Hashtable类型的集合,使用“键值对”来存储原型对象,客户端可以通过Key来获取对应原型对象的克隆对象。PrototypeManager类提供了工厂方法,用于返回一个克隆对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值