【Design Patterns】原型模式

原型模式(Prototype Pattern)

wiki:

【Design Patterns】原型模式_第1张图片

类型: 创建型

何时使用: 当直接创建对象的代价比较大时,则采用这种模式

UML

【Design Patterns】原型模式_第2张图片

原型设计模式解决了以下问题:

  • 如何创建对象以便在运行时指定要创建的对象?
  • 如何动态加载类的实例化

原型设计模式描述了如何解决这些问题:

  • 定义一个Prototype返回自身副本的对象。
  • 通过复制Prototype对象创建新对象。

原型模式的注意事项:

  • 使用原型模式复制对象不会调用类的构造方法。
  • 单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
  • 浅拷贝: Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝
  • 深拷贝: 将原型模式中的数组、容器对象、引用对象等另行拷贝
  • 因为是从内存中直接

原型模式实例

抽象原型角色

public abstract class Prototype implements Cloneable{
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

具体原型角色

public class ConcretePrototype1 extends Prototype {
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class ConcretePrototype2 extends Prototype {
    private ArrayList list = new ArrayList();

    /**
     * 由于Clone不会调用构造函数,可用来查看差别
     */
    public ConcretePrototype2() {
        System.out.println("ConcretePrototype2 init...");
        this.list.add("Hello World!");
    }

    public ArrayList getList() {
        return list;
    }

    public void setList(ArrayList list) {
        this.list = list;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        ConcretePrototype2 clone = (ConcretePrototype2)super.clone();
        // 深度拷贝
        clone.setList((ArrayList) this.getList().clone());
        return clone;
    }
}

场景类

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 测试克隆
        ConcretePrototype1 concretePrototype1 = new ConcretePrototype1();
        System.out.println(concretePrototype1);
        System.out.println(concretePrototype1.clone());

        System.out.println();

        ConcretePrototype2 concretePrototype2 = new ConcretePrototype2();
        System.out.println(concretePrototype2);
        final ConcretePrototype2 clone = (ConcretePrototype2)concretePrototype2.clone();
        System.out.println(clone);
        System.out.println(concretePrototype2.getList());
        System.out.println(clone.getList());



        // 测试性能
        System.out.println();
        int count = 10000;
        long startTmie = System.currentTimeMillis();
        for (int i = 0;i

带Prototype Manager的原型模式(登记形式的原型模型)

  • 从缓存(MAP)中获取
  • 可使用HashTable或者ConcurrentHashMap
  • 如果使用HashMap需要考虑加锁,或者Collections.synchronizeMap(hashMap);使其同步

UML

@startuml
class Client{
}

interface Prototype{
   + Prototype clone()
}

class ConcretePrototypeA{
   - name:String
   + clone():Prototype 
   + getName():String 
   + setName():void
}

class ConcretePrototypeB{
   - name:String 
   + clone():Prototype 
   + getName():String 
   + setName():void
}

class PrototypeManager{
   - map:Map
   - PrototypeManager():PrototypeManager
   + addPrototype(Prototype):void
   + removePrototype(Prototype):void
   + getPrototype():Prototype 
}

Client ..> Prototype
Client ..> PrototypeManager
Prototype <|.. ConcretePrototypeA
Prototype <|.. ConcretePrototypeB
@enduml

【Design Patterns】原型模式_第3张图片

抽象原型接口

public interface Prototype {
    /**
     * 自定义克隆(可使用第三方序列化方式)
     * @return Prototype
     */
    Prototype clone();

    /**
     * 标识
     * @return id
     */
    String id();
}

具体原型对象

public class ConcretePrototypeA implements Prototype{
    private String name;

    public ConcretePrototypeA(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Prototype clone() {
        // 自定义克隆,此处可新建或者使用第三方序列化
        return new ConcretePrototypeA(this.getName());
    }

    @Override
    public String id() {
        return this.name;
    }
}

public class ConcretePrototypeB implements Prototype{
    private String name;

    public ConcretePrototypeB(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Prototype clone() {
        // 自定义克隆,此处可新建或者使用第三方序列化
        return new ConcretePrototypeB(this.getName());
    }

    @Override
    public String id() {
        return this.name;
    }
}

PrototypeManager

public class PrototypeManager {
    private static Map map = new ConcurrentHashMap();

    /** 防止外部初始化,保证只有一个实例 */
    private PrototypeManager() {}

    public static void addPrototype(Prototype prototype){
        map.put(prototype.id(), prototype);
    }

    public static void removePrototype(Prototype prototype){
        map.remove(prototype.id());
    }

    /**
     * 获取原始对象
     * @param id 标识
     * @return Prototype
     */
    public static Prototype getPrototype(String id){
        return map.get(id);
    }

    /**
     * 获取拷贝对象
     * @param id 标识
     * @return Prototype
     */
    public static Prototype getPrototypeClone(String id){
        return map.get(id).clone();
    }
}

场景类

public class Client {
    public static void main(String[] args) {
        Prototype prototypeA = new ConcretePrototypeA("ConcretePrototypeA");
        Prototype prototypeB = new ConcretePrototypeB("ConcretePrototypeB");

        PrototypeManager.addPrototype(prototypeA);
        PrototypeManager.addPrototype(prototypeB);

        System.out.println(prototypeA);
        System.out.println(PrototypeManager.getPrototype("ConcretePrototypeA"));
        System.out.println(PrototypeManager.getPrototypeClone("ConcretePrototypeA"));
        //  ConcretePrototypeA@60e53b93
        //  ConcretePrototypeA@60e53b93
        //  ConcretePrototypeA@5e2de80c
    }
}

原型模式的优缺点

优点:

  • 性能提高(直接操作内存中的二进制流)
  • 逃避构造函数的约束

缺点:

  • 必须实现 Cloneable 接口
  • 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
  • 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

转载于:https://my.oschina.net/u/2254055/blog/3006484

你可能感兴趣的:(设计模式)