原型模式
原型模式主要用于对对象的复制,通过已有对象的属性在生成一个新的对象,在java中有个接口是Cloneable 主要通过代码来讲解
public class User {
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public User(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
这是简单的User类
public static void main(String[] args){
User user1=new User("小明",15);
User user2=new User("小明",15);
System.out.println(user1.toString());
System.out.println(user1.toString());
}
User [age=15, name=小明]
User [age=15, name=小明]
这是我们可能会做的较为简单做法 new 出两个对象,上面是他们打印的结果,对于当前两个对象他们的内部属性是一样的 在看看我们用实现了Cloneable 接口有什么区别
public class User implements Cloneable{
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public User(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public static void main(String[] args){
User user1=new User("小明",15);
System.out.println(user1.toString());
User user2 = null;
try {
user2 = (User) user1.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(user2.toString());
}
```
User [age=15, name=小明]
User [age=15, name=小明]
看上去好像new 出两个对象 和让对象实现clone 的接口效果是一样的 那么为什么有这样的设计模式。设想一下这样的场景,客户端 获取到服务器的客户信息,因为是唯一性,不能对其任意修改 ,即我们User对象第一次new 出来 就不能随意修改,尽量在其他模块获取 的是User对象的clone之后的对象,对于要必须要修改如网络请求完成你对用户修改,采用单例设计模式获取在修改,其他模块非必要修改可用原型模式获取数据避免了对原数据可能的误操作,你也可以说我就要new 对象 在对象的构造方法里面传递一个User 对象,然后把User对象的属性赋值给新的User对象,那我也不好说什么- -
如果了解过原型模式的人都知道 拷贝分为浅拷贝和深拷贝, 那什么是浅拷贝,什么是深拷贝,是什么场景需要用到深拷贝那,看下面的例子
public class User implements Cloneable{
public Game getmGame() {
return mGame;
}
public void setmGame(Game mGame) {
this.mGame = mGame;
}
@Override
public String toString() {
return "User [age=" + age + ", mGame=" + mGame + ", name=" + name + "]";
}
private String name;
private int age;
private Game mGame;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public User(String name,int age,Game mGame){
this.name=name;
this.age=age;
this.mGame=mGame;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Game {
private String name;
public Game(String name){
this.name=name;
}
public String getGame(){
return name;
}
@Override
public String toString() {
return "Game [name=" + name + "]";
}
public void setGame(String name){
this.name=name;
}
}
public static void main(String[] args){
Game game=new Game("LOL");
User user1=new User("小明",15,game);
User user2 = null;
try {
user2 = (User) user1.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
user2.getmGame().setGame("DATA");
user2.setAge(2);
System.out.println(user2.toString());
System.out.println(user1.toString());
}
User [age=2, mGame=Game [name=DATA], name=小明]
User [age=15, mGame=Game [name=DATA], name=小明]
我们在User对象中加入了一个新的对象Game,当我们修改User1中的Game属性
user2 居然变了,但是我们修改了user1中age的字段 但是user2没变,
说明了拷贝后的user2 复制了user1对象中的字段属性,对于user1中的引用,user2也持有,**我们使用原型模式 就是希望获取 User对象中的信息,但是同时我们不希望改变他(指的是自己代码可能写错了影响到了原始User对象的信息)** 接下来可以回到我们刚才的浅拷贝和深拷贝的区别,浅拷贝只是拷贝字段属性,而深拷贝会拷贝引用,解决办法
重写User对象中 clone的方法
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
User u=(User) super.clone();
u.mGame=(Game) u.mGame.clone();
return u;
}
然后让Game 类实现 Cloneable 接口,结果就实现了深拷贝
User [age=2, mGame=Game [name=DATA], name=小明]
User [age=15, mGame=Game [name=LOL], name=小明]
总结
在开发中为了尽量避免副本对原始的数据的修改,尽量都使用深引用
使用原型模式的优点
原型模式是在内存中的二进制的拷贝,要比直接new一个对象要好得多,如果你写一个for循环生成对象,显然前者更能体现好处
缺点:
因为是在内存中的拷贝,构造函数是不会执行的,在开发中需要注意这个问题
736

被折叠的 条评论
为什么被折叠?



