devise模式:工厂vs工厂方法与抽象工厂

我正在从网站阅读devise模式

在那里,我读到了工厂,工厂方法和抽象工厂,但他们是如此混乱,不清楚的定义。 根据定义

工厂 – 创build对象而不会将实例化逻辑暴露给客户端,并通过通用接口引用新创build的对象。 是Factory Method的简化版本

工厂方法 – 定义创build对象的接口,但让子类决定实例化哪个类,并通过一个公共接口引用新创build的对象。

抽象工厂 – 提供用于创build相关对象族的界面,而不显式指定其类。

我也看了关于抽象工厂vs工厂方法的其他stackoverflow线程,但绘制在那里的UML图使我的理解更加糟糕。

任何人都可以告诉我

  1. 这三种模式如何不同?
  2. 什么时候用哪个?
  3. 还有,如果可能的话,任何有关这些模式的Java示例?

所有三种工厂types都做同样的事情:他们是一个“聪明的构造函数”。

假设你想创造两种水果:苹果和橙子。

工厂是“固定的”,因为你只有一个没有子类化的实现。 在这种情况下,你将有一个这样的课程:

class FruitFactory { public Apple makeApple() { // Code for creating an Apple here. } public Orange makeOrange() { // Code for creating an orange here. } } 

用例:构造一个Apple或者一个Orange有点太复杂,无法在构造函数中处理。

工厂方法

工厂方法通常用于在一个类中进行一些通用处理,但想要改变实际使用的水果types。 所以:

 abstract class FruitPicker { protected abstract Fruit makeFruit(); public void pickFruit() { private final Fruit f = makeFruit(); // The fruit we will work on.. <bla bla bla> } } 

…然后你可以通过在子类中实现一个工厂方法来重用FruitPicker.pickFruit()的常用function:

 class OrangePicker extends FruitPicker { @Override protected Fruit makeFruit() { return new Orange(); } } 

抽象工厂

抽象工厂通常用于诸如dependency injection/策略之类的东西,当你希望能够创build一个需要是“相同types”的对象的全家族,并且有一些共同的基类。 这是一个模糊的水果相关的例子。 这里的用例是我们要确保我们不会在苹果上意外地使用OrangePicker。 只要我们从同一个工厂得到我们的水果和捡取器,他们就会匹配。

 interface PlantFactory { Plant makePlant(); Picker makePicker(); } public class AppleFactory implements PlantFactory { Plant makePlant() { return new Apple(); } Picker makePicker() { return new ApplePicker(); } } public class OrangeFactory implements PlantFactory { Plant makePlant() { return new Orange(); } Picker makePicker() { return new OrangePicker(); } } 

工厂 – 单独工厂类创build复杂的对象。

例如:FruitFactory类来创buildFruit的对象

 class FruitFactory{ public static Fruit getFruit(){...} } 

工厂方法 – 而不是整个单独的工厂类,只是在该类本身添加一个方法作为工厂。

例如:

 Calendar.getInstance() (Java's Calendar) 

抽象工厂方法 – 工厂工厂

例如:可以说我们要build造电脑零件的工厂。 所以有几种types的电脑,如笔记本电脑,桌面,服务器。

所以对于每一个comptertypes我们都需要工厂。 所以我们创build了一个像下面这样的工厂的高级工厂

 ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory. 

现在这三个本身又是工厂。 (你将会处理PartFactory本身,但是根据你在抽象工厂中提供的内容,将会有单独的实现)

  Interface-> PartFactory. getComputerPart(String s), Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Usage: new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”) 

编辑:编辑提供精确的接口为抽象工厂根据反对意见。

  1. 这三种模式如何不同?

工厂:创build对象而不将实例化逻辑公开给客户端。

工厂方法:定义创build对象的接口,但让子类决定实例化哪个类。 Factory方法让类将实例化推迟到子类

抽象工厂:提供一个接口,用于创build相关或依赖对象的族,而不指定具体的类。

AbstractFactory模式使用组合来将创build对象的责任委托给另一个类,而Factory方法devise模式使用inheritance,并依赖于派生类或子类来创build对象

  1. 什么时候用哪个?

工厂:客户只需要一个类,并不关心它得到的具体实现。

工厂方法:客户端不知道在运行时需要创build什么样的具体类,但是只想得到一个可以完成这个工作的类。

AbstactFactory:当您的系统必须创build多个产品系列,或者您希望提供一个产品库而不公开实施细节。

抽象工厂类通常使用Factory Method实现。 工厂方法通常在模板方法中调用。

  1. 还有,如果可能的话,任何有关这些模式的Java示例?

工厂和FactoryMethod

意图:

定义一个创build对象的接口,但让子类决定实例化哪个类。 工厂方法让类将实例化延迟到子类。

UML图 :

在这里输入图像说明

产品:它定义了Factory方法创build的对象的接口。

ConcreteProduct:实现产品界面

创build者:声明工厂方法

ConcreateCreator:实现Factory方法来返回ConcreteProduct的一个实例

问题陈述:使用定义游戏界面的工厂方法创build一个游戏工厂。

代码片段:

