一、前言
今天我们来分享java设计模式中的原型模式。原型模式对于我自身而言,到目前为止我还没有见到过原型模式的应用(其实是因为自己道行太浅啦)。不过呢,虽然目前不会用到,但是我们还是需要了解什么是原型模式,以及原型模式的一些应用场景,以便于今后使用时做好准备。
合适使用场景:
1、复制对象的结构与数据。
2、希望对目标对象的修改不影响既有的对象。
3、创建成本较大的情况下
二、原型模式
原型模式的原理很简单,以前我们在创建两个或者多个相同的对象时,我们常常的做法就是使用new()这个方式来创建对象,但是如果创建是那些属性比较多的对象时,new()这种方式耗时耗力,而原型模式就是为了解决这种相同对象的创建问题。它的原理就是通过复制现有的实例来创建新的实例,无需知道类的信息。什么意思呢?意思就是说我们通过克隆这种方式来代替new()对象这种方式,我们在复制的时候不需要知道类的信息,只需要一个模板即可。其实现方式就是继实现一个Clonable这个接口,clone()方法中调用Object的clone()方法,在这里还有一个问题就是Object的clone()方法只能拷贝基本数据类型,所以这里又涉及到两个知识点,浅拷贝和深拷贝。这两个的区别就是前者只能实现基本数据类型的拷贝,后者可以对类中的引用数据类型进行拷贝(这个后面我们用代码解释可能会清晰的多)。
三、代码展示
3.1浅拷贝
浅拷贝只使用了Object的clone()方法,所以只能拷贝基本数据类型。这里为了演示方便,我重写了toString()方法,观看结果我们可以发现,我们复制了一个机器人的模板,当我们改变模板的基本数据类型时,克隆的对象基本数据类型不会发生改变,但当我们改变了模板中的引用数据类型时,克隆的对象也发生了改变。
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
public class Robot implements Cloneable{
private String name;
private String type;
private User user;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Robot(String name, String type, User user) {
super();
this.name = name;
this.type = type;
this.user = user;
}
@Override
public String toString() {
return "Robot [name=" + name + ", type=" + type + ", user=" + user + "]";
}
/**
* 浅克隆,只会复制基本数据类型,引用数据只能复制地址。
*/
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Test {
public static void main(String[] args) {
User user = new User("老五",30);
Robot robot =new Robot("将军","管家",user);
Robot cloneRobot = null;
try {
cloneRobot = (Robot)robot.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("模板"+robot);
System.out.println("复制"+cloneRobot);
System.out.println("--------------------------");
robot.setName("小老鼠");
user.setAge(5);
user.setName("小明");
System.out.println("模板"+robot);
System.out.println("复制"+cloneRobot);
}
}
结果展示:
模板Robot [name=将军, type=管家, user=User [name=老五, age=30]]
复制Robot [name=将军, type=管家, user=User [name=老五, age=30]]
--------------------------
模板Robot [name=小老鼠, type=管家, user=User [name=小明, age=5]]
复制Robot [name=将军, type=管家, user=User [name=小明, age=5]]
3.2 深克隆
深克隆其实就是对模板中的属性进行递归克隆,所以我们一般都会谨慎使用深克隆(其实我也不知道为啥,前辈都这么说的),我想可能是因为递归需要处理好,如果处理不好可能会复制成残缺或者多复制什么吧(自己个人想法)。在结果中我们可以看到,当我们修改了模板中的引用数据类型以后我们的克隆中的对象是不会发生变化的。
代码:在模板对象的clone()方法中,对引用数据类型再进行一次克隆,当然这个引用类型也要实现Cloneable这个接口
public class Robot implements Cloneable{
private String name;
private String type;
private User user;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Robot(String name, String type, User user) {
super();
this.name = name;
this.type = type;
this.user = user;
}
@Override
public String toString() {
return "Robot [name=" + name + ", type=" + type + ", user=" + user + "]";
}
/**
* 深克隆。
*/
@Override
protected Robot clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Robot robot =(Robot)super.clone();
robot.user = robot.user.clone();
return robot;
}
}
public class User implements Cloneable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
protected User clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return (User)super.clone();
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
结果展示:
模板Robot [name=将军, type=管家, user=User [name=老五, age=30]]
复制Robot [name=将军, type=管家, user=User [name=老五, age=30]]
--------------------------
模板Robot [name=小老鼠, type=管家, user=User [name=小明, age=5]]
复制Robot [name=将军, type=管家, user=User [name=老五, age=30]]