当前位置: 首页 > 知识库问答 >
问题:

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

翟善
2023-03-14

我正在学习新的设计模式

我编写了一个简单的工厂类,如下所示

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

我们创建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个答案

锺离逸春
2023-03-14

我认为在你的例子中,工厂似乎毫无用处,因为你的蛋糕和巧克力构造器不需要任何参数。

当您想要构造一个包含许多参数的复杂对象以尊重DIP(依赖项反转原则)并避免尴尬的耦合时,工厂非常有用。

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

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

第一个示例对于实例化继承同一超类的类很有用,但是可以使用arg和reflection(使用java.lang.reflect)来调用构造函数,而不仅仅是使用字符串求值。(你的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);
    }
}

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

看看这本书,这是一个很好的资源:头先设计模式

OCP只是打开扩展关闭修改原则。如果您需要打开您的工厂以添加一个新类(在交换机或if中管理的新案例),不,您的工厂不是“OCP”。

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

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

周玺
2023-03-14

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

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

代码的第二部分是使用CakeFactory和ChocolateFactory,您尝试使用Factory方法(尽管您的命名建议使用抽象工厂)。这里工厂方法getXXX()的用法不正确。这些模式的目的是不同的。在代码中,除了增加类的数量,你什么都没有实现。(尽管类和并行层次结构数量的增加被记录为与工厂相关的成本)

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

创造者在工厂模式中的作用

在下面的示例中使用抽象工厂而不是工厂方法的真正好处是什么?

丌官浩旷
2023-03-14

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

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

对于您在这里的案例,我建议例如使用工厂方法模式以及简单工厂模式与依赖注入模式相结合,以创建完全美丽的东西,同时满足Open封闭主体。

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();
    }
}
 类似资料:
  • 本文向大家介绍Java设计模式之工厂模式分析【简单工厂、工厂方法、抽象工厂】,包括了Java设计模式之工厂模式分析【简单工厂、工厂方法、抽象工厂】的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java设计模式之工厂模式。分享给大家供大家参考,具体如下: 一、 简单工厂 先来思考一个问题。我们平时写程序时,会有这种情况,A对象里面需要调用B对象的方法,这时我们使用的一般是new关键字来创建

  • 简单工厂(Simple Factory) Intent 在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。 Class Diagram 简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。 这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所

  • 本文向大家介绍Ruby中使用设计模式中的简单工厂模式和工厂方法模式,包括了Ruby中使用设计模式中的简单工厂模式和工厂方法模式的使用技巧和注意事项,需要的朋友参考一下 之前有看过《ruby设计模式》,不过渐渐的都忘记了。现在买了一个大话设计模式,看起来不是那么枯燥,顺便将代码用ruby实现了一下。 简单工厂模式: 这样写的好处是降低耦合。 比如增加一个开根号运算的时候,只需要在工厂类中添加一个分支

  • 工厂-创建对象而不向客户机公开实例化逻辑,并通过公共接口引用新创建的对象。是工厂方法的简化版本 工厂方法-定义一个创建对象的接口,但让子类决定实例化哪个类,并通过公共接口引用新创建的对象。 抽象工厂-提供了创建相关对象家族的接口,而无需显式指定它们的类。 null

  • 工厂方法(Factory Method) Intent 定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。 Class Diagram 在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。 下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。

  • 本文向大家介绍PHP设计模式之简单工厂和工厂模式实例分析,包括了PHP设计模式之简单工厂和工厂模式实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP设计模式之简单工厂和工厂模式。分享给大家供大家参考,具体如下: 工厂模式是创建型模式的一种,分为简单工厂模式,工厂模式,抽象工厂模式,简单工厂可以称之为工厂模式的一个特例 先用一段简单的代码说明一下,现在假设我们是顾客,需要苹果味饮