我有一组都需要与Web服务同步的应用程序:


从网络服务下载一些XML。
解析该XML。
然后更新数据库以匹配解析的XML。


我想将尽可能多的相关代码保存在一个公共库中,以避免重复,并且我想让不同的应用程序将其解析和更新代码全部放入一个相当简单的公共框架中。

因此,有一个常见的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页建议将两个类层次结构合并为一个层次结构,但是我觉得“正在处理的事情”和“正在执行的事情”足够不同,因此它们应该是单独的类。

有没有一种结构整齐的方法,或者可以派上用场的某些设计模式?

最佳答案

使用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模式。

09-29 19:45