我学设计模式 之 原型模型模式

我学设计模式之原型模式

 

1.  简介

原型模式属于对象的创建模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的创建办法创建出更多同类型的对象。

不通过new来创建对象而是通过拷贝来创建对象的模式就叫做原型模式。

2.  原型模式的结构

原型模式有两种表现形式:第一种是简单形式,第二种是登记形式。这两种表现形式仅仅是原始模型模式的不同实现。

 

       2.1简单形式的原始模型模式的类图如下:

      

       这种形式设计3个角色:

       客户角色:客户类提出创建对象的请求。

       抽象原型:这是一个抽象角色,通常使用接口或抽象类实现。此角色给出所有具体原型类所需的接口。

       具体原型:被复制的对象。此角色需要实现抽象角色所提供的方法。

 

       下面用Java给出实现的源代码:

       抽象原型代码:

package com.zsw.prototype;

public interface Prototype extends Cloneable {

    public Prototype clone();

 

    public void setName(String name);

    public String getName();

}

 

 

       具体原型代码:

package com.zsw.prototype;

 

public class ConcretePrototype implements Prototype {

    private String name;

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Prototype clone(){

       try {

           return (Prototype) super.clone();

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

           return null;

       }

    }

}

       客户端原型代码:

package com.zsw.prototype;

public class Client {

    public static void main(String[] args) {

       Prototype prototype = new ConcretePrototype();

       prototype.setName("shangwu");

       Prototype p = prototype.clone();

       System.out.println(prototype == p);

       System.out.println(prototype.getName());

       System.out.println(p.getName());

    }

}

 

2.2登记形式的原始模型模式:

此种形式原始模型模式的类图如下:

作为原始模型模式的第二种形式,它有如下角色:

客户端角色:客户端向管理员提出创建对象的请求。

抽象原型角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有具体原型类所需的接口。

具体原型角色:被复制的对象,需要实现抽象原型角色定义的方法。

原型管理器角色:创建具体原型类的对象,并记录每一个被创建的对象。

 

3.  原型模式的实现:深复制和浅赋值

复制或克隆有两种方式。这两种方式分别叫做浅复制(浅克隆)和深复制(深克隆)。

被复制对象的所有变量都含有与原来的对象相同的值,而所有对其他对象的引用仍然指向原来的对象。

浅复制仅仅复制所考虑对象,而不复制他所引用的对象。

 

深复制要复制的对象所引用的对象都复制一遍,而这种对被引用到的对象的复制叫做间接复制。

 

3.1 复制简历来实现浅复制

给出Java实现代码如下:

抽象原型角色:

此角色为Java中的Cloneable接口

具体原型类型:

package com.zsw.prototype.resume;

public class Resume implements Cloneable {

    private String name;

    private String sex;

    private int age;

    private WorkExperience work;

   

    public Resume(String name){

       this.name = name;

       work = new WorkExperience();

    }

   

    //设置个人信息

    public void setPersonalInfo(String sex,int age){

       this.sex = sex;

       this.age = age;

    }

   

    //设置工作经历

    public void setWorkExperience(String workDate,String company){

       work.setWorkDate(workDate);

       work.setCompany(company);

    }

   

    public void display(){

       System.out.println("姓名:"+name+"性别:"+sex+"年龄:" + age);

       System.out.println("工作日期:"+work.getWorkDate()+"工作公司:"+work.getCompany());

    }

   

    public Object clone(){

       try {

           return super.clone();

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

           return null;

       }

    }

}

 

工作经历代码:

package com.zsw.prototype.resume;

 

public class WorkExperience {

    private String workDate;

 

    private String company;

    public String getCompany() {

       return company;

    }

 

    public void setCompany(String company) {

       this.company = company;

    }

 

    public String getWorkDate() {

       return workDate;

    }

 

    public void setWorkDate(String workDate) {

       this.workDate = workDate;

    }

}

客户端:

package com.zsw.prototype.resume;

 

public class Client {

 

