
基本介绍
原型模式(Prototype Pattern)主要用于在保证性能的情况下创建重复的对象,也就是创建当前对象的克隆,这种模式是实现了一个原型接口。在开发过程中,如果我们已经明确了所需要创建对象的种类,且创建这种类型对象的代价比较大(创建数量庞大,频繁的数据库交互对数据库等),就可以用原型实例指定所要创建对象的种类,然后通过拷贝这些原型创建新的对象。这就有点像我们生物里面学的细胞分裂。

日常举例
克隆羊的例子:有一只克隆羊叫多莉,没错就是这只羊,长的就是下面图片中的样子。。。现在按照这个样子再克隆 N 只多莉。。。

传统方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class Sheep { private String name; private int age; private String color;
public Sheep(String name, int age, String color) { this.name = name; this.age = age; this.color = color; }
public Sheep() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class CloneDollySimple { static class Client{ public static void main(String[] args) { Sheep dolly = new Sheep("dolly",2,"gray"); Sheep sheep = new Sheep(dolly.getName(),dolly.getAge(),dolly.getColor()); Sheep sheep1 = new Sheep(dolly.getName(),dolly.getAge(),dolly.getColor()); Sheep sheepN = new Sheep(dolly.getName(),dolly.getAge(),dolly.getColor()); } } }
|
原型模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| public abstract class SheepPrototype implements Cloneable{ private String name; private int age; private String color; private SheepPrototype mother;
public SheepPrototype(String name, int age, String color) { this.name = name; this.age = age; this.color = color; }
public SheepPrototype() { } protected abstract String eat(); public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; } public SheepPrototype getMother() { return mother; }
public void setMother(SheepPrototype mother) { this.mother = mother; }
@Override protected SheepPrototype clone() { SheepPrototype sheepPrototype = null; try { sheepPrototype = (SheepPrototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return sheepPrototype; }
@Override public String toString() { return "SheepPrototype{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + ", mother=" + mother + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public class ConcreteSheepPrototype extends SheepPrototype{ public ConcreteSheepPrototype(String name, int age, String color) { super(name, age, color); } @Override protected String eat() { return "Eating green grass"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class CloneDollyPrototype {
static class Client{ public static void main(String[] args) { ConcreteSheepPrototype dolly = new ConcreteSheepPrototype("dolly",2,"gray"); dolly.setMother(new ConcreteSheepPrototype("dolly",5,"gray")); ConcreteSheepPrototype sheepPrototype = (ConcreteSheepPrototype) dolly.clone(); ConcreteSheepPrototype sheepPrototype1 = (ConcreteSheepPrototype) dolly.clone(); ConcreteSheepPrototype sheepPrototypeN = (ConcreteSheepPrototype) dolly.clone(); dolly.getMother().setColor("red"); dolly.setAge(6); System.out.println(dolly); System.out.println(sheepPrototype); System.out.println(sheepPrototype1); System.out.println(sheepPrototypeN); } } }
|
运行结果:

对比以上的两种方式很容易可以看出,传统的方式虽然易于理解,但是每次创建新的对象时,都需要重新初始化对象,并获取原始对象的属性,然后设置属性,显然,这种方式效率低;相对于传统方式,原型模式就方便快捷很多,在无需关注细节的情况下,就可以通过原型对象创建出另外的可定制对象,这种方式必须实现 Cloneable 接口。
原型模式主要包含 3 个角色:
- Prototype (抽象原型类):声明克隆方法的接口,是所有具体原型类的公共父类,它可是抽象类也可以是接口,甚至可以是具体实现类。
- ConcretePrototype (具体原型类):它实现抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
- Client (客户端):在客户类中,让一个原型对象克隆自身从而创建一个新的对象。
原型模式在 Spring 框架中的应用
1 2 3 4 5 6 7
| <bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype"> <property name="patterns"> <list> <value>com.syshlang.service..*Service.*(..)</value> </list> </property> </bean>
|
1 2 3 4 5 6 7
| @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE ) public class Sheep { private String name; private int age; private String color; }
|
在上面的配置中可以看到一个标签属性 scope=”prototype”,原型模式与名称为 prototype 的作用域相似。在 Spring 中,一个类如果被标记为”prototype”, 那么将该类注入到另一个 bean 中或者调用容器的 getBean () 方法时,都会产生一个新的 bean 实例。其实,这个产生新的 bean 的过程就是利用了原型模式。
源码:org.springframework.beans.factory.support.AbstractBeanFactory#getBean (java.lang.String)1 2 3 4 5 6 7
|
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
|
源码:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean ()(片段)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { ... else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } } ...
|
附:本次演示的项目地址
https://github.com/syshlang/java-design-patterns