设计模式: Prototype (原型)

论坛 期权论坛 脚本     
匿名网站用户   2020-12-21 04:41   22   0

设计模式: Prototype (原型)

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

Prototype模式允许一个对象再创建另外一个可定制的对象,无需指定如何创建的细节。

原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实现创建。

简单来说,就是当你做一个有固定模板的东西的时候,只是其中部分内容有变化,你是想从头开始,新建然后写写写,还是Ctrl C+Ctrl V,当然除却勤快的人愿意从头开始,我个人是比较倾向于copy/pasty的。

Java中提供了clone()方法来实现对象的克隆,所以Prototype模式一下子变得很简单。

使用场景

资源优化场景。

类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

性能和安全要求的场景。

通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

一个对象多个修改者的场景。

一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

我们先看一下之前工厂模式的例子,来重新用原型模式做一下,创建一个抽象类Animal 和扩展了Animal 类的实体类。下一步是定义类AnimalCache,该类把Animal 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆。

PrototypPatternDemo,我们的演示类使用 AnimalCache类来获取 Animal 对象。

创建一个实现了Clonable 接口的抽象类

Animal.java

public abstract class Animal implements Cloneable {

 private String name;
 protected String type;

 abstract void sing();

 public String getType() {
  return type;
 }

 public String getName() {
  return name;
 }

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

 public Object clone() {
  Object clone = null;
  try {
   clone = super.clone();
  } catch (CloneNotSupportedException e) {
   e.printStackTrace();
  }
  return clone;
 }

}

创建扩展了上面抽象类的实体类。

Dog.java

public class Dog extends Animal{

 public Dog() {
  type = "Dog!";
 }

 @Override
 void sing() {
  System.out.println("Inside Dog::sing() method.");
  System.out.println("what's dog sing: 汪汪汪");
  
 }

}


Pig.java

public class Pig extends Animal {

 public Pig() {
  type = "Pig!";
 }

 @Override
 void sing() {
  System.out.println("Inside Pig::sing() method.");
  System.out.println("what's pig sing: 哼哼哼");
  
 }

}


Fox.java

public class Fox extends Animal {

 public Fox() {
  type = "Fox!";
 }

 @Override
 void sing() {
  System.out.println("Inside Fox::sing() method.");
  System.out.println("what's fox sing: 叮叮叮");

 }

}

创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。

AnimalCache.java

import java.util.Hashtable;

public class AnimalCache {

 private static Hashtable<String, Animal> AnimalMap = new Hashtable<String, Animal>();

 public static Animal getAnimal(String AnimalName) {
  Animal cachedAnimal = AnimalMap.get(AnimalName);
  return (Animal) cachedAnimal.clone();
 }

 // 对每种动物都运行数据库查询,并创建该动物
 // AnimalMap.put(AnimalKey, Animal);
 // 例如,我们要添加三种动物
 public static void loadCache() {
  Dog Dog = new Dog();
  Dog.setName("1");
  AnimalMap.put(Dog.getName(), Dog);
  
  Pig Pig = new Pig();
  Pig.setName("2");
  AnimalMap.put(Pig.getName(), Pig);

  Fox Fox = new Fox();
  Fox.setName("3");
  AnimalMap.put(Fox.getName(), Fox);
 }
}

PrototypePatternDemo使用 AnimalCache 类来获取存储在 Hashtable 中的形状的克隆

PrototypePatternDemo.java

public class PrototypePatternDemo {

  public static void main(String[] args) {
       AnimalCache.loadCache();

       Animal clonedAnimal = (Animal) AnimalCache.getAnimal("1");
       System.out.println("Animal : " + clonedAnimal.getType());        
       clonedAnimal.sing();
       
       Animal clonedAnimal2 = (Animal) AnimalCache.getAnimal("2");
       System.out.println("Animal : " + clonedAnimal2.getType());        
       clonedAnimal2.sing();
       
       Animal clonedAnimal3 = (Animal) AnimalCache.getAnimal("3");
       System.out.println("Animal : " + clonedAnimal3.getType());    
       clonedAnimal3.sing();
    }

}

验证输出:

优点

简化对象创建过程,通过拷贝的方式构建效率更高

可运行时指定动态创建的对象

Animal : Dog!
Inside Dog::sing() method.
what's dog sing: 汪汪汪
Animal : Pig!
Inside Pig::sing() method.
what's pig sing: 哼哼哼
Animal : Fox!
Inside Fox::sing() method.
what's fox sing: 叮叮叮

缺点

需要实现 Cloneable接口, clone位于内部,不易扩展,容易违背开闭原则(程序扩展,不应该修改原有代码)

默认的 clone 只是浅克隆,深度克隆需要额外编码(比如:统一实现 Cloneable接口,或者序列化方式,还有 org.apache.commons:commons-lang3.SerializationUtils.java)

注意事项

通过内存拷贝的方式构建出来的,会忽略构造函数限制

需要注意深拷贝和 浅拷贝,默认Cloneable 是浅拷贝,只拷贝当前对象而不会拷贝引用对象,除非自己实现深拷贝

与单例模式冲突, clone是直接通过内存拷贝的方式,绕过构造方法

常用克隆不可变对象,如果你克隆的对象10个字段改9个还不如实例化算了

clone只是一个语法,非强制方法命名

很少单独出现,常与工厂模式相伴

本文参考了Patterns in Java 和http://www.runoob.com


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP