
在面向对象编程中,为具有继承关系的实体生成唯一标识符是一个常见需求。本教程将解决一个具体场景:需要为Item及其子类(如CommercialFlight、IndustrialFlight、Person、Cargo)生成9位长的唯一ID。这些ID的生成规则如下:
初始尝试可能是在父类构造器中使用this instanceof Subclass来判断类型并分配ID。然而,这种方法存在明显缺陷:局部变量(如commercialID)在每次构造器调用时都会被重新初始化,无法实现全局递增。即使将这些变量声明为static,也需要为每种类型维护一个独立的静态计数器,并且在父类中通过instanceof进行类型判断,这违反了开闭原则,每次新增子类都需要修改父类代码。
为了实现一个健壮、可扩展的解决方案,我们将采用以下设计原则:
Item类作为所有具体物品的抽象基类,负责定义ID生成的核心逻辑。它将包含一个静态变量来跟踪全局序列,以及一个抽象方法来获取子类特定的ID前缀。
立即学习“Java免费学习笔记(深入)”;
public abstract class Item {
protected int id; // 存储生成的ID
protected static int lastGeneratedId = 0; // 静态变量,用于生成ID的后8位,全局唯一递增
/**
* Item类的构造器,负责生成并组装唯一ID。
* 每次创建Item的子类实例时,都会调用此构造器。
*/
protected Item() {
// 递增全局计数器,确保后8位数字的唯一性
lastGeneratedId++;
// 组装ID:(前缀 * 100,000,000) + 后8位序列号
// 例如:前缀为1,序列号为0,则ID为 1 * 100,000,000 + 0 = 100,000,000
// 前缀为3,序列号为1,则ID为 3 * 100,000,000 + 1 = 300,000,001
this.id = 100000000 * getIdPrefix() + lastGeneratedId;
System.out.println(toString()); // 打印创建的Item及其ID
}
/**
* 抽象方法,强制子类实现,以提供其特有的ID前缀。
*
* @return 该Item类型对应的ID首位数字。
*/
protected abstract int getIdPrefix();
@Override
public String toString() {
return "New " + getClass().getName() + " created with id " + id;
}
}代码解析:
为了更好地组织类层次结构,我们引入了两个中间抽象类:Flight和Payload。它们继承自Item,并各自作为不同类型物品的基类。
// Flight类,作为所有飞行器类型的抽象基类
public abstract class Flight extends Item {
public Flight() {
super(); // 调用父类Item的构造器,完成ID生成
}
}
// Payload类,作为所有载荷类型的抽象基类
public abstract class Payload extends Item {
public Payload() {
super(); // 调用父类Item的构造器,完成ID生成
}
}这些中间抽象类本身不提供getIdPrefix()的实现,因为它们仍然是抽象的。它们的主要作用是构建更清晰的继承体系。
现在,我们来创建具体的子类。每个子类都必须实现getIdPrefix()方法,返回其对应的ID前缀。
public class CommercialFlight extends Flight {
public CommercialFlight() {
super(); // 调用父类Flight的构造器,最终会调用Item的构造器
}
@Override
protected int getIdPrefix() {
return 1; // 商业航班的ID前缀为1
}
}public class IndustrialFlight extends Flight {
public IndustrialFlight() {
super(); // 调用父类Flight的构造器
}
@Override
protected int getIdPrefix() {
return 2; // 工业航班的ID前缀为2
}
}public class Person extends Payload {
public Person() {
super(); // 调用父类Payload的构造器
}
@Override
protected int getIdPrefix() {
return 3; // 人员的ID前缀为3
}
}public class Cargo extends Payload {
public Cargo() {
super(); // 调用父类Payload的构造器
}
@Override
protected int getIdPrefix() {
return 4; // 货物的ID前缀为4
}
}代码解析:
为了验证ID生成机制的正确性,我们可以创建一个测试类来实例化不同类型的Item。
public class ItemTester {
public static void main(String[] args) {
System.out.println("--- 开始创建Item实例 ---");
new Cargo(); // ID前缀4, 序列号1
new IndustrialFlight(); // ID前缀2, 序列号2
new Cargo(); // ID前缀4, 序列号3
new CommercialFlight(); // ID前缀1, 序列号4
new IndustrialFlight(); // ID前缀2, 序列号5
new Person(); // ID前缀3, 序列号6
new Person(); // ID前缀3, 序列号7
System.out.println("--- Item实例创建完毕 ---");
}
}预期输出:
--- 开始创建Item实例 --- New Cargo created with id 400000001 New IndustrialFlight created with id 200000002 New Cargo created with id 400000003 New CommercialFlight created with id 100000004 New IndustrialFlight created with id 200000005 New Person created with id 300000006 New Person created with id 300000007 --- Item实例创建完毕 ---
从输出可以看出,ID的前缀正确地反映了类型,而后缀(后8位数字)则在所有Item实例之间保持了全局递增,完全符合设计要求。
通过上述实现,我们成功地构建了一个灵活且可扩展的唯一ID生成系统。
这种设计模式在处理具有相似行为但特定属性不同的对象集合时非常有用。它体现了面向对象编程中继承、多态和封装的强大组合,使得系统结构清晰,维护和扩展都更为便捷。
注意事项:
以上就是Java中基于继承体系的唯一ID生成策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号