当你有一堆非常相似的类无法共享接口时,使用什么样的设计模式?

时间:2014-03-01 23:56:20

标签: java design-patterns

我有一个名为Base的抽象类,它处理一堆逻辑来处理我的一些数据。 API看起来像这样:

// Class has no abstract methods, but is uninstantiable
public abstract class Base {
    private Param param;

    protected Base() {}

    protected void setParam(Param param) {
        this.param = param
    }

    public void doThing() {
        // Code here to do a common thing
    }

    public void doOtherThing() {
        // Code here to do another common thing
    }

    protected void handle(Object... objects) {
        // This code delegates work to a scripting language via the param 
        // It is not type safe and the array of objects needed will vary depending 
        // on the implementing class.
    }
}

当然,这里奇怪的是handle(Objects...)方法。要显示它的使用方式,请查看其中一个子类:

public class Person extends Base {
    protected Person(Param param) {
        super();
        setParam(param);
    }

    public void handle(String name, int age) {
        // Expose a type safe interface to the world
        super.handle(name, age);
    }
}

正如您所看到的,子类隐藏了super.handle,这是受保护的,对于某些参数,以便此类的使用者可以具有类型安全交互,而无需传递对象数组。问题是,我想从一个工厂创建这些,这个工厂强制每个参数有一个子类实例。目前,这家工厂看起来像这样:

public class Factory {
    Map<Param, Person> persons;
    Map<Param, Other> others; // Other also extends Base

    public Person getPerson(Param param) {
        Person person = persons.get(param);

        if (person == null) {
            person = new Person(param);
            persons.put(param, person);
        }

        return person;
    }

    public Other getOther(Param param) {
        Other other = others.get(param);

        if (other == null) {
            other = new Other(param);
            other.put(param, other);
        }

        return other;
    }
}

显然,这很糟糕,但我认为没有更好的方法来处理这种情况,因为通过param与脚本语言交互的奇怪性质,它依赖于字符串构造来执行代码。有没有人对如何清理这个设计有任何指导?

1 个答案:

答案 0 :(得分:1)

可以概括工厂类,使用一些泛型和反射来在运行时实例化特定的子类类型:

import java.util.HashMap;
import java.util.Map;

public class Factory<T> {

    private Map<Param, T> instances = new HashMap<Param, T>();

    public final T create(Class<T> clazz, Param param) throws Exception {
        T cur = instances.get(param);

        if (cur == null) {
             cur = clazz.newInstance();
             ((Base)cur).setParam(param);
             instances.put(param, cur);
        }
        return cur;
    }
}

子类应该有no-args构造函数,而不是public;为了一致性,删除with-param one:

public class Person extends Base {

    protected Person(){}

    public void handle(String name, int age) {
        // Expose a type safe interface to the world
        super.handle(name, age);
    }

}

使用示例:

public class TestFactory {
    public static void main(String[] args) throws Exception {
        Factory<Person> factory = new Factory<Person>();
        Person p = factory.create(Person.class, new Param());
    }
}

当然我知道这不是一个模式,它不是我可以引以为豪的更优雅的代码,但仍然避免你必须为每个新的子类更改工厂,它不使用静态方法并保持在单点指向缓存逻辑。