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

使用访问者模式替代类型转换:优化冗余代码方案问询

优化访问者模式的返回值获取,减少样板代码

我太理解这种困扰了——用访问者模式本来是为了避开instanceof和强制类型转换的坏味道,结果为了获取一个简单的返回值,却要写一堆绕来绕去的样板代码,完全违背了使用这个模式的初衷。针对你的需求,我整理了几种更简洁的优化方案,既能保持访问者模式的类型安全,又能大幅减少冗余代码:

方案1:封装泛型访问者+静态工厂方法

首先,我们把访问者接口改成支持返回Optional<T>的泛型接口,然后在工具类里封装好常用的类型收集逻辑,避免每次都写匿名内部类:

核心代码

// 基础Animal接口,支持返回泛型Optional
interface Animal {
    <T> Optional<T> accept(AnimalVisitor<T> visitor);
}

// 泛型访问者接口,默认方法返回empty,只需要实现关心的类型
interface AnimalVisitor<T> {
    default Optional<T> visit(Dog dog) { return Optional.empty(); }
    default Optional<T> visit(Cat cat) { return Optional.empty(); }
}

// Dog和Cat的实现和之前一致,只是返回Optional
class Dog implements Animal {
    @Override
    public <T> Optional<T> accept(AnimalVisitor<T> visitor) {
        return visitor.visit(this);
    }
}

class Cat implements Animal {
    @Override
    public <T> Optional<T> accept(AnimalVisitor<T> visitor) {
        return visitor.visit(this);
    }
}

// 工具类:封装常用的类型收集访问者
class AnimalVisitors {
    // 获取Dog的访问者
    public static AnimalVisitor<Dog> collectDog() {
        return new AnimalVisitor<>() {
            @Override
            public Optional<Dog> visit(Dog dog) {
                return Optional.of(dog);
            }
        };
    }

    // 获取Cat的访问者
    public static AnimalVisitor<Cat> collectCat() {
        return new AnimalVisitor<>() {
            @Override
            public Optional<Cat> visit(Cat cat) {
                return Optional.of(cat);
            }
        };
    }
}

使用方式

Animal animal = new Dog();
// 一行代码获取Optional<Dog>
Optional<Dog> possibleDog = animal.accept(AnimalVisitors.collectDog());

这个方案的优势是外部调用极其简洁,所有样板代码都被封装在工具类里,新增类型时只需要在工具类里加一个静态方法即可。

方案2:通用类型收集访问者

如果你的Animal子类较多,不想为每个类型都写静态方法,可以实现一个通用的类型收集器,内部通过类型检查完成转换(但外部代码完全看不到instanceof或强制转换):

核心代码

class GenericTypeCollector<T> implements AnimalVisitor<T> {
    private final Class<T> targetType;

    public GenericTypeCollector(Class<T> targetType) {
        this.targetType = targetType;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Optional<T> visit(Dog dog) {
        return targetType.isInstance(dog) ? Optional.of((T) dog) : Optional.empty();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Optional<T> visit(Cat cat) {
        return targetType.isInstance(cat) ? Optional.of((T) cat) : Optional.empty();
    }
}

使用方式

Animal animal = new Cat();
// 传入目标类型即可获取Optional
Optional<Cat> possibleCat = animal.accept(new GenericTypeCollector<>(Cat.class));

这个方案的优势是扩展性极强,新增Animal子类时,只需要在GenericTypeCollector里新增对应的visit方法即可,外部调用不需要修改。

方案3:优化你现有的抽象Collector

你目前使用的抽象AnimalCollector思路很好,我们可以给它加上静态工厂方法,进一步简化使用:

核心代码

abstract class AnimalCollector<T> implements AnimalVisitor {
    private Optional<T> result = Optional.empty();

    protected void setResult(T value) {
        if (result.isPresent()) {
            throw new IllegalStateException("Result can only be set once");
        }
        result = Optional.of(value);
    }

    public Optional<T> getResult() {
        return result;
    }

    // 静态工厂:创建Dog收集器
    public static AnimalCollector<Dog> dogCollector() {
        return new AnimalCollector<>() {
            @Override
            public void visit(Dog dog) {
                setResult(dog);
            }
        };
    }
}

使用方式

AnimalCollector<Dog> collector = AnimalCollector.dogCollector();
animal.accept(collector);
Optional<Dog> possibleDog = collector.getResult();

这个方案保留了你熟悉的使用习惯,同时通过静态工厂减少了重复编写匿名内部类的工作量。

总结

如果你的业务场景中类型较少,方案1是最简洁的;如果类型较多且经常新增,方案2的扩展性更好;如果不想改动现有代码结构,方案3是对你现有实现的最小优化。三种方案都能彻底摆脱之前用列表/Stream.Builder绕圈的冗余写法,同时保持访问者模式的类型安全优势。

内容的提问来源于stack exchange,提问作者sprinter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:57:03