为什么要使用工厂方法模式而不是简单工厂

时间:2018-08-15 17:26:22

标签: java design-patterns

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

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

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

如果我在Factory Method的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();

    }

}

3 个答案:

答案 0 :(得分:2)

出于学习目的,可能需要遵循工厂方法和抽象工厂的GoF定义。 GoF是围绕基本模式的公共参考和讨论。最好警惕在几个充满广告的网站上找到的许多“示例”,因为某些示例充其量会误导您。

使用GoF标记有2种工厂模式Factory Method和Abstract Factory。

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

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

示例:考虑一个基本的TextEditor类,其中包含C#,PHP,JS,HTML等的子类。每个子类都需要有自己的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目的是“提供一个用于创建相关或依赖对象族的接口,而无需指定其具体类”。实际上,这意味着要创建一个抽象的Factory类,该类的子类定义如何创建相关对象的族。

示例:扩展了TextEditor示例,我们意识到除了SyntaxChecker之外,还需要特定于语言的Formatter和Debug模块。 (我们可以通过Factory Method的多个应用来实现这一点,但这涉及到编辑多个类)。使用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“标准”,尤其是在学习时。当您确定自己在做什么时,以后可以根据自己的需要进行适应和调整:-)。

答案 1 :(得分:0)

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

仅当可接受紧密耦合时,首选“简单工厂”,因为这种模式会将客户端耦合到工厂实现类。

当需要松散耦合时,通常首选Abstract Factory。

答案 2 :(得分:0)

如果愿意,可以将开关替换为枚举,并且对所允许枚举列表的简单迭代将返回所需的对象。 我从代码中看到的是,第一个使用委托,第二个将您的客户与具体工厂结合在一起。我希望这里是第一个。