遍历异构集合:无需instanceof访问ThingId专属方法可行吗?
当然可以!其实这正是多态设计的核心场景,我们完全能摆脱instanceof的束缚,写出更干净、易扩展的代码。下面给你两种常用的解决方案,你可以根据场景选择:
1. 利用多态(推荐,日常开发最常用)
核心思路是给所有ThingId类型定义一个统一的接口,把“打印标识符”这类和自身类型强相关的逻辑,封装到各自的实现类里。这样调用的时候,根本不需要判断类型,直接调用通用方法就行。
先定义接口:
interface ThingId { // 通用方法:打印自身标识符 void printIdentifier(); }
然后实现具体的Id类,把专属逻辑放进去:
class ToyId implements ThingId { private String toyCode; public ToyId(String toyCode) { this.toyCode = toyCode; } @Override public void printIdentifier() { System.out.println("玩具ID: " + toyCode); // 这里可以直接调用ToyId的专属方法,比如校验编码格式 // validateToyCode(toyCode); } // ToyId的专属方法 private void validateToyCode(String code) { // 专属逻辑实现 } } class FruitId implements ThingId { private int fruitNumber; public FruitId(int fruitNumber) { this.fruitNumber = fruitNumber; } @Override public void printIdentifier() { System.out.println("水果ID: " + fruitNumber); // 这里可以直接调用FruitId的专属方法,比如查询对应品种 // getFruitVariety(fruitNumber); } // FruitId的专属方法 private String getFruitVariety(int number) { // 专属逻辑实现 return "苹果"; } }
然后Thing类只需要持有ThingId和重量,调用通用方法即可:
class Thing { private ThingId id; private double weight; public Thing(ThingId id, double weight) { this.id = id; this.weight = weight; } public void printDetails() { id.printIdentifier(); // 不需要instanceof,直接调用 System.out.println("重量: " + weight + "kg"); } }
使用的时候就非常清爽:
public class Main { public static void main(String[] args) { Thing toyCar = new Thing(new ToyId("TOY-CAR-001"), 0.8); Thing redApple = new Thing(new FruitId(1002), 0.4); toyCar.printDetails(); redApple.printDetails(); } }
2. 访问者模式(适合复杂场景)
如果你的ThingId类型特别多,而且后续可能要频繁新增不同的操作(不只是打印),那访问者模式会更合适。它把操作逻辑和数据结构分离,新增操作不需要修改ThingId的实现类,符合开闭原则。
首先定义访问者接口,对应每个ThingId类型的操作:
interface ThingIdVisitor { void visit(ToyId toyId); void visit(FruitId fruitId); }
修改ThingId接口,添加接受访问的方法:
interface ThingId { void accept(ThingIdVisitor visitor); }
实现具体的Id类,让它们接受访问者:
class ToyId implements ThingId { private String toyCode; public ToyId(String toyCode) { this.toyCode = toyCode; } // 暴露ToyId的专属属性/方法给访问者 public String getToyCode() { return toyCode; } @Override public void accept(ThingIdVisitor visitor) { visitor.visit(this); // 把自身传递给访问者 } // ToyId专属方法 public boolean isCollectible() { return toyCode.startsWith("TOY-COLLECT"); } } class FruitId implements ThingId { private int fruitNumber; public FruitId(int fruitNumber) { this.fruitNumber = fruitNumber; } // 暴露FruitId的专属属性/方法给访问者 public int getFruitNumber() { return fruitNumber; } @Override public void accept(ThingIdVisitor visitor) { visitor.visit(this); } // FruitId专属方法 public boolean isOrganic() { return fruitNumber >= 2000; } }
然后实现打印操作的访问者,在这里处理每个类型的专属逻辑:
class PrintDetailsVisitor implements ThingIdVisitor { private double weight; public PrintDetailsVisitor(double weight) { this.weight = weight; } @Override public void visit(ToyId toyId) { System.out.println("玩具ID: " + toyId.getToyCode()); // 直接调用ToyId的专属方法 if (toyId.isCollectible()) { System.out.println("这是一款收藏级玩具"); } System.out.println("重量: " + weight + "kg"); } @Override public void visit(FruitId fruitId) { System.out.println("水果ID: " + fruitId.getFruitNumber()); // 直接调用FruitId的专属方法 if (fruitId.isOrganic()) { System.out.println("这是有机水果"); } System.out.println("重量: " + weight + "kg"); } }
使用的时候:
public class Main { public static void main(String[] args) { Thing collectibleToy = new Thing(new ToyId("TOY-COLLECT-007"), 1.2); Thing organicApple = new Thing(new FruitId(2005), 0.5); collectibleToy.getId().accept(new PrintDetailsVisitor(collectibleToy.getWeight())); organicApple.getId().accept(new PrintDetailsVisitor(organicApple.getWeight())); } }
总结一下
- 如果只是简单的固定操作,多态方案最简洁,代码量少,容易维护。
- 如果需要频繁新增不同操作,访问者模式更灵活,避免修改原有类。
内容的提问来源于stack exchange,提问作者Bojan Vukasovic
相关产品推荐
相关产品推荐

