大家好,欢迎来到IT知识分享网。
案例背景
假设我们有一个游戏系统,游戏中需要频繁创建 敌人对象。每个敌人对象包含以下属性:
- 名称(name)
- 血量(health)
- 攻击力(attackPower)
- 防御力(defensePower)
敌人的初始属性是通过配置文件加载的,创建敌人对象时需要从配置文件中读取数据并初始化。
代码实现
敌人类:Enemy
@Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Enemy { / * 名称 */ private String name; / * 血量 */ private int health; / * 攻击力 */ private int attackPower; / * 防御力 */ private int defensePower; @Override public String toString() { return "{" + "name='" + name + '\'' + ", health=" + health + ", attackPower=" + attackPower + ", defensePower=" + defensePower + '}'; } }
数据来源加载类
/ * 从配置信息中加载敌人信息 */ public class EnemyConfig { public static Enemy loadEnemyFromConfig() { // 模拟数据由配置文件 或 数据库加载 return new Enemy("暗黑巨魔", 100, 10, 5); } }
测试代码
public class EnemyTest { @Test public void getEnemy() { // 第一次获取敌人对象 加载数据 Enemy enemyA = EnemyConfig.loadEnemyFromConfig(); // 第二次获取敌人对象 加载数据 Enemy enemyB = EnemyConfig.loadEnemyFromConfig(); System.out.println("敌军一号: " + enemyA); System.out.println("敌军二号: " + enemyB); } }
存在的问题
- 重复初始化:
- 每次创建敌人对象时,都需要从配置文件中加载数据并初始化,导致重复的 I/O 操作和初始化逻辑。
- 性能问题:
- 如果配置文件加载过程耗时较长(如读取数据库或远程接口),频繁创建敌人对象会导致性能下降。
- 代码冗余:
- 初始化逻辑分散在多个地方,难以维护和扩展。
原型模式重构
1. 原型模式的主要内容
定义
原型模式是一种 创建型设计模式,它通过复制现有对象来创建新对象,而不是通过调用构造函数。原型模式的核心思想是 克隆。
核心角色
- 原型接口(Prototype):
- 定义克隆方法的接口。
- 具体原型(Concrete Prototype):
- 实现原型接口,提供克隆方法的具体实现。
- 客户端(Client):
- 使用原型对象创建新对象。
2. 使用场景
原型模式适用于以下场景:
- 对象创建成本高:
- 当对象的创建过程非常复杂或耗时,且需要频繁创建相似对象时。
- 例如:数据库连接、线程池。
- 对象状态相似:
- 当需要创建的对象与现有对象状态相似时。
- 例如:游戏中的敌人、文档模板。
- 避免构造函数调用:
- 当希望避免调用构造函数来创建对象时。
- 例如:某些构造函数参数复杂或不可控。
3. 使用原型模式进行重构
重构思路
- 定义原型接口:
- 让 Enemy 类实现 Cloneable 接口,支持克隆。
- 实现克隆方法:
- 在 Enemy 类中实现 clone() 方法,复制现有对象的属性。
- 使用原型对象:
- 从配置文件中加载一个原型对象,后续通过克隆原型对象来创建新对象。
重构后的代码
敌人类:Enemy(实现 Cloneable 接口)
@Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Enemy implements Cloneable { / * 名称 */ private String name; / * 血量 */ private int health; / * 攻击力 */ private int attackPower; / * 防御力 */ private int defensePower; @Override public Enemy clone() { try { return (Enemy) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("对象拷贝异常: ", e); } } @Override public String toString() { return "{" + "name='" + name + '\'' + ", health=" + health + ", attackPower=" + attackPower + ", defensePower=" + defensePower + '}'; } }
数据来源加载类
/ * 从配置信息中加载敌人信息 */ public class EnemyConfig { public static Enemy loadEnemyFromConfig() { // 模拟数据由配置文件 或 数据库加载 return new Enemy("暗黑巨魔", 100, 10, 5); } }
客户端代码
public class EnemyTest { @Test public void getEnemy() { // 第一次获取敌人对象 加载数据 Enemy enemyA = EnemyConfig.loadEnemyFromConfig(); Enemy enemyB = enemyA.clone(); System.out.println("敌军一号: " + enemyA); System.out.println("敌军二号: " + enemyB); } }
重构后的优势
- 减少初始化成本:
- 只需要从配置文件中加载一次原型对象,后续通过克隆创建新对象,避免了重复的 I/O 操作和初始化逻辑。
- 提升性能:
- 克隆操作比从配置文件加载数据更快,显著提升了性能。
- 代码更简洁:
- 初始化逻辑集中在原型对象中,客户端代码更简洁、更易维护。
4. 开源项目中的应用
长话短说
1、核心思想
- 克隆代替创建:通过复制现有对象来创建新对象,而不是通过调用构造函数。
- 减少创建成本:避免重复执行复杂的初始化逻辑。
2、何时可以使用原型模式?
- 对象的创建成本高(如需要从配置文件或数据库加载数据)。
- 需要频繁创建相似对象。
- 希望避免重复的初始化逻辑。
3、使用思路
- 定义原型接口:
- 定义克隆方法的接口。
- 例如:Cloneable 接口。
- 实现具体原型:
- 实现原型接口,提供克隆方法的具体实现。
- 例如:实现 Cloneable 接口的类。
- 客户端使用原型:
- 使用原型对象创建新对象。
- 例如:调用 clone() 方法复制对象。
设计模式是好东西,用对了项目好维护。但别硬套,不然设计过度,浪费成本。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/175195.html