原型模式(ProtoType) - Java里的对象复制
2014-12-21 15:04
429 查看
一, 引用的复制和对象复制.
在编程中, 我们有时会用两个引用指向同一个对象.例如:
ArrayList a = new ArrayLIst(); ArrayList b = a;
看起来好像有a,b两个容器, 实际上a,b是两个引用, 它们都指向同1个Object的内存地址.
而对象复制是指:
在内存里划分一块与指定对象相同内容的内存.
也就是说内存里原理有1个Object的内存, 复制后就有两个了...
二, 对象复制的简便方法.
当然, 对象复制的实现十分简单, 只需要实例化1个具有相同属性的对象就ok了.注意, 如果用 "==" 来讲比较两个引用是返回false, 因为它们的地址不同.
举个列子:
2.1 产品类Prod:
public class Prod { private int prodID; private String prodName; public int getProdID() { return prodID; } public void setProdID(int prodID) { this.prodID = prodID; } public String getProdName() { return prodName; } public void setProdName(String prodName) { this.prodName = prodName; } @Override public String toString(){ return "Prod: " + this.getProdID() + " , " + this.getProdName(); } }
2.2 订单类Order:
public class Order { private int orderID; private Prod prod; private int amount; public int getOrderID() { return orderID; } public void setOrderID(int orderID) { this.orderID = orderID; } public Prod getProd() { return prod; } public void setProd(Prod prod) { this.prod = prod; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public String toString(){ return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString(); } }
2.3 客户端代码:
这里我先实例化1个order类 od1, 然后在复制1个od1 的对象od2Prod p1 = new Prod(); p1.setProdID(1); p1.setProdName("Hammer"); Order od1 = new Order(); od1.setOrderID(1); od1.setProd(p1); od1.setAmount(20); Prod p2 = new Prod(); p2.setProdID(1); p2.setProdName("Hammer"); Order od2 = new Order(); od2.setOrderID(1); od2.setProd(p1); od2.setAmount(20); System.out.println(od1); System.out.println(od2);
输出:
Order: 1 , 20 Prod: 1 , Hammer Order: 1 , 20 Prod: 1 , Hammer
2.4 这种方法的缺点
首先这种写法不够优雅, 很多重复代码.其次, 这种复制方法调用了类的构造函数.
就如上面的例子, 即使Order类的构造函数是空的, 但是实际上构造函数的执行机制很复杂,.
构造函数最重要的动作就是给类里的每个成员划分内存空间. 毕竟java是类c语言, 相当于执行了很多次malloc()函数.
如果某些业务类的构造函数写的很复杂, 就更耗费资源了.
而且
三, 利用Object.clone()方法来实现对象复制.
java里所有对象都是直接或简直继承自基类Object.而clone()是基类的Native 方法, 所谓Native方法可以认为是java 内部特定方法, 它比非Native的执行效率要好.
也就是说, 利用Object.clone() 方法会比实例化1个相同内容对象效率要好.
3.1 Object.clone()方法和 Cloneable接口:
Object.clone() 方法有点特殊, 首先它是public方法, 也就是说它可以通过引用名和"."来调用.但是它不能被子类继承, 也就说, 出了Object类外所有java里的class里面都没有clone()这个方法的.
如果要使用Object.clone()方法.
只能引用1个叫做 Cloneable里的Interface, 然后重写Cloneable接口里的clone()方法, 在里面调用object.clone().
这个接口就起了1个标记的作用, 帮组实现多态.
3.2 订单类Order:
我们按在这个思路来修改上面的订单类Order:
public class Order implements Cloneable{ private int orderID; private Prod prod; private int amount; public int getOrderID() { return orderID; } public void setOrderID(int orderID) { this.orderID = orderID; } public Prod getProd() { return prod; } public void setProd(Prod prod) { this.prod = prod; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public String toString(){ return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString(); } @Override public Object clone(){ Object o = null; try{ o = super.clone(); }catch(Exception e){ e.printStackTrace(); } return o; } }
值得注意的是, Object.clone() 回抛异常.
而, Prod类没有任何修改.
3.3 客户端代码:
Prod p1 = new Prod(); p1.setProdID(2); p1.setProdName("knife"); Order od1 = new Order(); od1.setOrderID(2); od1.setAmount(30); od1.setProd(p1); Order od2 = (Order)od1.clone(); System.out.println(od1); System.out.println(od2);
可见, 只需要执行一句
Order od2 = (Order)od1.clone();
就相当于 复制了1个对象.
3.4 UML图
我们来看看这个例子的UML:实际上这个就是原型模式(prototype)的UML图了,
原来我们不知不觉得使用了原型模式.
四, 原型模式的定义
原型模式(protoType), 用原型实例制定创建对象的种类, 并且通过copy这些原型创建新的对象.总觉得设计模式的定义都太过于简单恶心了.
上面的
原型指的是 Cloneable这个接口.
原型实例指的是 Order这个类.
五, 浅复制和深复制
对象复制也分两种.浅复制:
两个对象中的值类型成员属性相等, 对象成员成员属性实际上没有复制,都是同一个对象.
深复制:
两个对象中的值类型成员属性相等, 对象成员属性指向不同的 具有相同成员的 对象.
如上面的例子, 稍稍修改客户端代码:
Prod p1 = new Prod(); p1.setProdID(2); p1.setProdName("knife"); Order od1 = new Order(); od1.setOrderID(2); od1.setAmount(30); od1.setProd(p1); Order od2 = (Order)od1.clone(); System.out.println(od1); System.out.println(od2);
od1.setOrderID(3);
od1.setAmount(40);
od1.getProd().setProdName("blade");
System.out.println(od1);
System.out.println(od2);
上面 构建了对象od1,
然后复制出了另1个对象od2,
然后修改od1的 值成员 和 对象成员
然后输出od1, 和 od2 成员的值:
Order: 2 , 30 Prod: 2 , knife Order: 2 , 30 Prod: 2 , knife Order: 3 , 40 Prod: 2 , blade Order: 2 , 30 Prod: 2 , blade
可见, 当od1 的id 和 amount的值被改成 3 和 40 后, od2 的id和 Amount的值并不受影响, 因为它们的值类型成员属性是相互独立的.
但是当od1 的 prod属性的内容被修改后, od2 的也被修改了(knife - > blade), 因为 od1 和 od2 的 prod成员指向的都是同1个对象.
这就证明了:
Java里的 Object.clone()方法实现的是浅复制.
六, 原型模式的深复制实现
接下来再次修改上面的例子, 令其实现成深复制而且, 根据项目需要, 复制并不会复制Order的id, 也就是订单号码是唯一的, 只复制Prod和数量.
6.1 订单类Order:
public class Order implements Cloneable{ private int orderID; private Prod prod; private int amount; public int getOrderID() { return orderID; } public void setOrderID(int orderID) { this.orderID = orderID; } public Prod getProd() { return prod; } public void setProd(Prod prod) { this.prod = prod; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public String toString(){ return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString(); } @Override public Object clone(){ Prod p = new Prod(); p.setProdID(this.getProd().getProdID()); p.setProdName(this.getProd().getProdName()); Order o = new Order(); o.setOrderID(this.getOrderID() + 1); o.setAmount(this.getAmount()); o.setProd(p); return o; } }
客户端输出:
Order: 2 , 30 Prod: 2 , knife Order: 3 , 30 Prod: 2 , knife Order: 3 , 40 Prod: 2 , blade Order: 3 , 30 Prod: 2 , knife
可以, 无论od1修改了什么, od2 都不受影响
这种方法放弃了Object.clone(), Order类在重写clone()方法里还是使用了构造方法去实例化1个新的对象.
这种方法配置更加灵活(选择性地复制成员)
当时放弃了Object.clone()的效能优点.
但是这仍然实现了原型模式(protoType)
相关文章推荐
- Rhyme/Java 设计模式之原型模式prototype通过clone方法和反序列化实现深复制
- java设计模式---Prototype Pattern---原型模式(复制建立对象)
- 233_尚学堂_高淇_java300集最全视频教程_【GOF23设计模式】_原型模式_prototype_浅复制_深复制_反序列化实现深复制
- Java 深复制(深克隆)&浅复制(浅克隆)&原型模式(ProtoType)
- 设计模式(Design Patterns)-可复用面向对象软件的基础 05:原型模式(Prototype)和Java中的深、浅拷贝
- Java设计模式_创建型_原型模式_复制对象及状态
- java23种设计模式之原型模式(Prototype)
- java设计模式--原型设计模式 Prototype
- 原型模式 对象深浅复制
- C#面向对象设计模式学习笔记(5) - Prototype 原型模式(创建型模式)
- 设计模式五:Prototype原型模式——对象创建型模式
- 面向对象设计模式之Prototype原型模式(创建型)
- Java设计模式-----Prototype原型模式
- 设计模式之原型法(ProtoType)----对象创建型模式
- JAVA设计模式五--Prototype(原型模式)
- (Prototype)原型模式的Java实现
- Java设计模式 - Prototype(原型模式)
- Prototype(原型)---对象创建型模式
- 原型模式(Prototype)与Delphi对象克隆技术
- java设计模式---prototype(原型)模式