    public static void main(String[] args) {

       Resume a = new Resume("大鸟");

       a.setPersonalInfo("",29);

       a.setWorkExperience("1998-2000", "XXXX-公司");

      

       Resume b = (Resume)a.clone();

       b.setWorkExperience("1998 - 2006", "YY企业");

      

       Resume c = (Resume)a.clone();

       c.setWorkExperience("1998-2003", "ZZ企业");

      

       a.display();

       b.display();

       c.display();

    }

}

输出结果:

姓名:大鸟性别:男年龄:29

工作日期:1998-2003工作公司:ZZ企业

姓名:大鸟性别:男年龄:29

工作日期:1998-2003工作公司:ZZ

姓名:大鸟性别:男年龄:29

工作日期:1998-2003工作公司:ZZ企业

此处的工作日期,和工作公司都是一样,abc三个对象都引用工作经历对象,但同时都引用了最后一个对象,所以三次输出的数据都相同。这就是浅复制的现象,只复制所考虑的对象,而不复制它的引用对象。使用深复制可以解决此问题。

 

3.2 对简历进行改造,使用深复制来实现

具体实现代码如下:

       工作经历类:

package com.zsw.prototype.resume;

 

public class WorkExperience implements Cloneable {

    private String workDate;

 

    private String company;

    public String getCompany() {

       return company;

    }

 

    public void setCompany(String company) {

       this.company = company;

    }

 

    public String getWorkDate() {

       return workDate;

    }

 

    public void setWorkDate(String workDate) {

       this.workDate = workDate;

    }

   

    public Object clone(){

       try {

           return super.clone();

       } catch (CloneNotSupportedException e) {        

           e.printStackTrace();

           return null;

       }

    }

}

 

 

简历源码类:

package com.zsw.prototype.resume;

 

public class Resume implements Cloneable {

 

    private String name;

    private String sex;

    private int age;

    private WorkExperience work;

   

    public Resume(String name){

       this.name = name;

       work = new WorkExperience();

    }

   

    //设置个人信息

    public void setPersonalInfo(String sex,int age){

       this.sex = sex;

       this.age = age;

    }

   

    //设置工作经历

    public void setWorkExperience(String workDate,String company){

       work.setWorkDate(workDate);

       work.setCompany(company);

    }

   

    public void display(){

       System.out.println("姓名:"+name+"性别:"+sex+"年龄:" + age);

       System.out.println("工作日期:"+work.getWorkDate()+"工作公司:"+work.getCompany());

    }

   

    public Object clone(){

       try {

           Resume resume = (Resume) super.clone();

           resume.work = (WorkExperience) this.work.clone();

           return resume;

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

           return null;

       }

    }

}

 

 

运行结果如下:

姓名:大鸟性别:男年龄:29

工作日期:1998-2000工作公司:XXXX-公司

姓名:大鸟性别:男年龄:29

工作日期:1998 - 2006工作公司:YY企业

姓名:大鸟性别:男年龄:29

工作日期:1998-2003工作公司:ZZ企业

 

       这样结果就是所要的结果了,看到这里应该深复制与浅复制应该很清楚了吧。

 

4.  原型模式的应用场景

1.    孙大圣身外身法术

2.    .Net中数据集对象DataSet,就有Clone()方法和Copy()方法,Clone()方法用来复制DataSet的结构,但不复制DataSet的数据,实现了原型模式的浅复制。Cope方法不但复制了结构,也复制了数据。在这里Clone()Copy()分别实现了原型模式中的浅复制和深复制。

3.    简历的复制

 

 

2.3对两种形式的比较:

如果要创建的原型对象数目较少而且比较固定的话,可以采用第一种形式,即简单形式的原始模型。

如果要创建的原型对象数目不固定的话,可以采取第二种形式,也即登记形式的原始模型模式。

5.  原型模式的有点和缺点

n         原型模式允许动态的添加或减少产品类。

n         原始模型模式提供简单的创建结构。

n         原始模型模式具有给一个应用软件动态加载新的功能能力。

n         产品类不需要非得有任何事先确定的等级结构。

 

原始模型模式的最主要的缺点是每一个类都必须配备一个克隆的方法。

 

 

6.  参考文档

n         Java与模式》

n         《大话设计模式》

 

 

 

待续………..

相关文章
相关标签/搜索