《大话设计模式》阅读笔记和总结。原书是C#编写的,本人用Java实现了一遍,包括每种设计模式的UML图实现和示例代码实现。
目录:设计模式
Github地址:DesignPattern
说明
定义:原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
UML图:
代码实现:
原型类
我们这里使用java api中Cloneable接口
具体原型类
class ConcretePrototype1 implements Cloneable{
private String id;
public ConcretePrototype1(String id){
this.id = id;
}
public String getId(){
return id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
客户端代码
public class PrototypePattern {
public static void main(String[] args) throws CloneNotSupportedException {
ConcretePrototype1 p1 = new ConcretePrototype1("I");
ConcretePrototype1 c1 = (ConcretePrototype1) p1.clone();
System.out.println("Cloned():"+c1.getId());
}
}
运行结果
Cloned():I
示例
例子:用程序模拟写简历,要求有一个简历类,必要有姓名,可以设置性别和年龄,可以设置工作经历,最终需要三份简历。
UML图:
代码实现:
工作经历类
public class WorkExperence implements Serializable {
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
简历类
public class Resume implements Cloneable,Serializable{
private String name;
private String sex;
private int age;
private WorkExperence workExperence;
public Resume(){
workExperence = new WorkExperence();
}
public void display() {
System.out.println(this.getName() + " " + this.getSex() + " "
+ this.getAge() + "\n工作经历: "
+ this.getWorkExperence().getWorkDate() + " "
+ this.getWorkExperence().getCompany());
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public WorkExperence getWorkExperence() {
return workExperence;
}
public void setWorkExperence(String workDate,String company) {
workExperence.setCompany(company);
workExperence.setWorkDate(workDate);
}
}
客户端调用
public class Main {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
copy();
}
public static void copy() throws CloneNotSupportedException {
Resume resumeA = new Resume();
resumeA.setName("大鸟");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.clone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.clone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
}
运行结果
大鸟 男 25
工作经历: 2017-2018 C公司
大鸟 男 25
工作经历: 2017-2018 C公司
大鸟 男 25
工作经历: 2017-2018 C公司
我们发现,设置的工作经历并没有正确的显示。原因是:如果复制的字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象,因此原始对象及其复本引用同一对象。
深拷贝实现
UML图:
代码实现:
简历类增加deepClone()方法
public class Resume implements Cloneable,Serializable{
// ……
public Object deepClone() throws IOException, ClassNotFoundException {
// 将对象写入流内
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 从流内读出对象
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
return ois.readObject();
}
}
客户端代码
public class Main {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
copy();
System.out.println("==============");
deepCopy();
}
public static void copy() throws CloneNotSupportedException {
Resume resumeA = new Resume();
resumeA.setName("大鸟");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.clone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.clone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
public static void deepCopy() throws IOException, ClassNotFoundException {
Resume resumeA = new Resume();
resumeA.setName("大鸟");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.deepClone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.deepClone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
}
运行结果:
大鸟 男 25
工作经历: 2017-2018 C公司
大鸟 男 25
工作经历: 2017-2018 C公司
大鸟 男 25
工作经历: 2017-2018 C公司
==============
大鸟 男 25
工作经历: 2015-2016 A公司
大鸟 男 25
工作经历: 2016-2017 B公司
大鸟 男 25
工作经历: 2017-2018 C公司