原型模式的定义:
用原型实例指定要创建的对象类型,通过复制这个实例创建新的对象
举一个例子(研磨设计模式中的例子)
例如现在有一个订单处理系统,接受订单对象,每个订单对象遵循相应的订单协议,即实现订单接口。
对于订单处理系统,只能接受订单数量小于1000的订单对象,如果订单对象的订单数量大于1000,则将该订单对象拆分成多个相同的订单对象
public interface OrderApi{
//定义一些列订单操作,如订单数,订单放,日期等
}
public class PersonalOrder implements OrderApi{
//私人订单
}
public class EnterpriseOrder implements OrderApi{
//企业订单
}
public class OrderBusiness{
public void saveOrder(OrderApi order){
//业务需求,如果订单对象的订单数大于1000,要拆分成多个订单对象,每个订单对象的订单数不大于1000
//1.判断订单对象的订单数是否大于1000
while(order.orderNumber>1000){
//如果订单数大于1000,拆分
OrderApi newOrder = null;
if(order instanceof PersonalOrder){
PersonalOrder p2 = new PersonalOrder();
personalOrder p1 = (PersonalOrder)order;
p2.setParamaters(p1.getParameters);
p2.setOrderNumber(1000);
newOrder = p2;
}
if(order instanceof EnterpriseOrder){
//与上面类似
}
//2.保存或处理新拆分元对象得到的新对象
save(newOrder);
order.setOrderNumber(order.orderNumber-1000);
}
//3.原订单对象的订单数已小于1000 可以直接处理保存。
save(order);
}
}
以上实现中,由于订单处理系统只接受订单接口,并不关心订单具体的实现,所以在拆分时,创建新的订单对象遇到麻烦,以上的
解决办法是通过instanceof判断订单类型。这样对于订单处理系统就必须知道所有的订单实现,也就是说订单处理系统和订单对象是
耦合在一起的,如果重新定义一个订单对象,势必重新改写订单处理系统的代码,即多加一个instanceof判断。
我们希望的实现是订单处理系统不关心订单对象有多少种实现,或者说我们的订单处理系统和订单是独立的,互不牵制。只要订单对象
实现订单接口,我们都能够对订单对象进行必要的处理如拆分和保存。如上代码,我们不用去判断订单对象到底属于何种类型。
原型模式可以解决此类问题。
在以上问题中,如果要拆分订单,得到新的订单对象,但并不知道订单对象的类型,如果使用原型模式,不必去判断订单类型,而是使用
复制,通过复制原型创建新的对象。通俗的讲,订单处理系统得到一个订单对象,发现他的订单数大于1000,需要拆分,复制原订单对象,
修改原订单对象和复制得到的对象的订单数。订单处理系统只知道原订单和复制对象都是接口类型。这样一来,不管新建多少个新的订单
对象,都不会影响订单系统的实现,实现了订单处理系统和订单对象的解耦合。
实现
public class PersonalOrder implements OrderApi{
//私人订单
//设置各种属性的方法
//提供复制方法
public OrderApi cloneOrder(){
PersonalOrder order = new PersonalOrder();
order.setParameters(this.parameters);
return order;
}
}
public class EnterpriseOrder implements OrderApi{
//与PersonalOrder类似
}
public class OrderBusiness{
public void saveOrder(OrderApi order){
while(order.orderNumber > 1000){
OrderApi newOrder = order.cloneOrder();
newOrder.setOrderNumber(1000);
order.setOrderNumber(order.orderNumber-1000);
save(newOrder);
}
save(order);
}
}
java中提供了clone()方法,只要类继承Cloneable接口,这个接口是一个标识接口,和序列化接口一样。复写其中的clone()方法即可
public Object clone(){
Object obj = null;
try{
obj = super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return obj;
}
不过复写的clone()方法返回Object类,在调用是还要在强制类型转换。
java中对于clone区分为深度克隆和浅度克隆
浅度克隆之是克隆按值传递的数据,如果某属性是引用类型,克隆无法完成引用类型的克隆,而只是复制引用,原对象和克隆对象
的引用共享同一个内存。(我的理解)
而深度克隆不仅克隆按值传递的数据,即使对于引用类型,要求该引用类型也必须实现cloneable接口,在深度克隆时,调用该
引用对象的clone方法克隆一个引用类型属性,如果该引用对象的属性仍然有引用类型,继续要求给引用类型实现Cloneable接口并
完成克隆,是一种递归克隆的过程,克隆出的对象和原对象的引用类型指向不同的内存,是两个不同的变量。
基于对象的克隆原型模式,实际上可以维护一个原型管理器,用于创建对象。
例如有一个原型接口:
public interface Prototype{//原型接口
//原型方法:如setName setID getName
public Prototype clone();
}
public class ConcretePrototype1 implements Prototype{//原型类
//属性和方法定义
public Prototype clone(){
ConcretePrototype1 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
public class ConcretePrototype2 implements Prototype{
//属性和方法定义
public Prototype clone(){
ConcretePrototype2 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
public class ConcretePrototype4 implements Prototype{
//属性和方法定义
public Prototype clone(){
ConcretePrototype3 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
...
public class PrototypeManager{
private static Map map = new HashMap();
private PrototypeManager(){};//私有构造方法
public synchronized static void regeistPrototye(String prototypeID,Prototype prototype){
map.put(prototypeID,prototype);
}
public synchronized static void removePrototype(String prototypeID){
map.remove(prototypeID);
}
public synchronized static Prototype getPrototype(String prototypeID) throws Exception{
Prototype p = map.get(prototypeID);
if(p == null){
throw new Exception("此原型未注册")
}
return p;
}
}
从原型管理器可以看出,原型模式应该是属于一种创建型的设计模式。
举一个例子(研磨设计模式中的例子)
例如现在有一个订单处理系统,接受订单对象,每个订单对象遵循相应的订单协议,即实现订单接口。
对于订单处理系统,只能接受订单数量小于1000的订单对象,如果订单对象的订单数量大于1000,则将该订单对象拆分成多个相同的订单对象
public interface OrderApi{
//定义一些列订单操作,如订单数,订单放,日期等
}
public class PersonalOrder implements OrderApi{
//私人订单
}
public class EnterpriseOrder implements OrderApi{
//企业订单
}
public class OrderBusiness{
public void saveOrder(OrderApi order){
//业务需求,如果订单对象的订单数大于1000,要拆分成多个订单对象,每个订单对象的订单数不大于1000
//1.判断订单对象的订单数是否大于1000
while(order.orderNumber>1000){
//如果订单数大于1000,拆分
OrderApi newOrder = null;
if(order instanceof PersonalOrder){
PersonalOrder p2 = new PersonalOrder();
personalOrder p1 = (PersonalOrder)order;
p2.setParamaters(p1.getParameters);
p2.setOrderNumber(1000);
newOrder = p2;
}
if(order instanceof EnterpriseOrder){
//与上面类似
}
//2.保存或处理新拆分元对象得到的新对象
save(newOrder);
order.setOrderNumber(order.orderNumber-1000);
}
//3.原订单对象的订单数已小于1000 可以直接处理保存。
save(order);
}
}
以上实现中,由于订单处理系统只接受订单接口,并不关心订单具体的实现,所以在拆分时,创建新的订单对象遇到麻烦,以上的
解决办法是通过instanceof判断订单类型。这样对于订单处理系统就必须知道所有的订单实现,也就是说订单处理系统和订单对象是
耦合在一起的,如果重新定义一个订单对象,势必重新改写订单处理系统的代码,即多加一个instanceof判断。
我们希望的实现是订单处理系统不关心订单对象有多少种实现,或者说我们的订单处理系统和订单是独立的,互不牵制。只要订单对象
实现订单接口,我们都能够对订单对象进行必要的处理如拆分和保存。如上代码,我们不用去判断订单对象到底属于何种类型。
原型模式可以解决此类问题。
在以上问题中,如果要拆分订单,得到新的订单对象,但并不知道订单对象的类型,如果使用原型模式,不必去判断订单类型,而是使用
复制,通过复制原型创建新的对象。通俗的讲,订单处理系统得到一个订单对象,发现他的订单数大于1000,需要拆分,复制原订单对象,
修改原订单对象和复制得到的对象的订单数。订单处理系统只知道原订单和复制对象都是接口类型。这样一来,不管新建多少个新的订单
对象,都不会影响订单系统的实现,实现了订单处理系统和订单对象的解耦合。
实现
public class PersonalOrder implements OrderApi{
//私人订单
//设置各种属性的方法
//提供复制方法
public OrderApi cloneOrder(){
PersonalOrder order = new PersonalOrder();
order.setParameters(this.parameters);
return order;
}
}
public class EnterpriseOrder implements OrderApi{
//与PersonalOrder类似
}
public class OrderBusiness{
public void saveOrder(OrderApi order){
while(order.orderNumber > 1000){
OrderApi newOrder = order.cloneOrder();
newOrder.setOrderNumber(1000);
order.setOrderNumber(order.orderNumber-1000);
save(newOrder);
}
save(order);
}
}
java中提供了clone()方法,只要类继承Cloneable接口,这个接口是一个标识接口,和序列化接口一样。复写其中的clone()方法即可
public Object clone(){
Object obj = null;
try{
obj = super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return obj;
}
不过复写的clone()方法返回Object类,在调用是还要在强制类型转换。
java中对于clone区分为深度克隆和浅度克隆
浅度克隆之是克隆按值传递的数据,如果某属性是引用类型,克隆无法完成引用类型的克隆,而只是复制引用,原对象和克隆对象
的引用共享同一个内存。(我的理解)
而深度克隆不仅克隆按值传递的数据,即使对于引用类型,要求该引用类型也必须实现cloneable接口,在深度克隆时,调用该
引用对象的clone方法克隆一个引用类型属性,如果该引用对象的属性仍然有引用类型,继续要求给引用类型实现Cloneable接口并
完成克隆,是一种递归克隆的过程,克隆出的对象和原对象的引用类型指向不同的内存,是两个不同的变量。
基于对象的克隆原型模式,实际上可以维护一个原型管理器,用于创建对象。
例如有一个原型接口:
public interface Prototype{//原型接口
//原型方法:如setName setID getName
public Prototype clone();
}
public class ConcretePrototype1 implements Prototype{//原型类
//属性和方法定义
public Prototype clone(){
ConcretePrototype1 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
public class ConcretePrototype2 implements Prototype{
//属性和方法定义
public Prototype clone(){
ConcretePrototype2 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
public class ConcretePrototype4 implements Prototype{
//属性和方法定义
public Prototype clone(){
ConcretePrototype3 prototype = new Concretetype1();
prototype.setName();
return prototype;
}
}
...
public class PrototypeManager{
private static Map map = new HashMap();
private PrototypeManager(){};//私有构造方法
public synchronized static void regeistPrototye(String prototypeID,Prototype prototype){
map.put(prototypeID,prototype);
}
public synchronized static void removePrototype(String prototypeID){
map.remove(prototypeID);
}
public synchronized static Prototype getPrototype(String prototypeID) throws Exception{
Prototype p = map.get(prototypeID);
if(p == null){
throw new Exception("此原型未注册")
}
return p;
}
}
从原型管理器可以看出,原型模式应该是属于一种创建型的设计模式。