我该如何设计这个代码(并行类层次结构)?

时间:2012-10-29 00:16:36

标签: java design-patterns

我有一组所有需要与网络服务同步的应用程序:

  1. 从网络服务下载一些XML。
  2. 解析XML。
  3. 然后更新数据库以匹配解析的XML。
  4. 我想在公共库中保留尽可能多的相关代码以避免重复,并且我希望让不同的应用程序将解析和更新代码插入到一个相当简单的通用框架中。 / p>

    所以有一个常见的sync()方法:

    public void sync(URI updateUrl, XMLParser parser, Updater animalUpdater) {
        String raw = getXML();
        List<ParsedAnimal> parsed = parser.parse(raw);
        // try:
        // begin transaction
        for (ParsedAnimal pi : parsed) {
            animalUpdater.updateItem(pi);
        }
        // commit transaction
        // catch: rollback transaction, rethrow
        // finally: close database connection
    }
    

    解析器返回ParsedCat或ParsedDog等等,所有这些都从公共ParsedAnimal类继承:

    public abstract class ParsedAnimal {...}
    public class ParsedCat extends ParsedAnimal {...}
    public class ParsedDog extends ParsedAnimal {...}
    

    然后我有一个Updater,它需要获取解析后的项目并将内容注入数据库:

    public abstract class Updater {
        public abstract void updateItem(ParsedAnimal parsed);
    }
    public class CatUpdater extends Updater {
        @Override
        public void updateItem(ParsedCat parsed) {}
    }
    public class DogUpdater extends Updater {...}
    

    这不起作用 - Updater的合同规定updateItem()接受ParsedAnimal,而CatUpdater和DogUpdater都只通过接受特定类型的动物来破坏该合同。

    我所拥有的是并行类层次结构--ParsedX与XUpdater一对一匹配。 Coding Horror上的Code Smells页面建议将两个类层次结构合并为一个层次结构,但我觉得“正在处理的事情”和“正在工作的事情”是不同的,它们应该是单独的类。

    是否有一种简洁的方法来构建这个,或者某种设计模式会派上用场?

2 个答案:

答案 0 :(得分:4)

对于Updater合同中的问题,泛型可以派上用场:

public abstract class Updater<T extends ParsedAnimal> {
    public abstract void updateItem(T parsed);
}
public class CatUpdater extends Updater<ParsedCat> {
    @Override
    public void updateItem(ParsedCat parsed) {}
}
public class DogUpdater extends Updater<ParsedDog> {...}

但是,您的sync方法有一个Updater作为参数,它会尝试用于所有已解析的项目。这不行。如果您要为每个解析类型分别设置Updater,则需要根据您拥有的解析结果来实例化更新程序。这可以通过某种形式的“工厂”来处理。首先,您可能希望使用Factory Method模式。

答案 1 :(得分:0)

updateItem(ParsedAnimal parsed){
    if (parsed instanceof ParsedCat) {
        ... 
    } else if (parsed instanceof ParsedDog) {
        ... 
    } 
}