Gof23-Portotype模式
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
介绍
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。也就是根据现有的实例来生成新的实例。
主要解决:在运行期根据原型创建实例或删除原型。
何时使用:
1、对象种类繁多,无法将它们整合到一个类中时
需要处理的类太多,如果将它们分别作为一个类,那么就需要编写很多类文件。
2、难以根据类生成实例时
生成实例的过程太为复杂,难以根据类生成新的实例。
3、想解耦框架与生成的实例时
生成实例的框架不依赖具体的类,可以先注册一个原型到map中,然后通过复制该原型生成新的实例。
关键代码:
1、实现克隆操作,在 JAVA 实现 Cloneable 接口,重写 clone()
2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。
使用场景:
1、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2、性能和安全要求的场景。
3、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
4、一个对象多个修改者的场景。
5、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
6、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
注意事项:
与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
角色:
- Prototype(抽象原型)
- 负责定义类中应该有哪些方法,以及定义复制现有实例生成新实例的方法。
- ConcreatePrototype(具体的原型)
- 负责实现上面接口定义的方法。
- Client(使用者)
- 负责使用复制实例的方法生吃新的实例。
UML类图:
实例
Product接口,(抽象原型角色)
/** * 复制功能的接口,继承了Cloneable接口,实现了该接口的类的实例,可以调用clone方法实现自动复制实例 */ public interface Product extends Cloneable{ /** * 使用的方法,具体怎么使用,不用关心,子类自己实现 * @param s */ public abstract void use(String s); /** * 用于复制实例的方法 * @return */ public abstract Product createProduct(); }
Manager类,(使用者角色)
public class Manager { /** * 用于保存实例和名字之间的对应关系 */ private Map<String, Product> showCase = new HashMap<>(); /** * 接收到一组名字和Product接口的子类,注册到showCase中 * @param name 类名 * @param proto Product的子类,它实现了Product,也就可以调用它的use方法和createClone方法 */ public void register(String name, Product proto) { showCase.put(name, proto); } /** * 通过该方法复制实例,Manager类和Product接口没有出现它们的子类,就可以独立修改这两个类,而不受它们子类的影响 * 降低了代码的耦合性 * @param protoName 模板名字 * @return */ public Product create(String protoName) { Product product = showCase.get(protoName); return product.createProduct(); } }
MeeageBox:(具体的原型角色)
public class MessageBox implements Product{ /** * 用于装饰的字符 */ private char decoChar; public MessageBox(char decoChar) { this.decoChar = decoChar; } /** * 自定义use方法 * @param s * @throws UnsupportedEncodingException */ @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(); } /** * 实现复制的方法,通过调用父类的clone方法实现复制 * @return */ @Override public Product createProduct() { Product product = null; try { product = (Product)clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return product; } }
Main类,测试类
public class Main { public static void main(String[] args) { Manager manager = new Manager(); MessageBox messageBox = new MessageBox('*'); // 将具体的原型类注册到manager中 manager.register("warning", messageBox); // 通过manager获得MessageBox的实例 Product product = manager.create("warning"); product.use("Hello, world"); } } /** * **************** * * Hello, world * * **************** */#设计模式#
笔者学习设计模式的记录与心得。