求解一个简单的 if-else 优化问题

2019-05-11 21:39:40 +08:00
 Caturra
不会画图..口头描述一下

一个类中有多个私有的 Set,分别对应不同的类型,但这多个类型都有共同的接口(也就是说基本都差不多一个样),用于存放分别对应类型的对象

现在我要设计一个方法,接收该接口的类型,方法内部调用相对应的 Set,如何避免多个 if-else ?

--手动分割--

由于语死早,所以还是用个具体的过程再描述一遍

比如说一个 class 有 3 个 Set,分别是私有的 Set<A> a,Set<B> b,set<C> c,其中 A,B,C 都是接口 I 的实现类
简化的方法声明:xjbfunction(I obj)
简化的内部实现:
if(obj instanceof A) a.add(obj);
if(obj instanceof B) b.add(obj);
c 同理
//以上是 java 的写法

现在我想把 if-else 换成一个更简化通用的写法去表示,该如何去做(因为往后要扩展出更多的类和更复杂的业务处理),补充下次要要求:Set 尽量不要暴露给不必要的类

自己实在太菜了暂时没啥头绪,大家有什么好方法可以分享一下
3380 次点击
所在节点    程序员
16 条回复
huhu3312
2019-05-11 21:42:18 +08:00
策略模式试试
HongJay
2019-05-11 21:45:14 +08:00
楼上说的没错吧
Caturra
2019-05-11 21:57:12 +08:00
@huhu3312 一开始也想到用策略模式,但这个该怎么套用才能避免类型的判断?似乎做不到的吧
sagaxu
2019-05-11 22:03:39 +08:00
map<type,set>
yehoha
2019-05-11 22:05:55 +08:00
建议看下表驱动设计模式
arrow8899
2019-05-11 22:08:42 +08:00
如果你要新增一种类型 Set<D> 还是需要改代码啊;可以用 hashmap 来保存

LinkedHashMap<String, Set<I>> linkedHashMap = new LinkedHashMap<>();

linkedHashMap.put(obj.getClass().getName(), new Set<I>())
linkedHashMap.get(obj.getClass().getName()).add(obj)
huhu3312
2019-05-11 22:14:05 +08:00
@Caturra 反射呀
Caturra
2019-05-11 22:18:22 +08:00
@sagaxu
@arrow8899

不错的方法啊

@yehoha
头一回听说 orz。。我现在就去 Google

@huhu3312
懂了 orz
1762628386
2019-05-11 22:27:55 +08:00
没啥必要,你再优化,逻辑还是这个逻辑,顶多就是用枚举将逻辑状态和函数对应
Corbusier
2019-05-11 22:30:38 +08:00
映射啊,策略模式什么的…
Caturra
2019-05-11 23:25:25 +08:00
@1762628386 就是想往后维护更为灵活一点,因为这些类我以后可能要用到 10 个左右,还不止一个地方,一直 if-else 不可取
skypyb
2019-05-11 23:32:26 +08:00
要是一个类型只会有一个 set 的话(即不出现一个以上的 Set<A>) 那可以用枚举吧。
AlisaDestiny
2019-05-11 23:32:37 +08:00
```java
public class Test1 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
T t = new T();
t.put(new A());
t.put(new B());
t.put(new A());
t.put(new C());
}
}

class T{
private Set<? super I> aset = new HashSet<>();
private Set<? super I> bset = new HashSet<>();
private Set<? super I> cset = new HashSet<>();

public void put(I item) throws NoSuchFieldException, IllegalAccessException {
Field f = T.class.getDeclaredField(item.getClass().getSimpleName().toLowerCase() + "set");
f.setAccessible(true);
Object o = f.get(this);
if(o instanceof java.util.Set){
((java.util.Set)o).add(item);
}
System.out.println("==============");
System.out.println(aset);
System.out.println(bset);
System.out.println(cset);
System.out.println("==============");
}

}
interface I{
}

class A implements I{

}
class B implements I{

}
class C implements I{

}
```
java 无所不能,你这看下 demo 是你需要的不,传入实现了 I 接口的类,自动根据实例名字添加到对应的 set. PS:需要你 set 的命名符合 实例名.toLowerCase() + "set" 的规则;
Yyyye
2019-05-11 23:57:08 +08:00
我倒是觉得可以将 ab 类处理成一个接口,每个类继承这个接口,接口方法么。public int getType () 变成一个 set 接口获取的时候么,根据 type 返回
mxalbert1996
2019-05-12 00:25:56 +08:00
没必要用反射啊,假设你有 A 和 B 两个类都实现了 Interface 这个接口,那你可以这么写:

public class Test {
private Class[] classes = {A.class, B.class};
private HashMap<Class, Set<Interface>> sets = new HashMap<>();

public Test() {
for (Class clazz : classes) {
sets.put(clazz, new HashSet<>());
}
}

public void add(Interface value) {
Set<Interface> set = sets.get(value.getClass());
if (set != null) {
set.add(value);
} else {
throw new IllegalArgumentException();
}
}
}
autogen
2019-05-12 03:26:31 +08:00
@sagaxu 机智,送你 10 个铜板~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/563230

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX