参考:1.《图解设计模式》 https://www.cnblogs.com/xuekyo/archive/2012/07/12/2587730.html java的浅克隆和深克隆:https://www.cnblogs.com/betterboyz/p/9356190.html Spring中的原型模式: https://www.jianshu.com/p/611be5eb42a1
模式定义
- 创建对象的种类,并且通过拷贝这些原型创建新的对象;
- Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。
例如仪器数据采集器的共同初始化工作可在原型类对象中完成,随后将其克隆出PDF文件数据采集器对象和Excel文件数据采集器对象,并为两对象属性做后续的扩展,免去了公共属性的初始化工作。
模式原理
通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
模式好处
每次NEW一个对象,都需要执行一次构造函数,如果构造函数时间长,那么多次执行初始化的效率大大降低了。一般在初始化信息不变化的情况下,克隆是最好的方法。这既隐藏了对象创造的细节,又对性能是大大的提升。
模式适合场景
对象种类繁多,无法将其整合到一个类中,如果要这些对象分别作为一个类,则需要编写很多类文件;
- 生成实例的过程太复杂,难以根据类来生成实例;
想要让生成实例的框架依赖具体的类,这时不能指定类名来生成实例,而是事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。
Spring里的Prototype模式
原型bean的创建
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {...}else {...try {...// Create bean instance.if (mbd.isSingleton()) {...}//创建原型beanelse if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {...}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}...return (T) bean;}
代码示例
UNL类图如下
/*** @Author:ling* @Date:2020/4/30 21:08* @Version:1.0*/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 product = (Product) showCase.get(protoname);return product.createClone();}}
public interface Product extends Cloneable{public abstract void use(String s) ;public abstract Product createClone() ;}
/*** @Author:ling* @Date:2020/4/30 21:12* @Version:1.0*/public class MessageBox implements Product {private char decochar;public MessageBox (char decochar) {this.decochar = decochar ;}@Overridepublic 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("");}@Overridepublic Product createClone() {Product p = null ;try {p = (Product) clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}}
/*** @Author:ling* @Date:2020/4/30 21:20* @Version:1.0*/public class UnderlinePen implements Product {private char ulchar ;public UnderlinePen (char ulchar) {this.ulchar = ulchar;}@Overridepublic void use(String s) {int length = s.getBytes().length;System.out.println("\"" + s + "\"");System.out.println(" ");for (int i = 0 ; i < length + 4 ; i++) {System.out.print(ulchar);}System.out.println("");}@Overridepublic Product createClone() {Product p = null ;try {p = (Product) clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}}
/*** @Author:ling* @Date:2020/4/30 21:30* @Version:1.0*/public class Main {public static void main(String[] args) {Manager manager = new Manager();UnderlinePen underlinePen = new UnderlinePen('~') ;MessageBox mbox = new MessageBox('*') ;MessageBox sbox = new MessageBox('/') ;manager.register("Strong message", underlinePen);manager.register("warning box", mbox);manager.register("slash box", sbox);Product p1 = manager.create("Strong message") ;p1.use("Hello world");Product p2 = manager.create("warning box");p2.use("Hello world");Product p3 = manager.create("slash box");p3.use("Hello world");}}
总结
- 在上述代码中,Product接口和Manager类中代码中完全没有出现MessageBox类和UnderlinePen类的名字,这意味着我们可以独立修改Product和Manager,不受MessageBox类和UnderlinePen类的影响,一旦在类中使用了别的类名,就意味着该类与其他类紧密的耦合在了一起。
