公司做游戏了
小明的公司赚的钱越来越多了,他们开始尝试新的机会,公司觉得游戏是一个不错的选择,所以公司准备做游戏了
小明负责游戏中的一个模块,这个模块是负责设计游戏中的各种小怪角色,小明拿觉得这个很简单啊,于是根据游戏策划对小怪的设计,开始写代码了:
class Monster {
String color;
int healthValue;
public Monster(String color, int healthValue) {
this.color = color;
this.healthValue = healthValue;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getHealthValue() {
return healthValue;
}
public void setHealthValue(int healthValue) {
this.healthValue = healthValue;
}
}
生成怪兽并使用
public class Client {
public static void main(String[] args) {
Monster monster = new Monster("green", 100);
int i = 1;
while (i < 10) {
if (i % 2 == 0)
monster.setColor("red");
else
monster.setColor("blue");
monster.setHealthValue(i * 200);
System.out.print(monster);
i++;
}
}
}
主管说,你现在只实例化了10个怪兽,我现在需要100万个小怪兽,让游戏有一种特殊的效果,你的方式还可以吗?小明想了一下,如果100万个的话,这样效率太低了,小明想那我们用多线程吧,主管说,多线程就必须每次都生成新的对象,不能像上面那样共用一个对象,这又是一笔额外的开支,所以我们想想可以在生成对象的时候提高一下效率吗?小明问,可以吗?主管说,当然,这种情况我们使用原型模式再适合不过了,我们改造一下Monster:
public class Monster implements Cloneable {
String color;
int healthValue;
public Monster(String color, int healthValue) {
this.color = color;
this.healthValue = healthValue;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getHealthValue() {
return healthValue;
}
public void setHealthValue(int healthValue) {
this.healthValue = healthValue;
}
@Override
protected Object clone(){
Monster monster = null;
try {
monster = (Monster) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return monster;
}
}
可以看到,我们的Monster实现了Cloneable接口,并重载了clone()方法,然后我们使用新的怪兽类
public class Client {
public static void main(String[] args) {
Monster monster = new Monster("green", 100);
int i = 1;
while (i <= 1000000) {
Monster cloneMonster = monster.clone();
if (i % 2 == 0)
cloneMonster.setColor("red");
else
cloneMonster.setColor("blue");
cloneMonster.setHealthValue(i * 200);
System.out.print(cloneMonster);
i++;
}
}
}
可以看到,我们用了clone方法来生成新的对象,这样做有什么好处呢,如果之前那种方式在我们的while中有耗时操作的话,实例化的过程效率很低,如果我们实现Cloneable接口,我们可以通过clone方法来生成对象,它是一个本地方法,直接在内存中再复制一份我们对象的二进制生成一个新的对象,而不是通过再使用构造函数去生成,这样效率会提升很多。所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多
原型模式
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象
使用原型模式的注意事项
使用原型模式复制对象不会调用类的构造方法
因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。还记得单例模式吗?单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意
深拷贝与浅拷贝
浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝,然后一直基本数据类型会被拷贝
深拷贝
被拷贝对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍
明白了深拷贝和浅拷贝,我们在使用clone方法的时候就必须注意,因为默认的clone方法是浅拷贝,对于一些引用对象不会拷贝为新的对象,所以在需要时,我们必须对对象引用再做一次拷贝:
public class Monster implements Cloneable {
String color;
int healthValue;
ArrayList<String> skills;
@Override
protected Monster clone() {
Monster monster = null;
try {
monster = (Monster) super.clone();
monster.skills = (ArrayList<String>) this.skills.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return monster;
}
}
深拷贝与浅拷贝问题中,会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