java 原型设计模式

来源:互联网 发布:c语言教程 编辑:程序博客网 时间:2024/05/27 09:46

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,也就是用原型实例

(也就是对象因为只有对象才可以称之为实例,对象肯定有它的属性) 通过拷贝把这些属性组建成一个新的对象.


结构和说明


先写一个简单的例子感受下原型模式的基本应用:

package com.zhimore.prototype1;
/**
 * 声明一个克隆自身的接口
 * @author Adminis
 *
 */
public interface Prototype {
/**
* 克隆自身的方法
* @return 一个从自身克隆出来的对象
*/
public Prototype clone();
}

ConcretePrototype1.java 实现克隆的子类实现

package com.zhimore.prototype1;
public class ConcretePrototype1 implements Prototype {
@Override
public Prototype clone() {
//最简单的克隆,新建一个自身对象,由于没有属性,就不去复制值了
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}

Client.java 

package com.zhimore.prototype1;
public class Client {
/**
* 持有需要使用的原型接口对象
*/
private Prototype prototype;
/**
* 构造方法,传入需要使用的原型接口对象
* @param prototype 需要使用的原型接口对象
*/
public Client(Prototype prototype){
this.prototype = prototype;
}
/**
* 把传递过来的对象克隆一个新的对象
*/
public void operation(){
Prototype newPrototype = prototype.clone();
}
}

上面只是怎么为下面讲原型模式的预热而已,知道有这样的方法可以创建对象就行,下面通过一个例子来讲解一下原型模式的使用更好解决实际问题:


我们先不用模式的解决方案,然后再使用原型设计模式解决,对比下使用模式后的优点以及好处:

不用模式的解决方案:

先把订单这块有些操作行为抽象成一个接口:

IOrder.java

package com.zhimore.prototype2;
/**
 * 订单的接口
 * @author Adminis
 *
 */
public interface IOrder {
/**
* 获取订单产品数量
* @return 
*/
   public long getOrderNum();
   /**
* 设置订单产品数量
* @param num 订单产品数量
*/
   public void setOrderNum(long num);
}

PersonalOrder.java 个人订单

package com.zhimore.prototype2;
/**
 * 个人订单
 * @author Adminis
 *
 */
public class PersonalOrder implements IOrder {
/**
* 订购人员姓名
*/
private String customerName;
/**
* 产品编号
*/
private String productId;
/**
* 订单产品数量
*/
private long orderProductNum = 0;
@Override
public long getOrderNum() {
return orderProductNum;
}


@Override
public void setOrderNum(long num) {
this.orderProductNum = num;
}


public String getCustomerName() {
return customerName;
}


public void setCustomerName(String customerName) {
this.customerName = customerName;
}


public String getProductId() {
return productId;
}


public void setProductId(String productId) {
this.productId = productId;
}
public String toString(){
return "本个人订单的订购人是="+this.customerName+",订购产品是="+this.productId+",订购数量为="+this.orderProductNum;
}
}

EnterpriseOrder.java   企业订单

package com.zhimore.prototype2;


public class EnterpriseOrder implements IOrder {
/**
* 企业名称
*/
private String enterpriseName;
/**
* 产品编号
*/
private String productId;
/**
* 订单产品数量
*/
private long orderProductNum = 0;
@Override
public long getOrderNum() {
return orderProductNum;
}


@Override
public void setOrderNum(long num) {
this.orderProductNum = num;
}


public String getEnterpriseName() {
return enterpriseName;
}


public void setEnterpriseName(String enterpriseName) {
this.enterpriseName = enterpriseName;
}


public String getProductId() {
return productId;
}


public void setProductId(String productId) {
this.productId = productId;
}
public String toString(){
return "本企业订单的订购企业是="+this.enterpriseName+",订购产品是="+this.productId+",订购数量为="+this.orderProductNum;
}
}

OrderBusiness.java 处理订单的业务类

package com.zhimore.prototype2;
/**
 * 处理订单的业务对象
 * @author Adminis
 *
 */
public class OrderBusiness {
   public void saveOrder(IOrder order){
while(order.getOrderNum() > 1000){
//2:如果大于,还需要继续拆分
//2.1再新建一份订单,跟传入的订单除了数量不一样外,其他都相同
IOrder newOrder = null;

if(order instanceof PersonalOrder){
//创建相应的新的订单对象
PersonalOrder p2 = new PersonalOrder();
//然后进行赋值,但是产品数量为1000
PersonalOrder p1 = (PersonalOrder)order;
p2.setCustomerName(p1.getCustomerName());
p2.setProductId(p1.getProductId());
p2.setOrderNum(1000);
//然后再设置给newOrder
newOrder = p2;
}else if(order instanceof EnterpriseOrder){
//创建相应的订单对象
EnterpriseOrder e2 = new EnterpriseOrder();
//然后进行赋值,但是产品数量为1000
EnterpriseOrder e1 = (EnterpriseOrder)order;
e2.setEnterpriseName(e1.getEnterpriseName());
e2.setProductId(e1.getProductId());
e2.setOrderNum(1000);
//然后再设置给newOrder
newOrder = e2;
}

//2.2原来的订单保留,把数量设置成减少1000
order.setOrderNum(order.getOrderNum()-1000);

//然后是业务功能处理,省略了,打印输出,看一下
System.out.println("拆分生成订单=="+newOrder);
}

//3:不超过,那就直接业务功能处理,省略了,打印输出,看一下
System.out.println("订单=="+order);
   }
}

测试类:

package com.zhimore.prototype2;
public class Client {
public static void main(String[] args) {
//创建订单对象,这里为了演示简单,直接new了
PersonalOrder op = new PersonalOrder();
//设置订单数据
op.setOrderNum(1500);
op.setCustomerName("赵菲");
op.setProductId("0001");
//这里获取业务处理的类,也直接new了,为了简单,连业务接口都没有做
OrderBusiness ob = new OrderBusiness();
//调用业务来保存订单对象
ob.saveOrder(op);
System.out.println("--------------------");
EnterpriseOrder enterpriseOrder = new EnterpriseOrder();
enterpriseOrder.setOrderNum(2001);
enterpriseOrder.setEnterpriseName("华为");
enterpriseOrder.setProductId("0002");
ob.saveOrder(enterpriseOrder);
}
}

打印信息:

拆分生成订单==本个人订单的订购人是=赵菲,订购产品是=0001,订购数量为=1000
订单==本个人订单的订购人是=赵菲,订购产品是=0001,订购数量为=500
--------------------
拆分生成订单==本企业订单的订购企业是=华为,订购产品是=0002,订购数量为=1000
拆分生成订单==本企业订单的订购企业是=华为,订购产品是=0002,订购数量为=1000
订单==本企业订单的订购企业是=华为,订购产品是=0002,订购数量为=1

从上面不使用设计模式的解决的问题何在呢?


现在使用原型设计模式方法实现上面的需求:

结构图:


对IOrder这个接口中添加一个方法:

