《图解设计模式》读书笔记3-2 Prototype模式

Prototype(原型)模式的由来

创建一个实例,可以关键字new创建。但有时候,我们需要在不指定类名的前提下生成实例,比如:

  • 需要处理的对象种类繁多,无法整合到一个类里面,如果分别作为一个类,类的数量又太多了。

  • 很难通过代码生成实例:比如用户在画图工具中画出来的图形实例,如果用代码创建的话是非常困难的。我们可以先保存起来,需要时通过复制生成实例。

  • 想解耦框架和生成的实例时:不指定类名来生成实例,而是事先注册一个原型实例,通过复制该实例来生成新实例。比如打印机,不需要知道具体的文档内容,到需要的时候复印就行了,复印多少次都没问题。

类图

代码

Product接口,继承Cloneable接口,实现Product接口的类都可以使用clone方法进行实例的复制。
use方法表示怎么使用,具体怎么用,由子类来实现。
createClone是用于复制实例的方法。

public interface Product extends Cloneable {
    public abstract void use(String s);
    public abstract Product createClone();
}

Manager类,需要生成对象的类可以调用Manager类的create方法复制实例

public class Manager {
    private HashMap showcase = new HashMap();
    public void register(String name, Product proto) {
        showcase.put(name, proto);
    }
    public Product create(String protoname) {
        Product p = (Product) showcase.get(protoname);
        return p.createClone();
    }
}

具体要进行对象复制的类

public class MessageBox implements Product {
    private char decochar;
    public MessageBox(char decochar) {
        this.decochar = decochar;
    }

    @Override
    public void use(String s) {
        int length = s.getBytes().length;
        for (int i = 0; i < length+4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
        System.out.println(decochar + " " + s + " " + decochar);
        for (int i = 0; i < length+4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
    }

    @Override
    public Product createClone() {
        Product p = null;
        try {
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

public class UnderlinePen implements Product {
    private char ulchar;
    public UnderlinePen(char ulchar) {
        this.ulchar = ulchar;
    }
    @Override
    public void use(String s) {
        int length = s.getBytes().length;
        System.out.println(""" + s + """);
        System.out.print(" ");
        for (int i = 0; i < length; i++) {
            System.out.print(ulchar);
        }
        System.out.println("");
    }

    @Override
    public Product createClone() {
        Product p = null;
        try {
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

如何使用

public static void main(String[] args) {
        Manager manager = new Manager();
        UnderlinePen upen = new UnderlinePen('~');
        MessageBox mbox = new MessageBox('*');
        MessageBox sbox = new MessageBox('/');

        manager.register("Strong Message", upen);
        manager.register("Warning box", mbox);
        manager.register("Slash box", sbox);


        Product p1 = manager.create("Strong Message");
        p1.use("hello");

        Product p2 = manager.create("Warning box");
        p2.use("hello");

        Product p3 = manager.create("Slash box");
        p3.use("hello");
}
	//结果
	"hello"
 	~~~~~
	*********
	* hello *
	*********
	/////////
	/ hello /
	/////////

角色

Prototype(原型)

此角色负责定义用现有实例复制新实例的方法。对应于本例中的Product接口。

ConcretePrototype(具体的原型)

负责实现原型的方法。对应于本例中的MessageBox和UnderlinePen

Client(使用者)

负责使用原型的方法复制生成新的实例

模式的类图

我的理解

  说实话,由于经验所限,我不太能体会的到这个模式的好处。
  看看示例代码:代码实现的功能类似于一个文本编辑器,可以对文本进行下划线(UnderlinePen)和提示(MessageBox)两个操作。在一篇文章里面,可能有很多很多个下划线和提示操作。每一个都创建对象,创建过程简单还好,复杂的话那代码量就太恐怖了。所以搞一个原型对象,用到了就复制就行了。
  这只是我能理解的其中一个好处,更多内容可以看看这篇文章https://www.cnblogs.com/chenssy/p/3313339.html


另外原型模式涉及到了对象的深拷贝和浅拷贝。区别就在于:复制对象时,是否复制对象中的引用指向的内存。那篇文章里面有解释。

原文地址:https://www.cnblogs.com/qianbixin/p/10992895.html