原型模式

  原型模式 (Prototype Pattern) 类似于ctrl+c然后ctrl+v,用于复制对象,而非创建,因为创建对象相对于复制,更消耗资源一些,而且不能获得对象在运行时的状态。但原型模式会使得访问权限失效,因为是直接从内存中拷贝对象,所以要注意使用的范围。它的使用场景也和生活中的拷贝类似:

  • 当需要大量相同或者相似的对象时
  • 当需要更多运行时的对象状态,而非初始的、干净的、空的对象状态时
  • 当类的初始化会消耗大量资源时
  • 当对象的创建要求复杂的数据准备、各类权限时
  • 当需要解耦框架和产生的实例时,即不使用类名来创建一些实例

  原型模式的结构

  • 抽象原型类 (Abstract Prototype):规定了具体原型对象必须实现的接口,提供解耦功能,它继承或实现Cloneable接口(仅仅只起标识作用,同Serializable接口,不继承而使用clone方法会导致CloneNotSupportedException异常),并重写Object类的clone方法;
  • 具体原型类 (Concrete Prototype):实现抽象原型类,是被克隆的目标类;
  • 调用者 (Invoker):具体原型类的调用者。

  原型模式是有浅拷贝 (Shallow Copy)深拷贝 (Deep Copy) 之分的。浅拷贝指的是对于八种基本数据类型的拷贝,Object类的clone方法的默认实现就是浅拷贝;深拷贝指的是针对除了八种基本数据类型以外的类型的拷贝,如数组、列表、集合。需要我们自己来写代码实现深拷贝。

/**
 * 抽象原型类
 * @author 青青橙
 *
 */
public interface AbstractPrototype extends Cloneable {
    void printShapeType();
    Object clone();
}
import java.util.HashMap;

/**
 * 具体原型类
 * @author 青青橙
 *
 */
public class ConcretePrototypeCircle implements AbstractPrototype {
    private String shapeName;
    private HashMap<Integer, String> info;
    private Circle circle;

    /*
     * get、set和toString方法
     */
     
    public ConcretePrototypeCircle(String shapeName, HashMap<Integer, String> info, Circle circle) {
        super();
        this.shapeName = shapeName;
        this.info = info;
        this.circle = circle;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public Object clone() {
        ConcretePrototypeCircle concretePrototypeCircle = null;
        try {
            // 对基本类型进行浅克隆
            concretePrototypeCircle= (ConcretePrototypeCircle)super.clone();
            // 对每个复杂类型进行单独克隆,需要先在该复杂类型的类中继承Cloneable接口,重写clone()方法或者使用序列化进行克隆
            // 这里HashMap已经继承Cloneable接口,且重写了clone方法,因此可以直接使用
            concretePrototypeCircle.info = (HashMap<Integer, String>)this.info.clone();
            // 对自定义对象进行深克隆,同复杂类型
            concretePrototypeCircle.circle = (Circle)this.circle.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return concretePrototype;
    }

    @Override
    public void printShapeType() {
        System.out.println(Circle.CIRCLE);
    }
}
/**
 * 自定义复杂对象javabean
 * 需要实现Cloneable接口,重写clone方法
 * @author 青青橙
 *
 */
public class Circle implements Cloneable {
    public static final String CIRCLE = "Circle";
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (Circle)super.clone();
    }

    @Override
    public String toString() {
        return CIRCLE;
    }
}
import java.util.HashMap;

/**
 * 普通原型模式调用者
 * @author 青青橙
 *
 */
public class Invoker {
    public static void main(String[] args) {
        HashMap<Integer, String> info = new HashMap<Integer, String>(16);
        info.put(1, "半径为2");
        AbstractPrototype abstractPrototype = new ConcretePrototypeCircle("圆形", info, new Circle());
        System.out.println(abstractPrototype);
        AbstractPrototype clone = (ConcretePrototypeCircle)abstractPrototype.clone();
        System.out.println(clone);
    }
}

