原型模式:
1.问题引入:(简历)
public class Test {
public static void main(String[] args) {
Resume a=new Resume("大鸟");
a.setPersonnalInfo("男", "29");
a.setWorkExperience("1998-2000","XX公司");
Resume b=new Resume("大鸟");
b.setPersonnalInfo("男", "29");
b.setWorkExperience("1998-2000","XX公司");
Resume c=new Resume("大鸟");
c.setPersonnalInfo("男", "29");
c.setWorkExperience("1998-2000","XX公司");
a.display();b.display();c.display();
}
}
//简历类
class Resume{
private String name;
private String sex;
private String age;
private String timeArea;
private String company;
public Resume(String name) {
this.name=name;
}
public void setPersonnalInfo(String sex,String age) {
this.sex=sex;
this.age=age;
}
public void setWorkExperience(String timeArea,String company) {
this.timeArea=timeArea;
this.company=company;
}
public void display() {
System.out.println(name+" "+sex+" "+age);
System.out.println("工作经历:"+timeArea+" "+company);
}
}
缺点:三份简历需要三次实例化,麻烦。
注:这里不能将客户端代码改为Resume b=a; 这是引用,一改都改。
2.改进:原型模式(浅复制)
用复制原型对象的方法创建出更多的同类型对象。
用到java.lang.Cloneable接口的clone()方法。
package computer;
public class Test {
public static void main(String[] args) {
Resume a=new Resume("大鸟");
a.setPersonnalInfo("男", "29");
a.setWorkExperience("1998-2000","XX公司");
Resume b=a.clone();
b.setWorkExperience("1998-2006","YY企业");
Resume c=a.clone();
c.setPersonnalInfo("男", "4");
a.display();b.display();c.display();
}
}
//简历类
class Resume implements Cloneable{
private String name;
private String sex;
private String age;
private String timeArea;
private String company;
public Resume(String name) {
this.name=name;
}
public void setPersonnalInfo(String sex,String age) {
this.sex=sex;
this.age=age;
}
public void setWorkExperience(String timeArea,String company) {
this.timeArea=timeArea;
this.company=company;
}
public void display() {
System.out.println(name+" "+sex+" "+age);
System.out.println("工作经历:"+timeArea+" "+company);
}
//克隆
public Resume clone() {
try {
return (Resume)super.clone();
}
catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
优点:修改简历只需要修改一份。不用每次都执行构造函数。
Clone()方法缺点:对于引用类型,只复制引用但不复制引用的对象(仍一改多改)。即“简历”类中若有对象引用,那么引用的对象数据不会被克隆。
3.简历类中有其他类的对象的情况:
package computer;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Resume a = new Resume("大鸟");
a.setPersonnalInfo("男", "29");
a.setWorkExperience("1998-2000", "XX公司");
Resume b = a.clone();
b.setWorkExperience("1998-2006", "YY企业");
Resume c = a.clone();
c.setWorkExperience("1998-2003", "ZZ企业");
a.display();
b.display();
c.display();
}
}
//工作经历类
class WorkExperience {
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public String getCompany() {
return company;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public void setCompany(String company) {
this.company = company;
}
}
//简历类
class Resume implements Cloneable {
private String name;
private String sex;
private String age;
// 工作经历类对象
private WorkExperience work = new WorkExperience();
public Resume(String name) {
this.name = name;
}
public void setPersonnalInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
public void setWorkExperience(String workDate, String company) {
work.setWorkDate(workDate);
work.setCompany(company);
}
public void display() {
System.out.println(name + " " + sex + " " + age);
System.out.println("工作经历:" + work.getWorkDate() + " " + work.getCompany());
}
// 克隆的另一种写法:
public Resume clone() throws CloneNotSupportedException {
return (Resume) super.clone();
}
}
出错原因:三个引用都指向了同一个对象。
4.改进:原型模式(深复制):
package computer;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Resume a = new Resume("大鸟");
a.setPersonnalInfo("男", "29");
a.setWorkExperience("1998-2000", "XX公司");
Resume b = a.clone();
b.setWorkExperience("1998-2006", "YY企业");
Resume c = a.clone();
c.setWorkExperience("1998-2003", "ZZ企业");
a.display();
b.display();
c.display();
}
}
//工作经历类
class WorkExperience implements Cloneable{
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public String getCompany() {
return company;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public void setCompany(String company) {
this.company = company;
}
public WorkExperience clone() {
try {
return (WorkExperience)super.clone();
}
catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
//简历类
class Resume implements Cloneable {
private String name;
private String sex;
private String age;
// 工作经历类对象
private WorkExperience work = new WorkExperience();
public Resume(String name) {
this.name = name;
}
public void setPersonnalInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
public void setWorkExperience(String workDate, String company) {
work.setWorkDate(workDate);
work.setCompany(company);
}
public void display() {
System.out.println(name + " " + sex + " " + age);
System.out.println("工作经历:" + work.getWorkDate() + " " + work.getCompany());
}
//深复制
public Resume clone() {
Resume r=new Resume(name);
r.sex=this.sex;
r.age=this.age;
r.work=this.work;
//this.work.clone()调用工作经历类的复制函数,工作经历类中没有引用的对象,可以避免复制引用的情况。即通过this.work.clone()复制出一个新的工作经历类对象a,再通过r.work=this.work.clone()让要复制出来的简历类对象中的工作经历类对象指向对象a。
r.work=this.work.clone();
return r;
}
}
5.原型模式的结构:
(浅复制为例):
package computer;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Resume a = new Resume("大鸟");
a.setPersonnalInfo("男", "29");
a.setWorkExperience("1998-2000", "XX公司");
Resume b = a.clone();
b.setWorkExperience("1998-2006", "YY企业");
Resume c = a.clone();
c.setWorkExperience("1998-2003", "ZZ企业");
a.display();
b.display();
c.display();
}
}
//抽象原型类
class Prototype implements Cloneable {
private String id;
public Prototype(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Prototype clonePrototype() {
return null;
}
}
//具体原型类1
class ConcretePrototype1 extends Prototype {
public ConcretePrototype1(String id) {
super(id);
}
// 返回值类型为父类类型原因:继承父类该函数,故返回值不变
public Prototype clonePrototype() {
try {
// 强制类型转换为父类类型原因:返回值类型为父类类型
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
//具体原型类2
class ConcretePrototype2 extends Prototype {
public ConcretePrototype2(String id) {
super(id);
}
// 返回值类型为父类类型原因:继承父类该函数,故返回值不变
public Prototype clonePrototype() {
try {
// 强制类型转换为父类类型原因:返回值类型为父类类型
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
原型模式一定程度上可以代替工厂模式:
工厂模式实现的生产产品的功能:生产的产品是由同一个抽象产品类派生出来的,即要生产一类产品就要引入一个抽象产品类,再由它派生出具体的几种产品。
原型模式中,可以同样定义“抽象产品-具体产品”的层次,再利用clone功能来产生具体产品本身来实现工厂模式的功能。即,原型模式中,每个具体的产品就扮演了工厂模式的具体工厂的角色(因为每个具体产品都具有生成自己拷贝的功能,这正是工厂的作用)。