有没有更好的方法来短路一个实例链?

时间:2017-02-04 06:46:59

标签: java oop switch-statement instanceof

我的班级最初是从几个单独的addAListener() addBListener()removeAListener等开始的。这对于一个班级来说并不是那么糟糕,但是当班级被内部使用时,它真的会向外爆炸另一个类和扩展的侦听器被传播出来。

一个简单的解决方案是使用单个界面并使用instanceof对侦听器进行排序:

public interface Listener {
}

public class ListenerA extends Listener {
}

public class ListenerB extends Listener {
}

public class ListenerC extends Listener {
}

List<ListenerA> ofListenersA = new List<>();
List<ListenerB> ofListenersB = new List<>();
List<ListenerC> ofListenersC = new List<>();

void addListener(Listener listener) {
    if (listener instanceof ListenerA) {
        ofListenersA.add(listener);

        return;
    }

    if (listener instanceof ListenerB) {
        ofListenersB.add(listener);

        return;
    }

    if (listener instanceof ListenerB) {
        ofListenersB.add(listener);

        return;
    }
}

void removeListener(Listener listener) {
    if (listener instanceof ListenerA) {
        ofListenersA.remove(listener);

        return;
    }

    if (listener instanceof ListenerB) {
        ofListenersB.remove(listener);

        return;
    }

    if (listener instanceof ListenerB) {
        ofListenersB.remove(listener);

        return;
    }
}

但是现在我必须完全评估每个instanceof,因为你不能在课堂上switch

这不是要求优化的尝试,因为我没有多种听众需要检查;而是一个关于在面向对象设计方面这是否是一种糟糕方法的问题。

更新

在界面中使用枚举的短路方法:

enum ListenerType {
    ListenerTypeA,
    ListenerTypeB,
    ListenerTypeC
}

public interface Listener {
    ListenerType getType();
}

public class ListenerA extends Listener {
    ListenerType getType() {
        return ListenerType.ListenerTypeA;
    }
}

public class ListenerB extends Listener {
    ListenerType getType() {
        return ListenerType.ListenerTypeB;
    }
}

public class ListenerC extends Listener {
    ListenerType getType() {
        return ListenerType.ListenerTypeC;
    }
}

List<ListenerA> ofListenersA = new List<>();
List<ListenerB> ofListenersB = new List<>();
List<ListenerC> ofListenersC = new List<>();

void addListener(Listener listener) {
    switch (listener) {
        case ListenerTypeA: {
            ofListenersA.add(listener);

            return;
        }
        case ListenerTypeB: {
            ofListenersB.add(listener);

            return;
        }
        case ListenerTypeC: {
            ofListenersC.add(listener);

            return;
        }
    }
}

void removeListener(Listener listener) {
    switch (listener) {
        case ListenerTypeA: {
            ofListenersA.remove(listener);

            return;
        }
        case ListenerTypeB: {
            ofListenersB.remove(listener);

            return;
        }
        case ListenerTypeC: {
            ofListenersC.remove(listener);

            return;
        }
    }
}

4 个答案:

答案 0 :(得分:1)

我建议您添加一个类型来指定您感兴趣的侦听器类型。您还可以将键更改为其他内容,例如使用hashCode和equals的常规类。

enum ListenerType {
    TYPE_A, TYPE_B, TYPE_C
}

interface Listener {

}

Map<ListenerType, Set<Listener>> listeners = new ConcurrentHashMap<>();

public void addListener(ListenerType type, Listener listener) {
    listeners.computeIfAbsent(type, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())).add(listener);
}

public void removeListener(ListenerType type, Listener listener) {
    listeners.computeIfPresent(type, (k, v) -> v.remove(listener) && v.isEmpty() ? null : v);
}

public Set<Listener> getListeners(ListenerType type) {
    return listeners.getOrDefault(type, Collections.emptySet());
}

答案 1 :(得分:0)

拥有一个interface并定义enum。在abstract method的{​​{1}}中,您可以将interface的实例作为参数。

现在您只需要一个侦听器列表。

现在您可以根据操作或事件类型调用方法。在实施时,您可以按照enum进行处理。

其他方式是enum instance type single interface。根据发生的事件调用方法,在实现时,您可以按照方法进行处理。

使用定义事件类型的变量的单个方法的方法(类型为enum,string或integer但更喜欢枚举的变量)的优点是,如果添加了更多操作,您只需要在界面中添加这些操作并不多需要改变。你只需要在枚举中添加添加的动作(如果你有字符串或整数常量,那么你可以为新动作定义额外的常量)。现在,您可以使用新定义的操作类型调用相同的方法。

只需要注意避免different methods接口。您需要在太薄(每个方法的单个接口)与胖接口之间进行平衡。您可以将属于逻辑相同任务的方法分组到接口中。太分散的代码也很糟糕,将每个(相关的和不相关的)api放在一个接口中也很糟糕。

答案 2 :(得分:0)

根据我的经验,总是比使用instanceOf更好的方法而不知道你的代码库很难说最合适的东西,但根据情况,以下对于类型比较有好处: / p>

  • 地图,它们的操作方式与基于类型的切换语句的操作方式大致相同,只要您将地图的键设置为您希望打开的类型,那么它就取决于您在返回时返回的内容它匹配。

  • Command Pattern,您将侦听器类层次结构替换为抽象/具体命令。然后,您可以将实际行为封装到接收器中。

  • Visitor Pattern,如果您想立即通知所有侦听器,那么访问者模式可能适用,则通过侦听器层次结构再次进行类型比较作为访问的元素。

我希望这有一些用处,如果我不在基地,请告诉我。

答案 3 :(得分:0)

我们在这种情况下使用过访问者模式。 如果添加了Listener的新实现,也可以很容易地使用访问者模式维护代码。