简单工厂和工厂方法设计模式的区别

Simple factory and Factory Method Design pattern difference

我正在学习新的设计模式,并且我正在尝试了解简单工厂模式和工厂方法模式之间的区别。首先,我想澄清一下,我尝试从 Stack-overflow 和其他网站阅读很多关于相同内容的文章,但这对我没有帮助。

这是我的问题: 让我们考虑一下我有一个产品层次结构,如下所示:

我写了一个简单的工厂class如下图

public class SimpleItemFactory {

    static Item getItem(String type) {
        if(type.equals("Cake")) {
            return new Cake();
        }else if(type.equals("Chocolate")) {
            return new Chocolate();
        }else {
            return null;
        }
    }
}

所以现在我在一个地方创建了所有对象,所以如果明天发生任何更改[就像构造函数需要一个参数],我们只需要在一个地方进行更改。但它打破了 OPEN CLOSED 原则,就好像明天我们添加更多项目,如果有条件,我们需要更改 getItem() 方法。所以我们选择工厂方法模式

我们创建工厂class如下图:

public abstract class ItemFactory {
    abstract Item getItem();
}

class CakeFactory extends ItemFactory {
    @Override
    Item getItem() {
        return new Cake();
    }
}

class ChocolateFactory extends ItemFactory {
    @Override
    Item getItem() {
        return new Chocolate();
    }
}


class Client{
    public static void main(String[] args) {

        Item chocolate = new ChocolateFactory().getItem();
        System.out.println(chocolate);
    }
 }

现在,当客户端想要添加名为 IceCream 的新项目时,他们只需创建名为 IceCreamFactory 的新工厂并从中创建 IceCream,如下所示:

class IceCreamFactory extends ItemFactory{

    @Override
    Item getItem() {
        return new IceCream();
    }

}

class Client{
    public static void main(String[] args) {
        Item iceCream = new IceCreamFactory().getItem();
        System.out.println(iceCream);

    }
}

我的理解对吗? 我们在这里满足了开闭原则,但是对于每个产品(Item)我们需要一个工厂class,这不是成为可管理的噩梦吗?

注意: 我指的是文章 https://www.codeproject.com/Articles/1135918/Factory-Patterns-Factory-Method-Pattern?msg=5380215#xx5380215xx

我认为在您的示例中,工厂似乎毫无用处,因为您的 Cake 和 Chocolate 构造函数不需要任何参数。

当您想构造一个具有许多参数的复杂对象以遵守 DIP(依赖倒置原则)并避免令人尴尬的耦合时,工厂很有用。

另外,你的例子好像违反了LSP(Liskov Substitution Principle)。 Cake 和 Chocolate class 没有任何共同点,作为证据,您的抽象超级 class 被命名为 Item,这是一个非常通用的名称。

对我来说,对于复杂的不常见对象,class选择一个工厂更好,并且有效地尊重OCP(开闭原则)。

您的第一个示例对于实例化 classes 很有用,它继承了相同的 superclass,但是使用您的 classes 作为参数和反射(使用 java.lang.reflect ) 来调用构造函数,而不仅仅是使用 String 求值。 (您的 IDE 无法自动完成)并且在不匹配的情况下不要 return null,抛出 IllegalArgumentException,它更正确。

像这样:

import java.lang.reflect.Constructor;

public class SimpleItemFactory {
    public <T extends Item> T createItem(Class<? extends Item> itemClass) {
        try {
            // construct your dependencies here
            // and inject them in the getConstructor
            Constructor<? extends Item> constructor = itemClass.getConstructor();
            return (T)constructor.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
    }
}

并像这样使用它:

class Client {
    public static void main(String[] args) {
        SimpleItemFactory factory = new SimpleItemFactory();
        IceCream iceCream = factory.createItem(IceCream.class);
        System.out.println(iceCream);
        Cake cake = factory.createItem(Cake.class);
        System.out.println(cake);
        Chocolate chocolate = factory.createItem(Chocolate.class);
        System.out.println(chocolate);
    }
}

如果您没有依赖项,则可以直接在您的抽象项 class 中将 createItem() 方法实现为静态方法。

看看这本书,这是一个很好的资源:Head First Design Patterns

OCP只是Open for extension Close for modification的原则。如果你需要打开修改你的工厂来添加一个新的class(一个新的案例在一个开关或一个if中管理),不,你的工厂不是"OCP"。

你不应该在构造函数中计算税收,构造函数应该只是......构造一个对象......你可以使用类似策略的模式来拥有许多taxCalculator并将它们注入构造函数,使用IOC(控制反转)机制,例如依赖项注入或以简单的方式使用.....工厂(这是可以接受的),但不能使用 class 中的简单静态方法。

对不起我的英语不好,我很难回答这样复杂的问题。

其实你的理解是正确的,只是你需要注意,每个设计模式都是为了解决至少一个问题,有时它可能会带来其他问题复杂性副作用,这意味着没有完美的设计模式可以解决所有问题。

为了学习的目的,你一个一个地应用设计模式(这使得设计模式的真正力量同样是害羞或隐藏),但是在现实世界中,设计模式是混合在一起的(或者你甚至可以发明一个新的 :p) 为了创造满足您的大部分需求并接近理想的东西,您可以遇到例如 Builder 模式与 Factory 模式的混合或 Factory 模式与 Strategy 模式的混合,甚至他们三个混合在一起。 ..

对于您的情况,我建议例如使用 Factory Method Pattern 以及 Simple Factory Pattern依赖注入模式 创造出完全美丽的东西,同时满足 Open closed 原则。

class ItemFactoryContainer() {

    private Map<String, ItemFactory> factories = new HashMap<>();

    public void register(String name, ItemFactory factory) {
        factories.put(name, factory);
    }

    public ItemFactory getFactory(String name) {
        return factories.get(name);
    }
}

public class ItemFactoryTest {

    public static void main(String...args) {

        ItemFactoryContainer factoryContainer = new ItemFactoryContainer();

        factoryContainer.register("choclate", new ChocolateFactory ());
        factoryContainer.register("cake", new CakeFactory ());
        factoryContainer.register("iceCream", new IceCreamFactory  ());

        Chocolate choclate = factoryContainer.getFactory("choclate").getItem();
        Cake cake = factoryContainer.getFactory("cake").getItem();
    }
}

答案(@Mouad EL Fakir 和@François LEPORCQ)是关于静态工厂的。那是你的代码的第一部分。

还有两种风格,即工厂方法抽象工厂)

你的代码的第二部分正在使用 CakeFactory 和 ChocolateFactory,你正在尝试使用工厂方法(尽管你的命名暗示抽象工厂)。这里工厂方法getXXX()的用法是不正确的。这些模式的目的是不同的。在您的代码中,除了增加 类 的数量外,您没有取得任何成就。 (尽管 增加的 类 平行层次结构 被记录为与工厂相关的成本)

我最近回答过类似的问题,看看这些回答是否有帮助