我的班级最初是从几个单独的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;
}
}
}
答案 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的新实现,也可以很容易地使用访问者模式维护代码。