我有一个MyObjects列表,我需要将其分为三组:
- 已知良好(保持)
- 已知错误(拒绝)
- 无法识别(引发警报)
MyObject 包含各种属性,必须检查这些属性以确定要将对象放入 3 组中的哪一组。
我的初始实现(Java)只是在其构造函数中获取一个列表并在那里进行分类。伪代码:
class MyObjectFilterer {
public MyObjectFilterer(List<MyObject> list) {
// triage items here
}
public List<MyObject> getGood() {
// return sub-list of good items
}
public List<MyObject> getBad() {
// return sub-list of bad items
}
public List<MyObject> getUnrecognized() {
// return sub-list of unrecognized items
}
}
此实现有任何问题吗?有没有更好的OO选择?
我可能更喜欢使用静态工厂方法来执行过滤,然后调用一个私有构造函数,该构造函数采用三个过滤列表,遵循从不在构造函数中做任何严肃工作的良好代码实践。 除此之外,这看起来不错。
可能有多种方法。如果问题足够通用/重复,则可以使用对对象进行分类的方法定义一个接口。
interface Selector {
public boolean isGood(MyObject myObject);
public boolean isBad(MyObject myObject);
public boolean isUnknown(MyObject myObject);
}
这样,您就可以轻松更改逻辑实现。
另一个想法是使用责任链。
您的 MyObjectFilterer 包含对三个对象 GoodFilterer、BadFilterer 和 UnrecognizedFilter er 的引用。 它们中的每一个都包含以下方法:addMethod(MyObject object)、getObjects() 和 addFilter()。当然,他们必须实现一个接口过滤器。
使用 addFilter 方法,您可以构建链。 以便 GoodFilterer 包含对 BadFilterer 的引用,而这个包含对 UnrecognizedFilterer 的引用
现在,您浏览 MyObjects 列表,并在 GoodFilterer(此链中的第一个)上调用 add 方法。在 add 方法中,您决定这是否好,然后保留它并完成工作,如果没有将其传递给 BadFilterer。
你保留了获取好/坏和无法识别的三种方法,但你会把它传递给相应过滤器的 getObjects() 方法。
好处是,如果这是一个好/坏或无法识别的逻辑,现在被分开了。
缺点是您需要 3 个新类和 1 个界面。
但就像我说的,这只是你可以做的另一种想法。
你应该尽可能简化。只需使用以下签名在MyObjectFilter中创建静态方法:
公共静态列表过滤器MyObjects(列表数据,组组)。
组是具有三个值的枚举,可以用作MyObject类的属性
我可能会尝试如下:
enum MyObjectStatus {
GOOD, BAD, UNRECOGNIZED;
}
class MyObjectFilterer {
private MyObjectStatus getStatus(MyObject obj) {
// classify logic here, returns appropriate enum value
}
// ListMultimap return type below is from Google Guava
public ListMultimap<MyObjectStatus, MyObject> classify(List<MyObject> objects) {
ListMultimap<MyObjectStatus, MyObject> map = ArrayListMultimap.create();
for(MyObject obj: objects) {
map.put(getStatus(obj), obj);
}
}
}
调用 classify() 来获取 Multimap,并根据需要提取每个类别
,如下所示:List<MyObject> good = map.get(GOOD);
List<MyObject> bad = map.get(BAD);
List<MyObject> unknown = map.get(UNRECOGNIZED);
这个解决方案的一个好处是,你不必为每个类别创建/发布访问器方法(除非你愿意),如果创建了新类别,你也不会添加新的访问器 - 只是新的枚举和额外的分类器逻辑。