我怎样才能将这个带有多个泛型的可怕的抽象 java 类重构为"better"的东西?



我们的JSF web应用程序中有多个搜索页面,它们具有类似的功能:

  • 他们有搜索结果(称这些对象为T)
  • 有一个包含搜索条件的对象(称此对象为C)
  • 他们能够用名称保存搜索条件(将此对象称为S)

因此,这些都使用JSF页面支持bean,它们都扩展了一个抽象类:

public abstract class AbstractSearch<T, C, S> implements Serializable {

例如:

public class FooSearch extends AbstractSearch<Foo, FooCriteria, FooSavedCriteria> 
    implements Serializable {

我看到的一个问题是,放入T、C和S中的类与另一个T、C或S类不共享超类型。不过,他们确实有类似的方法。例如,所有的S型类都有一个"getName()"方法。我不能用一个通用的超类来获得这个名称。相反,我必须将以下方法放在AbstractSearch类中,并用它包装我的所有对象:

abstract String getNameFromSavedCriteria(S);

然后在每个子类中实现转换方法:

@Override
String getNameFromSavedCriteria(FooSavedCriteria criteria) {
    return criteria.getName();
}

这种做法不好吗?页面上到处都是这些转换助手方法。

另一个似乎是奇怪编码的例子。这是一个刻板的公共方法的抽象搜索:

public void runSearch() {
    if (simpleSearch == true) {
        clearAdvancedSearchFields(); // abstract method
    }        
    populateSearchFromForm(); // abstract method
    try {
        setResults(processRunSearch()); // abstract method
        cacheResults(results); // abstract method
        cacheSearch(search); // abstract method
        if (getResults().isEmpty()) {
            Messages.addGlobalWarn("No results found");
        }
        if (formAutoHide) {
            searchFormVisible = getResults().isEmpty();
        }
    } catch (MyException ex) {
        FacesUtils.addGlobalError(ex);
    }
}

再说一遍,这是一种糟糕的做法吗?有没有更好的方法来处理这样一个抽象类,它有很多通用功能,但没有很多可操作的通用类?

我还应该注意到,也许在某个时候,我可以将T/C/S重构为所有使用公共子类型的子类型,这样这些转换辅助方法就可以消失了。还我还没有完全做到。

我看不出"抽象搜索的常规公共方法"有什么问题。抽象类定义了抽象方法,这样它们就可以使用它们了。

为了解决你的问题,我认为朝着正确的方向迈出的一大步是定义T、C、S的边界,这样它们就可以在抽象的层面上相互使用。

例如:

abstract class Criteria {
    abstract String getName();
    String getNameFromSavedCriteria(SavedCriteria s) {
        return s.getName();
    }
}
interface SavedCriteria {
    String getName();
}
public abstract class AbstractSearch<T, C extends Criteria, S extends SavedCriteria> implements Serializable {
   void foo() {
       System.out.println("Hello. Searching for " + getCriteria().getName());
   }
}

T、 C,S不一定需要一个公共类;S可能。

您的代码示例runSearch()遵循模板方法模式,我认为它没有太大问题。

我也不认为你的类中有3个泛型有什么问题。看看新的Java 8 Stream/Collect/Reduce方法,它们通常有3种类型。

在我的代码中,当我有这么多这样的泛型时,有时我会制作一个标记接口,但这只是因为如果你有几个不同的FooSearch实现,它们都使用相同或泛型。

如果你查看Android的AsyncTask,你会发现它有3个类参数。

我说,只要这些类在功能上不重叠,就没有理由重构它

最新更新