定义
原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式实际上就是从一个对象创建另一个新的对象,使新的对象有具有原对象的特征,期间创建细节无需知道。
结构图
image.png简单理解,就是实现clone接口,复制对象。浅复制有很大局限性,最好能够实现深复制。
深复制和浅复制
-
浅复制(shallow clone),浅拷贝是指拷贝对象时仅仅拷贝对象本身和对象中的基本变量,而不拷贝对象包含的引用指向的对象。
-
深复制(deep clone),深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
举例区别一下:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。
- 在Java中只要实现Cloneable接口就可以了。并且提供了默认的clone方法。不过这个方法是protected的。
@NonNull
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
- 对于基本类型,直接用这个默认的就可以了,不需要任何动作。不过对于自定义类嵌套的情况,由于默认是“浅复制”,所以要达到“深复制”的效果,一些内部成员的类就需要修改为public的,并且要重写clone方法,也需要实现Cloneable接口。
@NonNull
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
适用环境
-
创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其属性稍作修改。
-
系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。相反,如果对象的状态变化很大,或者对象占用的内存很大,那么采用状态模式会比原型模式更好。
-
需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。
简历的例子
- 工作经历作为一个成员变量的类,也要实现Cloneable接口:
class WorkExperience implements Cloneable {
public String workDate = null;//工作时间
public String company = null;//工作的公司名称
@NonNull
@Override
public Object clone() throws CloneNotSupportedException {
return (WorkExperience)super.clone();
}
}
- 简历类,使用clone复制。
class Resume implements Cloneable {
@NonNull
@Override
public Object clone() throws CloneNotSupportedException {
Resume obj = (Resume)super.clone();
obj.work = (WorkExperience)this.work.clone();
return obj;
}
//自身名字
private String name;
//性别
private String sex;
//年龄
private String age;
//自己的之前的工作经验
private WorkExperience work;
//构造函数 新建这个建立模板的实例时传入利用这个简历模板的人的名字
//并新建一个工作经验的实例
public Resume(String name) {
this.name = name;
work = new WorkExperience();
}
//供Bob复制Tom的简历时用于修改名字把自己的名字替换tom时调用
public void setName(String name) {
this.name = name;
}
//供调用这个模板的人书写自己的信息
//供Bob复制Tom的简历时用于修改名字把自己的名字替换tom时调用
public void setPersonalInfo(String sex, String age) {
this.age = age;
this.sex = sex;
}
//供调用这个模板的人书写自己工作的信息
//供Bob复制Tom的简历时用于修改工作调用
public void setWorkExperience(String workDate, String company) {
work.workDate = workDate;
work.company = company;
}
// 显示
public String display() {
String message = "姓名:" + name + "\n" +
"性别:" + sex + "\n" +
"年龄:" + age + "\n" +
"工作经历:" + work.workDate + "===" + work.company;
Log.v("Resume", message);
return message;
}
}
- 测试界面:
- 客户端代码:
public class PrototypeActivity extends AppCompatActivity {
public static void launch(Context context) {
if (null != context) {
Intent intent = new Intent();
intent.setClass(context, PrototypeActivity.class);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
}
TextView displayView;
Resume xiaoCai;
Resume xiaoCaiCopy;
Resume daNiao;
Resume daNiaoCopy1;
Resume daNiaoCopy2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_prototype);
setTitle("原型模式");
displayView = findViewById(R.id.display);
xiaoCai = new Resume("小菜");
xiaoCai.setPersonalInfo("男", "24");
xiaoCai.setWorkExperience("2000-2002", "学校软件公司");
try {
xiaoCaiCopy = (Resume) xiaoCai.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
try {
daNiao = (Resume) xiaoCai.clone();
daNiao.setName("大鸟");
daNiao.setPersonalInfo("男","28");
daNiao.setWorkExperience("2004-2005", "XX公司");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
try {
daNiaoCopy1 = (Resume) daNiao.clone();
daNiaoCopy1.setWorkExperience("2006-2008", "YY公司");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
try {
daNiaoCopy2 = (Resume) daNiao.clone();
daNiaoCopy2.setWorkExperience("2010-2011", "ZZ公司");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
public void onXiaoCaiClick(View view) {
displayView.setText(xiaoCai.display());
}
public void onXiaoCaiCopyClick(View view) {
displayView.setText(xiaoCaiCopy.display());
}
public void onDaNiaoClick(View view) {
displayView.setText(daNiao.display());
}
public void onDaNiaoCopy1Click(View view) {
displayView.setText(daNiaoCopy1.display());
}
public void onDaNiaoCopy2Click(View view) {
displayView.setText(daNiaoCopy2.display());
}
}
Demo地址
https://gitee.com/zhangxusong888/Android/tree/master/design_pattern
网友评论