Appearance
原型模式
定义
原型模式(Prototype Pattern)是指用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
使用场景
- 类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
- 新对象的创建复杂,通过原型拷贝可以简化创建过程,同时还能保证性能,因为原型拷贝不会执行类的构造函数。
- 集合类频繁地添加和删除元素,而新元素都是类似的对象。
优点
- 性能优良,原型拷贝是在内存中进行的,比直接new一个对象性能好很多。
- 简化创建过程,特别是创建复杂对象时,通过原型拷贝可以简化创建过程。
缺点
- 需要为每一个类配备一个克隆方法,这对全新的类来说不是问题,但对已有的类进行改造时,需要修改其源代码,违背了开闭原则。
- 深拷贝与浅拷贝需要自行控制,容易引入风险。
代码示例
编写一个怪物类,通过原型模式来创建新的怪物对象。
原型
怪物类
java
package com.design.pattern.prototype.one;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class Monster implements Cloneable{
private String name;
private int level;
private int hp;
private int attack;
private int defense;
private List<Skill> skills;
public Monster() {
String[] names = {
"幽灵", "野猪", "野狼", "野鸡", "野兔", "巨龙",
"暴猿", "通灵石猴", "野牛", "老虎", "蛮熊"
};
Random random = new Random();
this.name = names[random.nextInt(names.length)];
this.level = random.nextInt(10) + 1;
this.hp = random.nextInt(100) + 100;
this.attack = random.nextInt(20) + 10;
this.defense = random.nextInt(10) + 8;
String[] skillNames = {
"突击", "撕咬", "锤击", "冲撞", "致残打击", "嗜血", "附身", "尖啸", "拍击"
};
int size = random.nextInt(skillNames.length);
List<Skill> skills = new ArrayList<>();
for (int i = 0; i < size; i++) {
skills.add(new Skill(skillNames[random.nextInt(skillNames.length)], random.nextInt(10 + 2)));
}
this.skills = skills;
}
@Override
public Monster clone() {
try {
return (Monster) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefense() {
return defense;
}
public void setDefense(int defense) {
this.defense = defense;
}
public List<Skill> getSkills() {
return skills;
}
public void setSkills(List<Skill> skills) {
this.skills = skills;
}
@Override
public String toString() {
String format = "╭───────────────────────────────\n"+
"├怪物名称:%s\n"+
"├怪物等级:%d\n"+
"├怪物技能:%s\n"+
"├怪物生命值:%d\n"+
"├怪物攻击力:%d\n"+
"├怪物防御力:%d\n"+
"╰───────────────────────────────";
return String.format(format,
this.name,
this.level,
skills.stream().map(Skill::getName).collect(Collectors.joining(",")),
this.hp,
this.attack,
this.defense);
}
}
技能类
java
package com.design.pattern.prototype.one;
public class Skill implements Cloneable{
private String name;
private int level;
public Skill(String name, int level) {
this.name = name;
this.level = level;
}
@Override
public Skill clone() {
try {
return (Skill) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
}
客户端
java
package com.design.pattern.prototype.one;
import java.util.ArrayList;
import java.util.Collections;
public class Client {
public static void main(String[] args) {
Monster monster = new Monster();
System.out.println(monster.toString());
Monster clone = monster.clone();
clone.setName("蜘蛛精");
clone.setSkills(new ArrayList<>(Collections.singletonList(new Skill("蛛丝", 10))));
System.out.println(clone.toString());
}
}
运行结果
txt
╭───────────────────────────────
├怪物名称:幽灵
├怪物等级:7
├怪物技能:锤击,冲撞,致残打击,嗜血,锤击,撕咬,突击,拍击
├怪物生命值:156
├怪物攻击力:13
├怪物防御力:14
╰───────────────────────────────
╭───────────────────────────────
├怪物名称:蜘蛛精
├怪物等级:7
├怪物技能:蛛丝
├怪物生命值:156
├怪物攻击力:13
├怪物防御力:14
╰───────────────────────────────