  运行调用者,输出结果为:

ConcretePrototype [shapeName=圆形, info={1=半径为2}, shapeType=Circle]
ConcretePrototype [shapeName=圆形, info={1=半径为2}, shapeType=Circle]

  两对象内容相同,当然,内存地址是不同的。去掉剧体原型类中的toString方法,输出内存地址即可验证。当然这里的Circle类完全可以不要,只是为了模拟自定义对象的克隆才强行写的。
  这就是基本的原型模式使用方法,还可以为原型模式中加入原型管理器 (PrototypeManager),扩展原型模式。该类用HashMap保存多种原型,调用者可以通过原型管理器提供的get(String id)方法从中获取不同原型的复制。
  再创建一个具体原型类,来使得原型管理器能放入多种原型:

import java.util.HashMap;

/**
 * 具体原型类
 * @author 青青橙
 *
 */
public class ConcretePrototypeSquare implements AbstractPrototype {
    private String shapeName;
    private HashMap<Integer, String> info;
    private Square square;

    /*
     * get、set和toString方法
     */

    public ConcretePrototypeSquare(String shapeName, HashMap<Integer, String> info, Square square) {
        super();
        this.shapeName = shapeName;
        this.info = info;
        this.square = square;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public Object clone() {
        ConcretePrototypeSquare concretePrototypeSquare = null;
        try {
            // 对基本类型进行浅克隆
            concretePrototypeSquare = (ConcretePrototypeSquare)super.clone();
            // 对每个复杂类型进行单独克隆,需要先在该复杂类型的类中继承Cloneable接口,重写clone()方法或者使用序列化进行克隆
            // 这里HashMap已经继承Cloneable接口,且重写了clone方法,因此可以直接使用
            concretePrototypeSquare.info = (HashMap<Integer, String>)this.info.clone();
            // 对自定义对象进行深克隆,同复杂类型
            concretePrototypeSquare.square = (Square)this.square.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return concretePrototypeSquare;
    }

    @Override
    public void printShapeType() {
        System.out.println(Square.SQUARE);
    }

}
/**
 * 自定义复杂对象javabean
 * @author 青青橙
 *
 */
public class Square implements Cloneable {
    public static final String SQUARE = "Square";
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (Square)super.clone();
    }

    @Override
    public String toString() {
        return SQUARE;
    }
}

  原型管理器:

import java.util.HashMap;

/**
 * 原型管理器:存放多种原型,返回不同原型的复制
 * @author 青青橙
 *
 */
public class PrototypeManager {
    private HashMap<String, AbstractPrototype> prototypeMap = null;

    public PrototypeManager() {
        super();
        prototypeMap = new HashMap<>(16);
        HashMap<Integer, String> info1 = new HashMap<Integer, String>(16);
        info1.put(1, "半径为3");
        prototypeMap.put("圆", new ConcretePrototypeCircle("圆形", info1, new Circle()));
        HashMap<Integer, String> info2 = new HashMap<Integer, String>(16);
        info2.put(1, "边长为3");
        prototypeMap.put("方", new ConcretePrototypeSquare("方形", info2, new Square()));
    }
    
    public void addShape(String key, AbstractPrototype abstractPrototype) {
        prototypeMap.put(key, abstractPrototype);
    }
    
    public AbstractPrototype getShape(String key) {
        AbstractPrototype abstractPrototype = prototypeMap.get(key);
        return (AbstractPrototype)abstractPrototype.clone();
    }
}

  调用者:

/**
 * 扩展原型模式调用者
 * @author 青青橙
 *
 */
public class Invoker2 {
    public static void main(String[] args) {
        PrototypeManager prototypeManager = new PrototypeManager();
        AbstractPrototype circle = prototypeManager.getShape("圆");
        System.out.println(circle);
        AbstractPrototype square = prototypeManager.getShape("方");
        System.out.println(square);
    }
}

  运行调用者,输出如下:

ConcretePrototypeCircle [shapeName=圆形, info={1=半径为3}, shapeType=Circle]
ConcretePrototypeSquare [shapeName=方形, info={1=边长为3}, shapeType=Square]

  获取到两种原型的克隆。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值