【问题标题】:Why to use Factory method pattern instead of Simple factory为什么使用工厂方法模式而不是简单工厂
【发布时间】:2018-08-16 08:41:36
【问题描述】:

与简单工厂相比,我试图了解何时使用工厂方法模式,我知道每种方法是如何实现的,但我并不完全明白它的重点。

假设我有提供字符串(汽车名称)的客户端,并且基于该字符串,工厂提供对象。

我知道方法工厂满足开/关原则,如果我有新的汽车品牌,例如梅赛德斯,我将不得不编辑开关盒并添加新品牌,那将是不好的做法。但是使用工厂方法,我的工厂无法决定制作哪个对象,因为没有开关盒。我想我在这里遗漏了一点。如果我在创建汽车对象时有不同的逻辑/策略,也许我应该使用工厂方法,也许一种制造随机汽车对象,一种采用字符串并基于该字符串制造对象。

如果我在工厂方法 getCar() 函数中使用并在那里执行更多逻辑,例如 car.tuneEngine() 等,在返回准备好使用的对象之前,这也是一个好习惯吗?

简单工厂

public class FordCar extends Car {

    public FordCar() {
        super("Ford", "Mondeo", 1.6);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void move() {
        System.out.println("Ford moves");

    }

}

public class CarFactory {

    public Car getCar(String brand) {
        switch (brand) {
        case "ferrari":
            return new FerrariCar();
        case "ford":
            return new FordCar();
        default:
            return null;

        }
    }
}

public class Client {

    public static void main(String[] args) {

        //Simple factory
        CarFactory carFactory = new CarFactory();
        Car clientSimpleCar = carFactory.getCar("ford");
        clientSimpleCar.move();     
    }
}

工厂方法模式

public abstract class CarMethodFactory {

    public Car getCar(){
        Car car = createCar();
        return car;
    }

    public abstract Car createCar();

}

public class FordMethodFactory extends CarMethodFactory{

    @Override
    public Car createCar() {
        return new FordCar();
    }

}

public class Client {

    public static void main(String[] args) {

        CarMethodFactory carMethodFactory = new FordMethodFactory();
        Car clientMethodCar = carMethodFactory.getCar();
        clientMethodCar.move();

    }

}

【问题讨论】:

  • 你的模式都错了——首先确实是工厂,其次是抽象工厂模式。通过方法工厂,我假设您的意思是静态方法工厂模式 - 以上都不是。
  • @BoristheSpider 第二个是抽象工厂吗?抽象工厂用于对象族。在他的示例中只有一种对象,即 Car。工厂方法模式具有抽象的创建功能,这让大多数人误以为它是抽象工厂模式。所以,他的例子很重要。

标签: java design-patterns


【解决方案1】:

出于学习目的,保留工厂方法和抽象工厂的 GoF 定义可能是有意义的。 GoF 是围绕基本模式的共同点参考和讨论。最好警惕在几个充满广告的网站上发现的许多“示例”,因为有些示例充其量是误导性的。

坚持使用 GoF,有 2 种工厂模式工厂方法和抽象工厂。

简单工厂不是一个单独的模式,它是工厂方法的一个特例。没有提到简单工厂模式作为 Gof 中的命名模式。见下文。

工厂方法:这不涉及工厂对象。顾名思义,它涉及到工厂方法()。

示例:考虑一个带有 C#、PHP、JS、HTML 等子类的基本 TextEditor 类。每个子类都需要自己的 SyntaxChecker 对象。 TextEditor 基类有一个抽象的 CreateSyntaxChecker() 方法,TextEditor 的每个子类都实现了 CreateSyntaxChecker() 接口并返回子类所需的特定 SyntaxChecker。考虑下面的伪代码以供典型使用。

Editor = new PHPTextEditor;  // instantiates PHP subclass of  TextEditor
_syntaxChecker = this->CreateSyntaxChecker();     // The constructor of  
PHPTextEditor invokes its over-ridden CreateSyntaxChecker() method, which returns 
the correct PHP SyntaxChecker object.

这符合工厂方法的 GoF 意图。 “定义创建对象的接口,但让子类决定实例化哪个类”。

“简单工厂”:是工厂方法的一种变体。在这个变体中,使用文本编辑器示例,TextEditor 基类有一个具体(而不是抽象)方法 CreateSyntaxChecker(),它可能会或不会在子类中被覆盖,如果没有被覆盖,则基类实现是用过。

抽象工厂:抽象工厂的 GoF 意图是“为创建相关或依赖对象的系列提供接口,而无需指定它们的具体类”。这实际上意味着创建一个抽象工厂类,其子类定义如何创建相关对象的系列。

示例:扩展 TextEditor 示例,我们意识到除了 SyntaxChecker 之外,还需要特定语言的 Formatter 和 Debug 模块。 (我们可以通过多次应用工厂方法来实现这一点,但这涉及到编辑几个类)。使用 3 个抽象方法 CreateSyntaxChecker()、CreateDebugger()、CreateFormatter() 定义一个抽象 Factory 类。然后定义子类 PHPFactory、JSFactory、HTMLFactory 等,每一个都提供 3 种方法的实现并返回正确的对象实例。

考虑下面的典型使用伪代码。

Factory = new PHPFactory();
Editor = new PHPEditor(Factory);    // Constructor of PHPEditor will invoke the 3 
Factory methods to instantiate the correct versions of the SyntaxChecker, Debugger 
and Formatter objects.

我强烈建议您重构代码以符合 GoF“标准”作为起点,尤其是在学习时。当您确定自己在做什么时,请随时适应和调整以满足您的需求:-)。

【讨论】:

    【解决方案2】:

    首选继承时首选工厂方法,因为该模式是通过继承实现的。

    只有在可以接受紧密耦合时才首选简单工厂,因为该模式将客户端耦合到工厂实现类。

    当需要松散耦合时首选抽象工厂,这几乎总是如此。

    【讨论】:

      【解决方案3】:

      如果您愿意,可以将 switch 替换为 enum,并且对允许的 enum 列表进行简单迭代将返回您想要的对象。 我从代码中可以看出,第一个使用委托,第二个将您的客户与具体工厂耦合。我更喜欢这里的第一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多