【3W2H设计模式】- 原型模式
一、WHAT 什么是原型模式
原型模式是创建者模式的一种,用于创建重复对象,且能保证性能。它提供了一种创建对象的最佳方式。
原型模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
二、WHY 为什么用原型模式
原型模式实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。原型模式主要解决在运行期建立和删除原型。
三、WHEN 什么时候用原型模式
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
四、HOW 如何实现原型模式
4.1 类图
4.2、原型模式组成与作用
编号 | 组成(角色) | 作用 |
1 | 抽象原型(Prototype) | 规定拷贝接口。 |
2 | 具体原型(Concrete Prototype) | 被拷贝的对象。 |
3 | 客户(Client) | 客户类提出创建对象的请求。 |
4.3、创建者模式代码示例
- 创建一个抽象原型
public interface Prototype{ int id = 0; String name = null; Prototype clone(); }
- 实现原型创建具体的原型
public class ConcretePrototypeA implements Prototype { public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private int id; private String name; @Override public ConcretePrototypeA clone() { ConcretePrototypeA concretePrototype = new ConcretePrototypeA(); concretePrototype.setId(this.id); concretePrototype.setName(this.name); return concretePrototype; } }
/* * 继承Prototype并创建类ConcretePrototypeB */ public class ConcretePrototypeB implements Prototype { public int getIdb() { return idb; } public void setIdb(int idb) { this.idb = idb; } public String getNameb() { return nameb; } public void setNameb(String nameb) { this.nameb = nameb; } public String getValueb() { return valueb; } public void setValueb(String valueb) { this.valueb = valueb; } private int idb; private String nameb; private String valueb; @Override public ConcretePrototypeB clone() { ConcretePrototypeB concretePrototype = new ConcretePrototypeB(); concretePrototype.setIdb(this.idb); concretePrototype.setNameb(this.nameb); concretePrototype.setValueb(this.valueb); return concretePrototype; }
- 使用 Prototype 类实现clone 对象。
public class Client { public static void main(String[] args) { ConcretePrototypeA concreteProductA=new ConcretePrototypeA(); concreteProductA.setId(100); concreteProductA.setName("Clone ConcreteProtoTypeA"); System.out.println(concreteProductA.getName()); ConcretePrototypeA prototypeA=concreteProductA.clone(); prototypeA.setId(100); prototypeA.setName("Clone PrototypeA"); System.out.println(prototypeA.getName()); } }
4.4、通过浅拷贝创建新对象
在浅克隆中,如果源对象的成员变量是值类型,将复制一份给克隆对象;如果源对象的成员变量是引用类型,则将引用对象的地址复制一份给目标对象,也就是说源对象和目标对象的成员变量指向相同的内存地址。简言之,浅克隆,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
import java.util.List; public class ShallowClone implements Cloneable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getAddr() { return addr; } public void setAddr(List<String> addr) { this.addr = addr; } private List<String> addr; @Override public ShallowClone clone() { try { return (ShallowClone) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } } }
import java.util.ArrayList; import java.util.List; public class ShallowCloneClinet { public static void main(String[] args) { ShallowClone superClone=new ShallowClone(); superClone.setId(100); superClone.setName("赤木"); List<String> attrList=new ArrayList<>(); attrList.add("东京"); attrList.add("京都"); superClone.setAddr(attrList); System.out.println("superClone Id="+superClone.getId()); System.out.println("superClone Id="+superClone.getName()); ShallowClone superClone2=superClone.clone(); superClone2.setId(10000); superClone2.setName("赤木"); System.out.println("superClone2 Id="+superClone2.getId()); System.out.println("superClone2 Id="+superClone2.getName()); } }
4.5、通过序列化深拷贝创建对象
import java.io.*; public class SerializableClone implements Serializable { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public SerializableClone deepClone() throws Exception { ByteArrayOutputStream buf = new ByteArrayOutputStream(); // 把流放在 tyr资源块中,程序结束java会自动关闭流资源 try (ObjectOutputStream outputStream = new ObjectOutputStream(buf)) { outputStream.writeObject(this); } try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()))) { return (SerializableClone) inputStream.readObject(); } } }
public class SerializableClient { public static void main(String[] args) { SerializableClone clone=new SerializableClone(); clone.setId(100); clone.setName("樱木花道"); System.out.println("clone->Id:"+clone.getId()); System.out.println("clone->Name:"+clone.getName()); try { SerializableClone clone2 = clone.deepClone(); clone2.setId(1000); clone2.setName("流川枫天"); System.out.println("clone2->Id:"+clone2.getId()); System.out.println("clone2->Name:"+clone2.getName()); }catch (Exception e){ System.out.println(e.getMessage()); } } }