 import java.util.HashMap; /* Product interface as per UML diagram */ interface Game{ /* createGame is a complex method, which executes a sequence of game steps */ public void createGame(); } /* ConcreteProduct implementation as per UML diagram */ class Chess implements Game{ public Chess(){ createGame(); } public void createGame(){ System.out.println("---------------------------------------"); System.out.println("Create Chess game"); System.out.println("Opponents:2"); System.out.println("Define 64 blocks"); System.out.println("Place 16 pieces for White opponent"); System.out.println("Place 16 pieces for Black opponent"); System.out.println("Start Chess game"); System.out.println("---------------------------------------"); } } class Checkers implements Game{ public Checkers(){ createGame(); } public void createGame(){ System.out.println("---------------------------------------"); System.out.println("Create Checkers game"); System.out.println("Opponents:2 or 3 or 4 or 6"); System.out.println("For each opponent, place 10 coins"); System.out.println("Start Checkers game"); System.out.println("---------------------------------------"); } } class Ludo implements Game{ public Ludo(){ createGame(); } public void createGame(){ System.out.println("---------------------------------------"); System.out.println("Create Ludo game"); System.out.println("Opponents:2 or 3 or 4"); System.out.println("For each opponent, place 4 coins"); System.out.println("Create two dices with numbers from 1-6"); System.out.println("Start Ludo game"); System.out.println("---------------------------------------"); } } /* Creator interface as per UML diagram */ interface IGameFactory { public Game getGame(String gameName); } /* ConcreteCreator implementation as per UML diagram */ class GameFactory implements IGameFactory { HashMap<String,Game> games = new HashMap<String,Game>(); /* Since Game Creation is complex process, we don't want to create game using new operator every time. Instead we create Game only once and store it in Factory. When client request a specific game, Game object is returned from Factory instead of creating new Game on the fly, which is time consuming */ public GameFactory(){ games.put(Chess.class.getName(),new Chess()); games.put(Checkers.class.getName(),new Checkers()); games.put(Ludo.class.getName(),new Ludo()); } public Game getGame(String gameName){ return games.get(gameName); } } public class NonStaticFactoryDemo{ public static void main(String args[]){ if ( args.length < 1){ System.out.println("Usage: java FactoryDemo gameName"); return; } GameFactory factory = new GameFactory(); Game game = factory.getGame(args[0]); System.out.println("Game="+game.getClass().getName()); } } 

输出:

 java NonStaticFactoryDemo Chess --------------------------------------- Create Chess game Opponents:2 Define 64 blocks Place 16 pieces for White opponent Place 16 pieces for Black opponent Start Chess game --------------------------------------- --------------------------------------- Create Checkers game Opponents:2 or 3 or 4 or 6 For each opponent, place 10 coins Start Checkers game --------------------------------------- --------------------------------------- Create Ludo game Opponents:2 or 3 or 4 For each opponent, place 4 coins Create two dices with numbers from 1-6 Start Ludo game --------------------------------------- Game=Chess 

此示例通过实现FactoryMethod显示Factory类。

  1. Game是所有types游戏的界面。 它定义了复杂的方法: createGame()

  2. Chess, Ludo, Checkers是不同的游戏,它提供了执行createGame()

  3. public Game getGame(String gameName)IGameFactory类中的IGameFactory

  4. GameFactory在构造函数中预先创build不同types的游戏。 它实现了IGameFactory工厂方法。

  5. 游戏名称作为命令行parameter passing给NotStaticFactoryDemo

  6. getGame中的GameFactory接受一个游戏名称并返回相应的Game对象。

与其他创作模式的比较:

  1. devise从使用工厂方法开始(不太复杂,更可定制的子类泛化),并向devise师发现需要更多灵活性的抽象工厂,原型或生成器 (更灵活,更复杂)

  2. 抽象工厂类通常使用工厂方法实现,但也可以使用Prototype实现

进一步阅读的参考资料来源: devise模式

每种devise模式都能够帮助确保书面的工作代码不被触及。 我们都知道,一旦我们触及工作代码,现有工作stream程就有缺陷,需要做更多的testing来确保我们不会破坏任何东西。

工厂模式根据input条件创build对象,从而确保您不需要编写代码,就像创build这个对象一样。 旅游网站就是一个很好的例子。 一个旅游网站只能提供旅行(飞行,火车,巴士)或/和提供旅馆或/和提供旅游景点套餐。 现在,当用户select下一个时,网站需要决定它需要创build什么对象。 它应该只创build旅行或酒店对象。

现在,如果您打算为您的投资组合添加另一个网站,并且您认为使用了相同的核心网站,例如拼车网站(现在可以search出租车并在线进行支付),则可以在您的核心使用抽象工厂。 这样你就可以在一个更多的出租车和汽车工厂。

这两个工厂都没有任何关系,所以它是一个很好的devise,让他们在不同的工厂。

希望这个现在很清楚。 再次研究网站,记住这个例子,希望它会有所帮助。 我真的希望我已经正确地代表了模式:)。

 AbstractProductA, A1 and A2 both implementing the AbstractProductA AbstractProductB, B1 and B2 both implementing the AbstractProductB interface Factory { AbstractProductA getProductA(); //Factory Method - generate A1/A2 } 

使用工厂方法,用户可以创buildAbstractProductA的A1或A2。

 interface AbstractFactory { AbstractProductA getProductA(); //Factory Method AbstractProductB getProductB(); //Factory Method } 

但抽象工厂有超过1个工厂方法(例如:2个工厂方法),使用这些工厂方法将创build一组对象/相关对象。 使用Abstract Factory,用户可以创buildAbstractProductA,AbstractProductB的A1,B1对象