前言
Prototype原型模式属于创建型模式。用原型的实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。Prototype原型模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
需求
某个客户产生一个订单,订单有产品的数量、产品的名称,公司接收订单并进入内部处理系统。
要求先保留最原始的一份数据作为存根,一个生产部门最多生产100个产品。
基本实现
订单接口IOrder:
public interface IOrder {
void setOrderNum(int num);
int getOrderNum();
void setOrderName(String name);
String getOrderName();
}
个人订单类PersonalOrder:
public class PersonnalOrder implements IOrder {
private int orderNum;
private String orderName;
@Override
public void setOrderNum(int num) {
this.orderNum = num;
}
@Override
public int getOrderNum() {
return this.orderNum;
}
@Override
public void setOrderName(String name) {
this.orderName = name;
}
@Override
public String getOrderName() {
return this.orderName;
}
}
工厂接口IOrderDealFactory:
public interface IOrderDealFactory {
void dealOrder(IOrder order);
}
订单生产工厂类OrderDealFactory:
public class OrderDealFactory implements IOrderDealFactory {
@Override
public void dealOrder(IOrder order) {
System.out.println("原始订单地址:" + order.hashCode());
PersonalOrder personalOrderStub = (PersonalOrder) order;
int orderNum = personalOrderStub.getOrderNum();
while (orderNum > 0) {
PersonalOrder personalOrder = new PersonalOrder();
personalOrder.setOrderName(personalOrderStub.getOrderName());
personalOrder.setOrderNum(orderNum > 100 ? 100 : orderNum);
orderNum -= 100;
System.out.println("生产订单:" + personalOrder.hashCode() + "," + personalOrder.getOrderName() + ", " + personalOrder.getOrderNum());
}
}
}
接下来我们来模拟一个客户订单场景类Client:
public class Client {
public static void main(String[] args) {
OrderDealFactory factory = new OrderDealFactory();
PersonalOrder personalOrder = new PersonalOrder();
personalOrder.setOrderName("个人订单");
personalOrder.setOrderNum(430);
factory.dealOrder(personalOrder);
}
}
这样,基本上需求已经完成:
原始订单地址:356573597
生产订单:1735600054,个人订单, 100
生产订单:21685669,个人订单, 100
生产订单:2133927002,个人订单, 100
生产订单:1836019240,个人订单, 100
生产订单:325040804,个人订单, 30
新增需求
这时候,又来了一个公司订单,我们可能会这样做:
新增一个公司订单类CompanyOrder:
public class CompanyOrder implements IOrder {
private int orderNum;
private String orderName;
@Override
public void setOrderNum(int num) {
this.orderNum = num;
}
@Override
public int getOrderNum() {
return this.orderNum;
}
@Override
public void setOrderName(String name) {
this.orderName = name;
}
@Override
public String getOrderName() {
return this.orderName;
}
}
有人要说了,这个CompanyOrder类和PersonalOrder除了名字不一样而已,其他都是一样啊,其实不然,我们只不过简化了具体的内容,其实两个类里面还应该存在其他的业务逻辑,只不过我们省略了而已,而这部分正是两者的不同之处。
修改OrderDealFactory类:
public class OrderDealFactory implements IOrderDealFactory {
@Override
public void dealOrder(IOrder order) {
System.out.println("原始订单地址:" + order.hashCode());
if (order instanceof PersonalOrder) {
PersonalOrder personalOrderStub = (PersonalOrder) order;
int orderNum = personalOrderStub.getOrderNum();
while (orderNum > 0) {
PersonalOrder personalOrder = new PersonalOrder();
personalOrder.setOrderName(personalOrderStub.getOrderName());
personalOrder.setOrderNum(orderNum > 100 ? 100 : orderNum);
orderNum -= 100;
System.out.println("生产订单:" + personalOrder.hashCode() + "," + personalOrder.getOrderName() + ", " + personalOrder.getOrderNum());
}
} else if (order instanceof CompanyOrder) {
CompanyOrder companyOrderStub = (CompanyOrder) order;
int orderNum = companyOrderStub.getOrderNum();
while (orderNum > 0) {
CompanyOrder companyOrder = new CompanyOrder();
companyOrder.setOrderName(companyOrderStub.getOrderName());
companyOrder.setOrderNum(orderNum > 100 ? 100 : orderNum);
orderNum -= 100;
System.out.println("生产订单:" + companyOrder.hashCode() + "," + companyOrder.getOrderName() + ", " + companyOrder.getOrderNum());
}
}
}
}
这样做,虽然能够满足需求,但是如果再来一个其他种类的订单呢?我们是不是还需要修改OrderDealFactory类,我们要知道设计模式的原则是对修改关闭,对拓展开放,而这里我们其实是违背了这个原则,那我们应该怎么做呢?接下来来看原型模式怎么去解决这个问题:
原型模式
新增一个原型复制接口Prototype :
public interface Prototype {
Prototype cloneOrder();
}
IOrder继承这个接口:
public interface IOrder extends Prototype {
void setOrderNum(int num);
int getOrderNum();
void setOrderName(String name);
String getOrderName();
}
这样PersonalOrder和CommpanyOrder就必须重写这个接口中的方法:
PersonalOrder:
public class PersonalOrder implements IOrder {
private int orderNum;
private String orderName;
@Override
public void setOrderNum(int num) {
this.orderNum = num;
}
@Override
public int getOrderNum() {
return this.orderNum;
}
@Override
public void setOrderName(String name) {
this.orderName = name;
}
@Override
public String getOrderName() {
return this.orderName;
}
@Override
public Prototype cloneOrder() {
PersonalOrder personalOrder = new PersonalOrder();
personalOrder.setOrderName(orderName);
personalOrder.setOrderNum(orderNum);
return personalOrder;
}
}
CommpanyOrder:
public class CompanyOrder implements IOrder {
private int orderNum;
private String orderName;
@Override
public void setOrderNum(int num) {
this.orderNum = num;
}
@Override
public int getOrderNum() {
return this.orderNum;
}
@Override
public void setOrderName(String name) {
this.orderName = name;
}
@Override
public String getOrderName() {
return this.orderName;
}
@Override
public Prototype cloneOrder() {
CompanyOrder companyOrder = new CompanyOrder();
companyOrder.setOrderName(orderName);
companyOrder.setOrderNum(orderNum);
return companyOrder;
}
}
此时我们的工厂类OrderDealFactory :
public class OrderDealFactory implements IOrderDealFactory {
@Override
public void dealOrder(IOrder order) {
int orderNum = order.getOrderNum();
System.out.println("原始订单地址:" + order.hashCode());
while (orderNum > 0) {
IOrder iorder = (IOrder) order.cloneOrder();
iorder.setOrderNum(orderNum > 100 ? 100 : orderNum);
orderNum -= 100;
System.out.println("生产订单:" + iorder.hashCode() + "," + iorder.getOrderName() + ", " + iorder.getOrderNum());
}
}
我们调用的时候传入PersonablOrder或者CompanyOrder,通过IOrder iorder = (IOrder) order.cloneOrder()获得该对象,这样就无需继续判断属于哪一种类型了。
这时候我们回过头来看工厂类,是不是很简单,而且以后新增不同种类的订单,也无须修改这个工厂类,只需要新增不同种类的订单类,满足了设计模式的原则。
浅拷贝和深拷贝
对于浅拷贝和深拷贝,我在此就不逐一举例了,不清楚内部工作原理的,可以查看博客设计模式之原型模式,大致可以总结如下:
浅拷贝: 对基本数据类型的成员变量进行值的复制,对引用类型的成员变量只复制引用(地址相同),不复制引用的对象(内容不同)。
深拷贝: 对基本数据类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制(地址和内容都不同)。
原型模式在Android中的应用
Intent源码就是采用的原型模式:

总结
原型模式虽然简单,但是在实际生活中还是会经常用到的,经常配合工厂模式综合应用。
喜欢本篇博客的简友们,就请来一波点赞,您的每一次关注,将成为我前进的动力,谢谢!
网友评论