 /**
* 克隆方法
* @return 订单原型的实例
*/
public IOrder cloneOrder();

它的子类就变成这样:

package com.zhimore.prototype3;




/**
 * 个人订单
 * @author Adminis
 *
 */
public class PersonalOrder implements IOrder {
/**
* 订购人员姓名
*/
private String customerName;
/**
* 产品编号
*/
private String productId;
/**
* 订单产品数量
*/
private long orderProductNum = 0;
@Override
public long getOrderNum() {
return orderProductNum;
}


@Override
public void setOrderNum(long num) {
this.orderProductNum = num;
}


public String getCustomerName() {
return customerName;
}


public void setCustomerName(String customerName) {
this.customerName = customerName;
}


public String getProductId() {
return productId;
}


public void setProductId(String productId) {
this.productId = productId;
}
public String toString(){
return "本个人订单的订购人是="+this.customerName+",订购产品是="+this.productId+",订购数量为="+this.orderProductNum;
}


@Override
public IOrder cloneOrder() {
PersonalOrder personalOrder = new PersonalOrder();
personalOrder.setCustomerName(customerName);
personalOrder.setOrderNum(orderProductNum);
personalOrder.setProductId(productId);
return personalOrder;
}
}


业务类:

package com.zhimore.prototype3;




public class OrderBusiness {
/**
* 创建订单的方法
* @param order 订单的接口对象
*/
public void saveOrder(IOrder order){
//根据业务要求,当订单的预定的产品数量超过1000的时候,就需要把订单拆成两份订单
//当然如果要做好,这里的1000应该做成常量,这么做是为了演示简单

//1:判断当前的预定产品数量是否大于1000
while(order.getOrderNum() > 1000){
//2:如果大于,还需要继续拆分
//2.1再新建一份订单,跟传入的订单除了数量不一样外,其他都相同
IOrder newOrder = order.cloneOrder();
//然后进行赋值,产品数量为1000
newOrder.setOrderNum(1000);

System.out.println("old order num=="+order.getOrderNum()+" , new Order num==="+newOrder.getOrderNum());

//2.2原来的订单保留,把数量设置成减少1000
order.setOrderNum(order.getOrderNum()-1000);

//然后是业务功能处理,省略了,打印输出,看一下
System.out.println("拆分生成订单=="+newOrder);
}
//3:不超过,那就直接业务功能处理,省略了,打印输出,看一下
System.out.println("订单=="+order);
}
}

这个业务类改造就不需要依赖具体的实现了,而且扩展性也提高了,系统以后不管需要添加什么类型的订单都没问题,也不关心订单的具体实现(也就是订单中有什么方法) 业务是不是大大简化而且提高了扩展性 

通过上面的例子对原型设计模式一些基本的总结:



上面的克隆是自己写的 其实java jdk中已经帮我们实现了克隆,它是定义在Object类中,我把Object中所有定义的方法截图看下:



深度克隆和纤度克隆


现在使用java jdk中自带的克隆

我们把PersonalOrder类中复写了clone了方法

@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = null;
obj = super.clone();
return obj;
}

使用:

package com.zhimore.prototype3;
public class Client {
public static void main(String[] args) {

//先创建原型实例
PersonalOrder oa1 = new PersonalOrder();

//设置原型实例的订单数量的值
oa1.setOrderNum(100);
//为了简单,这里仅仅输出数量
System.out.println("这是第一次获取的对象实例==="+oa1.getOrderNum());

//通过克隆来获取新的实例
PersonalOrder oa2 = null;
try {
oa2 = (PersonalOrder)oa1.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//修改它的数量
oa2.setOrderNum(80);
//输出克隆出来的对象的值
System.out.println("输出克隆出来的实例==="+oa2.getOrderNum());

//再次输出原型实例的值
System.out.println("再次输出原型实例==="+oa1.getOrderNum());
}
}

打印效果:

这是第一次获取的对象实例===100
输出克隆出来的实例===80
再次输出原型实例===100

说明在克隆后改变了克隆对象的属性值 而不会影响之前对象的属性值

如果对克隆不是很熟悉的话 可以去网上找找文章写个demo就理解了,原型设计模式就讲到这里了!

0 0