You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遍历异构集合:无需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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:41:28