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

Java 使用每个子类方法创建工厂对象,java,design-patterns,factory,factory-pattern,Java,Design Patterns,Factory,Factory Pattern,我有一个简单的工厂(GenericFudge),它根据外部环境创建不同类型的对象。目前,我的代码如下所示: abstract class Fudge { Fudge() { } void make() { System.out.println("made."); } } class VanillaFudge extends Fudge { @Override void make() { System.out.pri

我有一个简单的工厂(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()”方法。(在我的实际应用程序中,我必须反复尝试,但我对其他可能性感兴趣。)

我的直觉是为每个子类(perxxxfudge)使用一个静态初始值设定项,通过调用GenericFudge的registerFudge方法将“自身”添加到列表中,但这遇到了鸡和蛋的问题(该类从未使用过,因此其静态初始值设定项从未被调用)


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

如果您使用的是任何类型的依赖项注入系统,比如Spring,那么使用它很容易实现。如果这样做有效,那么您可以从用PostConstruct注释的方法调用GenericFudge中的register方法。在GenericFudge中,您有一个映射,每当调用addType时,您都会将其添加到映射中。这样,您的常规密码保持不变,新呼叫者将使用PostConstruct进行注册。为了进一步简化,可以在基类Fudge中定义它,并使用构造函数传递Fudge名称,这样就不必在每个子类中声明register方法

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

@Autowired
private GenericFudge fudge;

@PostConstruct
private void register() {
    fudge.addType(fudge, this);
}
一般的谎言

private Map<String, Fudge> fudgeTypes = Maps.newHashMap();
public void register(final String fudgeType, final Fudge fudgeInstance) {
    fudgeTypes.put(fudgeType, fudgeInstance);
}
private Map fudgeTypes=Maps.newHashMap();
公共无效寄存器(最终字符串fudgeType、最终Fudge fudgeInstance){
put(fudgeType,fudgeInstance);
}
如果不使用任何依赖项注入系统: 另一种方法是在基类Fudge中使用静态方法,在基类中声明所有类型的Fudge,然后根据请求返回实例。这样,您就不会修改GenericFudge类,而只修改Fudge的基类。这并不理想,但它使您不必修改GenericFudge类,而不是使用PostConstruct之类的东西“注册”,而是在地图中添加一个条目

示例(来自Guava的ImmutableMap,您可以随意声明该地图,这仅用于示例):

公共抽象类伪造{
私有静态最终映射FUDGE_TYPES=ImmutableMap.of(
“Type1”,新的Type1Fuude(),
“Type2”,新的Type2Fudge()
//在实现时添加新条目
);
公共静态Fudge getFudge(最终字符串Fudge){
if(软糖类容器(软糖)){
返回FUDGE_类型。获取(FUDGE);
}否则{
//根据您的喜好处理缺少的软糖
}
}
}

我看到我在上面有一个未说明的目标,那就是能够在不更改任何其他代码的情况下添加新的子类,使子类“自注册”。我现在看到这是不可行的(由于Java加载类的方式),除非可能通过某种方式搜索jar文件并使用反射。我还发现这是一个与我原来的问题不同的问题。我对你的问题的解释让我觉得你应该看看装饰图案。@bot谢谢。似乎Decorator适用于不同的装饰会添加不同/正交行为的情况。而且,我在上面找到的讨论并没有讨论创作。而是创建普通对象,然后添加装饰器。这不适合我的情况,在我的情况下,软糖要么是香草,要么是巧克力,不可能两者兼而有之(所以我的类比在这里失败了!)没有弗兰肯斯坦人会出现。但这绝对值得考虑,所以再次感谢。如果您使用任何类型的依赖项注入系统,如Spring,那么使用PostConstruct:,这很容易实现。如果没有,请说明您是如何启动该应用程序的。根据你的应用程序,有不同的方法来实现这一点。目前,它只是直接运行。将来我可能会使用WebStart。我不知道春天,所以也许我应该调查一下。非常感谢您的输入。Spring是Java应用程序中使用最广泛的容器框架之一,如果您正在寻找一些东西,您一定要了解。而且它的开始相当简单。如果你喜欢这个答案,请接受:)@JeffLearman如果这个答案适合你,也请接受:)
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
        }
    }
}