共计 3840 个字符,预计需要花费 10 分钟才能阅读完成。
一、原型模式介绍
1. 解决的问题
次要解决的问题就是创立反复对象,这部分对象内容自身比较复杂,生成过程可能从库中或者 RPC 接口中获取数据的耗时较长,因而采纳克隆的形式节省时间。
2. 定义
原型模式是一种创立型模式,可能复制已有对象,而又无需使代码依赖它们所属的类。
3. 利用场景
- 对象的初始化须要很多其余对象的数据筹备或其余资源的繁琐计算。
- 须要复制一些对象,同时又心愿代码独立于这些对象所属的具体类。
这种场景通常呈现在代码须要解决第三方代码通过接口传递过去的对象时。即便不思考代码耦合的状况,咱们的代码也不能依赖这些对象所属的具体类,因为不晓得其具体信息。
原型模式为咱们的代码提供了一个通用接口,咱们能够通过这一接口与所有实现了克隆的对象进行交互,使得咱们的代码与所克隆的对象具体类独立开。
- 子类的区别仅在于其对象的初始化形式,能够应用原型模式来缩小子类的梳理。
创立这些子类的目标可能只是为了创立特定类型的对象。
原型模式已与 Java 融为一体,能够顺手拿来应用:
Object
的clone()
办法。Cloneable
接口的实现类,至多能够看到一千多个实现。
4. 浅拷贝与深拷贝
在 Java 中,数据类型分为值类型和援用类型,值类型 包含 int、double、byte、boolean、char 等根本数据类型,援用类型 包含类、接口、数组等简单类型。
浅拷贝与深拷贝的次要区别在于 是否反对援用类型的成员变量的复制。
- 浅拷贝
在浅拷贝中,若原型对象的成员变量是值类型,将复制给克隆对象;若原型对象的成员变量是援用类型,则将援用对象的地址复制一份给克隆对象,即原型对象和克隆对象的成员变量指向雷同的内存地址。
简略来说,在浅拷贝中,对象被复制时 只复制其自身和其蕴含的值类型的成员变量 ,而 援用类型的成员对象并没有复制。
在 Java 中,通过笼罩
Object
类的clone()
办法即可实现浅拷贝。 -
深拷贝
在深拷贝中,无论原型变量的成员变量是值类型还是援用类型,都将复制给克隆对象。
简略来说,在深拷贝中,除了对象自身被复制外,对象所蕴含的所有成员变量也将复制。
在 Java 中,实现深克隆,能够通过复制援用对象或序列化读取二进制流等形式实现,须要留神的是,可能序列化的对象必须实现
Serializable
接口。实现
Serializable
读取二进制流示例:protected Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException { // 将对象写入流中 ByteArrayOutputStream bao = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bao); oos.writeObject(this); // 将对象从流中取出 ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (ois.readObject()); }
二、原型模式优缺点
1. 长处
- 能够克隆对象,而无需与其所属的具体类相耦合。
- 能够克隆生成原型,防止重复运行初始化代码。
- 能够更不便的生成简单对象。
- 能够应用继承以外的形式来解决简单对象的不同配置。
2. 毛病
- 克隆蕴含循环援用的简单对象可能会十分麻烦。
三、原型模式利用实例:英雄联盟齐天大圣 - 虚实猴王
1. 实例场景
英雄联盟中有一个英雄叫齐天大圣 · 孙悟空,这个名字想必咱们都很相熟,而在英雄联盟中,它的人物背景是这样的:
悟空是一个瓦斯塔亚族的机灵鬼,用本人的力量、灵活和机智蛊惑对手并抢得先机。机缘巧合让他结识了一位剑客并与之成为毕生的挚友,这位剑客被人称作易巨匠。起初,悟空就成为了古老武术门派“无极”的最初一位弟子。现在,附魔长棍傍身的悟空,指标是让艾欧尼亚免遭解体的命运。
“我的游记才刚刚开始……”——齐天大圣 · 孙悟空
齐天大圣 · 孙悟空有一个技能叫做虚实猴王:
孙悟空进入继续 1 秒的隐形状态并朝着一个方向突进 300 间隔(不能越过墙体),同时留下一个会攻打左近敌人的分身。
孙悟空的分身会模拟孙悟空的普通攻击和终极技能,然而仅造成 35/40/45/50/55% 挫伤。
明天咱们就应用发明孙悟空的分身作为模仿场景。
2. 原型模式实现
2.1 工程构造
builder-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.prototype
│ ├─ model
│ │ ├─ Hero.java
│ │ └─ WuKong.java
└─ test
└─ java
└─ org.design.pattern.prototype.test
└─ WuKongTest.java
2.2 代码实现
英雄基类
/**
* 英雄基类
*/
@Getter
@Setter
@NoArgsConstructor
public abstract class Hero {
/**
* 生命值
*/
protected int healthPoint;
/**
* 法力值
*/
protected int magicPoint;
/**
* 物理挫伤
*/
protected int attackDamage;
/**
* 法术挫伤
*/
protected int abilityPower;
public Hero(Hero hero) {if (hero != null) {
this.healthPoint = hero.healthPoint;
this.magicPoint = hero.magicPoint;
this.attackDamage = hero.attackDamage;
this.abilityPower = hero.abilityPower;
}
}
public abstract Hero clone();
/**
* 攻打
*/
public void attach() {System.out.printf("This hero’s attack caused %d damage", this.attackDamage);
System.out.println();}
}
齐天大圣 · 孙悟空
/**
* 齐天大圣孙悟空
*/
@Getter
@Setter
@NoArgsConstructor
public class WuKong extends Hero {
/**
* 物理挫伤比例
*/
protected float attackDamageProportion = 1;
public WuKong(WuKong wuKong) {super(wuKong);
if (wuKong != null) {
this.healthPoint = wuKong.healthPoint;
this.magicPoint = wuKong.magicPoint;
this.attackDamage = (int) (wuKong.attackDamage * wuKong.attackDamageProportion);
this.abilityPower = wuKong.abilityPower;
}
}
@Override
public WuKong clone() {return new WuKong(this);
}
/**
* 攻打
*/
public void attach() {super.attach();
}
}
2.3 测试验证
2.3.1 测试验证类
public class WuKongTest {
@Test
public void testWuKong() {
// 齐天大圣孙悟空
WuKong wuKong = new WuKong();
wuKong.setHealthPoint(540);
wuKong.setMagicPoint(300);
wuKong.setAttackDamage(68);
wuKong.setAbilityPower(54);
// 复制孙悟空分身
wuKong.setAttackDamageProportion(0.3f);
WuKong fakeKong = wuKong.clone();
System.out.println("孙悟空攻打:");
wuKong.attach();
System.out.println("孙悟空分身攻打:");
fakeKong.attach();}
}
2.3.2 测试后果
孙悟空攻打:This hero’s attack caused 68 damage
孙悟空分身攻打:This hero’s attack caused 20 damage
四、原型模型构造
- 原型 (Prototype)接口将对克隆办法进行申明。在绝大多数状况下,其中只会有一个名为
clone
克隆的办法。 - 具体原型(Concrete Prototype)类将实现克隆办法。除了将原始对象的数据复制到克隆体中之外,该办法有时还需解决克隆过程中的极其状况,例如克隆关联对象和梳理递归依赖等等。
- 客户端(Client)能够复制实现了原型接口的任何对象。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/d…
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei…
深刻设计模式:https://refactoringguru.cn/de…