设计模式之原型模式(Prototype Pattern)

概述

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

原型模式主要使用场景:
1.类初始化需要消耗非常多的资源。
2.通过new产生一个对象需要非常繁琐的数据准备或者访问权限。

原型模式的两种形式

原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。
原型模式的两种表现形式:1.简单形式,2.登记形式。

简单形式的原型模式:
UML类图如下:
这里写图片描述
上述的UML图中,存在三个角色:
1。Client角色:客户类提出创建对象的请求。
2。抽象原型(Prototype)角色:抽象的角色,由接口或者抽象类实现,用来定义具体原型类所需的接口。
3。具体原型(Concrete Prototype)角色:被复制的对象,此角色需要实现抽象的原型角色所要求的接口。
代码示例:

interface Prototype {

    public Object clonePrototype();
}

class ConcretePrototype implements Prototype{

    public Prototype clonePrototype() {

        Prototype prototype = new ConcretePrototype();
        return prototype;
    }
}

class Client  {

    private Prototype prototype;

    public Client(Prototype prototype){
        this.prototype = prototype;
    }
    public void operation(){
        Prototype pro = (Prototype) prototype.clonePrototype();
    }
}

public class MainTest{

    public static void main(String args[]){
        Prototype prototype = new ConcretePrototype();
        Client client = new Client(prototype);
        client.operation();
    }
}

登记形式的原型模式:
UML图如下所示:
这里写图片描述
上述UML中较之简单实行多一个角色,原型管理器角色(PrototypeManager),该角色主要是用来创建具体原型类的对象,并记录每一个被创建的对象。

代码示例:

import java.util.HashMap;
import java.util.Map;

interface Prototype {

    public Object clonePrototype();
}

class ConcretePrototype implements Prototype{

    public Prototype clonePrototype() {

        Prototype prototype = new ConcretePrototype();
        return prototype;
    }
}

class ProtoTypeManager{

    private static Map<String, Prototype> map = new HashMap<String, Prototype>();

    private ProtoTypeManager(){};

    public synchronized static void setPrototype(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 prototype = map.get(prototypeId);
        if(prototype == null){
            throw new Exception("您希望获取的原型还没有注册或已被销毁");
        }
        return prototype;
    }
}

public class Client{

    public static void main(String args[]) throws Exception{
        Prototype prototype = new ConcretePrototype();
        ProtoTypeManager.setPrototype("p1", prototype);

        Prototype p2 = (Prototype) ProtoTypeManager.getPrototype("p1").clonePrototype();
    }
}

两种形式的比较:
简单形式和登记形式的原型模式各有优缺点。
如果需要创建的原型模式对象数目较少而且比较固定的话,可以采用第一种形式。在这种情况下,原型对象的引用可以由客户端自己保存。
如果要创建的原型对象数目不固定的话,可以采取第二种形式,在这种情况下,客户端不保存对原型对象的引用,这个任务被交给管理员对象。在复制一个原型对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以直接从管理员类中取得这个对象的引用,如果没有,客户端需要自行复制此原型对象。

原型模式使用Java的“克隆”功能

Java的所有类都是从Java.lang.Object类继承而来的,Object类中有一个clone方法,用来返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用。因此,Prototype类需要将clone方法的作用域修改为public类型。
实现Cloneable接口,它在运行时通知虚拟机可以安全的实现了此接口的类上使用clone方法。只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException。
代码示例:

class Prototype implements Cloneable{

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        Prototype prototype = null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO: handle exception
            e.printStackTrace();
        }

        return prototype;
    }
}
class ConcretePrototype  extends Prototype{
    int i = 2;    
    public void show(){
        System.out.println("原型模式实现类"+i);
    }
}

public class Client{

    public static void main(String args[]){
        ConcretePrototype concretePrototype = new ConcretePrototype();
        for (int i = 0; i < 5; i++) {
            try {
                ConcretePrototype con = (ConcretePrototype) concretePrototype.clone();
                con.show();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

使用这个方式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能差别非常明显。
通过调用Object类的clone方法来完成对象的复制,它不会调用到类的构造方法,而且访问权限对clone无效。
单例模式中,只需要将构造方法的访问权限设置为private型,就可以实现单例。所以单例模式与原型模式是冲突的,使用时需要注意。
关于深拷贝和浅拷贝。Object类的clone方法只会拷贝对象中的基本数据类型,对于数组,容器对象,引用对象都不会拷贝,这就是浅拷贝,如果要实现深拷贝,必须将原型模式中的数组,引用对象等另行拷贝。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值