通过复制生成实例
1.使用背景
开发中通常通过new关键字生成实例,必须指定类名,然而在下边情况下,在 不指定类名的情况下生成实例,根据现有的实例生成新的实例。
-
对象种类繁多,无法将其整合到同一个类中
-
难以根据类生成实例.
生成实例的过程太复杂,很难根据类来生成实例.比如用户想生成和之前用户生成实例完全一样的实例时,由于生成过程复杂,很难保证完全一致,所以可以保存之前的实例,然后通过复制来生成。
-
解耦框架与生成实例
2.具体实例
类图:
Prduct
/**
* @author Jay
* @date 2019/6/3 22:36
* @description 继承复制接口,定义抽象方法
*/
public interface Product extends Cloneable {
/**
* 使用方法
*
* @param s
*/
void use(String s);
/**
* 定义生成实例的方法
*
* @return
*/
Product createClone();
}
Manager
用接口来制定方法,则所有实现此接口的类都可以调用.添加新类时不需要再去修改方法内部.一旦使用了别的类名,将会与其他类紧密耦合在一起了。
/**
* @author Jay
* @date 2019/6/3 22:47
* @description 定义注册的规范
*/
public class Manager {
/**
* 通过map实现一个实例池,每次调用注册方法都可以将实例放入,保证了不重复
*/
private HashMap showcase = new HashMap();
public void register(String name, Product proto) {
showcase.put(name, proto);
}
/**
* 定义获取实例流程,通过接口制定规范,可以接受其全部实现类对象.
*
* @param protoname
* @return
*/
public Product create(String protoname) {
Product p = (Product) showcase.get(protoname);
//调用复制方法,复制一个新的实例
return p.createClone();
}
}
MessageBox
creatClone()方法用来复制自己,若类实现复制接口或者接口继承接口,只有在本类及其子类,或者实现此接口的类中调用clone(),否则只能通过方法调用。
/**
* @author Jay
* @date 2019/6/3 22:58
* @description 具体实例创建的过程
*/
public class MessageBox implements Product {
private char decochar;
public MessageBox(char decochar) {
this.decochar = decochar;
}
@Override
public void use(String s) {
System.out.println(decochar + s + decochar);
}
@Override
public Product createClone() {
Product p = null;
try {
//只有继承了复制接口的类才可以调用此方法复制自己,将本实例n全部复制到
//新的实例当中.
p = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
main
/**
* @author Jay
* @date 2019/6/3 23:11
* @description
*/
public class Main {
public static void main(String[] args) {
//注册
Manager m1 = new Manager();
MessageBox m2 = new MessageBox('*');
MessageBox m3 = new MessageBox('%');
MessageBox m4 = new MessageBox('+');
m1.register("星号", m2);
m1.register("百分", m3);
m1.register("加号", m4);
//生成
//父类接收,可以直接生成,不用通过new,也不需要中间复杂的生成实例过程
Product p1 = m1.create("星号");
p1.use("hello world");
}
}
3.设计模式中的具体角色
Prototype(原型)
负责定义用来复制现有实例来生成新实例的方法。
ConncretePrototype(具体的原型)
继承或者实现原型,具体实现复制现有实例来生成新实例的方法,同时不同的类具体实现接口中的方法。(模板方法模式)
Client(使用者)
调用用来复制实现实例的方法,从而生成新的实例。注册生成实例池,调用复制方法复制池中已有的实例,实现生成新的对象.
使用类名会出现的问题:
当类作为组件复用时,一旦代码中出现要使用的类的名字,就无法与该类分离出来,无法实现代码的复用,即若要使用其他类时必须重写源码,但若是没有源码程序,只有字节码程序,则无法实现程序的修改,因此,该类能否被复用,必须是不通过修改源码也可以完成,即没有源码也可以完成复用。
面向对象编程的目标之一: 作为组件的复用(.class文件)
4.clone()方法
只有实现了Cloneable接口的本类或者子类才可以调用clone(),此方法返回的是复制出的实例。
clone()内部处理:
分配与要复制的实例同样大小的内存空间,将要复制的实例中的字段值复制到所分配的内存空间。
Cloneable接口是标记接口,标记此类可以复制,其中并没有clone()是object中有clone()方法。
clone()方法是浅复制
只是将复制实例的字段直接复制到新的实例中,并没有考虑字段中存的值,只会复制,并不会调用其构造函数。完全复制需要重写clone()方法,并且调用super.clone()父类方法。