使用每个子类方法创建工厂对象

时间:2015-03-19 16:27:34

标签: java design-patterns factory factory-pattern

我有一个简单的Factory(GenericFudge),它根据外部环境创建不同类型的对象。目前,我的代码看起来像这样:

abstract class Fudge {
    Fudge() {
    }
    void make() {
        System.out.println("made.");
    }
}

class VanillaFudge extends Fudge {
    @Override
    void make() {
        System.out.print("Vanilla ");
        super.make();
    }
}

class ChocolateFudge extends Fudge {
    @Override
    void make() {
        System.out.print("Chocolate ");
        super.make();
    }
}

class InvalidFlavorException extends Exception {};

// factory / proxy
public class GenericFudge {
    Fudge mFudge = null;
    GenericFudge(String flavor) throws InvalidFlavorException {
        if (flavor.equals("Chocolate")) {
            mFudge = new ChocolateFudge();
        } else if (flavor.equals("Vanilla")) {
            mFudge = new VanillaFudge();
        }
    }
    void make() {
        mFudge.make();
    }

    public static void main(String args[]) {
        for (String flavor : new String[] {"Chocolate", "Vanilla"}) {
            GenericFudge fudge;
            try {
                fudge = new GenericFudge(flavor);
                fudge.make();
            } catch (InvalidFlavorException e) {
                System.out.println("Sorry, we don't make that flavor");
            }
        }
    }
}

我的目标是从GenericFudge中获取巧克力和香草的细节,以便在实施CaramelFudge时,不需要更改GenericFudge。例如,GenericFudge将为每个xxxFudge类迭代地调用“createIfItsMyFlavor()”方法。 (在我的实际应用中,我必须迭代地尝试它们,但我会对其他可能性感兴趣。)

我的直觉是每个子类使用一个静态初始化器(每个xxxFudge),通过调用GenericFudge的registerFudge方法将“本身”添加到列表中,但这会遇到鸡与蛋的问题(该类从未使用过,所以它的静态初始化程序永远不会被调用。)

毫无疑问,有一种更好的方式我没想到。谢谢!

1 个答案:

答案 0 :(得分:1)

如果您使用任何类型的依赖注入系统(如Spring),则可以使用@PostConstruct轻松实现。如果这样可行,则可以使用PostConstruct注释的方法在GenericFudge中调用register方法。在GenericFudge中,您有一个地图,每当调用addType时,您都会将其添加到地图中。这样你的GenericFudge保持不变,新的调用者将使用PostConstruct注册。为了进一步简化,您可以在基类Fudge中定义它,并使用构造函数传递软糖名称,这样您就不必在每个子类中声明寄存器方法。

private String fudge;
public Fudge(final String fudge) {
    this.fudge = fudge;
}

@Autowired
private GenericFudge fudge;

@PostConstruct
private void register() {
    fudge.addType(fudge, this);
}

在GenericFudge中

private Map<String, Fudge> fudgeTypes = Maps.newHashMap();
public void register(final String fudgeType, final Fudge fudgeInstance) {
    fudgeTypes.put(fudgeType, fudgeInstance);
}

如果您不使用任何依赖注入系统: 另一种方法可能是在基类Fudge中有一个静态方法,您可以在其中声明所有类型的软糖,然后根据请求返回一个实例。这样你就不会修改GenericFudge类,而只修改Fudge的基类。这并不理想,但它让你不必修改GenericFudge类,而不是像PostConstruct那样“注册”,你就把一个条目放到Map中。

示例(来自Guava的ImmutableMap,您可以根据需要声明地图,这仅用于示例):

public abstract class Fudge {
    private static final Map<String, Fudge> FUDGE_TYPES = ImmutableMap.of(
        "Type1", new Type1Fudge(),
        "Type2", new Type2Fudge()
        // Add new entry when implemented
    );

    public static Fudge getFudge(final String fudge) {
        if (FUDGE_TYPES.containsKey(fudge)) {
            return FUDGE_TYPES.get(fudge);
        } else {
            // handle missing fudge depending on your preference
        }
    }
}