简单工厂和工厂方法设计模式差异

时间:2017-09-30 08:53:02

标签: java design-patterns factory-pattern software-design

我正在学习新设计模式。我试图理解Simple Factory& amp;工厂方法模式。首先,我想清楚一点,我尝试阅读Stack-overflow和其他网站上的大量文章,但这并没有帮助我。

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

我写了一个简单的Factory类,如下所示

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;
        }
    }
}

所以现在我在一个地方创建了所有对象,所以如果明天发生任何更改[Like constructor需要一个参数],我们只需要在一个地方进行更改。但它打破了OPEN CLOSED原则,好像明天我们需要添加更多项目,我们需要更改getItem()方法,如果条件。所以我们选择Factory Method Pattern  enter image description here

我们创建Factory类,如下所示:

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);

    }
}

我的理解是否正确? 我们在这里满足开放封闭原则,但是对于每个产品(项目)我们需要一个工厂类,它不会成为可管理的噩梦吗?

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

3 个答案:

答案 0 :(得分:1)

我认为在你的例子中,工厂似乎没用,因为你的蛋糕和巧克力构造者不需要任何工具。

当你想构造一个具有许多args的复杂对象来尊重DIP(依赖倒置原则)并避免令人尴尬的耦合时,工厂很有用。

此外,您的示例似乎违反了LSP(Liskov替换原则)。 Cake和Chocolate类没有任何共同点,作为证据,您的抽象超类名为Item,这是一个非常通用的名称。

对我而言,对于复杂的不常见对象,按类选择一个工厂更好,并且有效地遵守OCP(开放封闭原则)。

您的第一个示例可用于实例化继承相同超类的类,但使用您的类作为arg和反射(使用java.lang.reflect)来调用构造函数,而不仅仅是使用String求值。 (您的IDE无法自动完成该操作)并且如果不匹配,则不会返回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);
    }
}

如果没有依赖项,则可以直接在抽象Item类中将createItem()方法实现为static。

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

OCP只是为扩展而开放关闭修改原则。如果你需要打开修改你的工厂来添加一个新的类(一个新的案例来管理交换机或if),不,你的工厂不是&#34; OCP&#34;。

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

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

答案 1 :(得分:1)

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

出于学习目的,您逐个应用设计模式(这使得设计模式的真实力量变得难以捉摸或隐藏),但在现实世界中,设计模式混合在一起(甚至您可以创建一个新模式:p)为了创造满足大多数需求并接近理想的东西,你可以遇到例如与工厂模式混合的Builder模式或带有策略模式的工厂模式,或者甚至将它们中的三个混合在一起......

对于你的情况,我建议例如使用工厂方法模式简单工厂模式结合依赖注入模式来创建一些东西非常漂亮,同时满足公开关闭校长。

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();
    }
}

答案 2 :(得分:1)

答案(由@Mouad EL Fakir和@FrançoisLEPORCQ撰写)是关于静态工厂的。这是代码的第一部分。

还有两种口味,即 工厂方法 抽象工厂

您的代码的第二部分是使用CakeFactory和ChocolateFactory,您尝试使用Factory Method(尽管您的命名建议使用Abstract Factory)。这里使用工厂方法getXXX()是不正确的。这些模式的目的是不同的。在您的代码中,除了增加课程数量之外,您无法实现任何目标。 (虽然增加了类的数量并行层次结构被记录为与工厂相关的成本)

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

Role of Creator in Factory Pattern

What are the real benefits of using the Abstract Factory in the following example, instead of the factory method?