设计模式:工厂vs工厂方法与抽象工厂

我正在从网站阅读设计模式

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

工厂 - 创建对象而不向客户端公开实例化逻辑,并通过公共接口引用新创建的对象。 是Factory Method的简化版本

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

抽象工厂 - 提供创建相关对象系列的界面,而无需明确指定其类。

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

任何人都可以告诉我

  • 这三种模式如何彼此不同?
  • 何时使用哪个?
  • 还有,如果可能的话,任何与这些模式相关的Java示例?

  • 所有三种工厂类型都做同样的事情:它们是“智能构造函数”。

    假设您想要创建两种水果:Apple和Orange。

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

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

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

    工厂方法

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

    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()的常用功能:

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

    抽象工厂

    抽象工厂通常用于诸如依赖注入/策略之类的事情,当你希望能够创建一系列需要“同类”的对象,并且拥有一些通用的基类时。 这是一个模糊的水果相关的例子。 这里的用例是我们要确保我们不会在Apple上不小心使用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();
      }
    }
    

    工厂 - 单独工厂类创建复杂对象。

    例如:FruitFactory类来创建Fruit的对象

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

    工厂方法 - 而不是整个单独的工厂类,只需在该类中添加一个方法作为工厂。

    例如:

    Calendar.getInstance() (Java's Calendar)
    

    抽象工厂方法 - 工厂工厂

    例如:假设我们想为电脑零件建造工厂。 所以有几种类型的电脑,如笔记本电脑,台式机,服务器。

    所以对于每种康普特类型我们都需要工厂。 所以我们创建了一个像下面这样的工厂的高级工厂

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

    现在这3个本身又是工厂。 (您将与PartFactory本身打交道,但根据您在抽象工厂中提供的内容,将会有单独的实现)

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

    编辑:根据评论中的反对意见编辑提供抽象工厂的确切接口。


  • 这三种模式如何彼此不同?
  • 工厂:创建对象而不将实例化逻辑暴露给客户端。

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

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

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

  • 何时使用哪个?
  • 工厂:客户只需要一个类,并不关心它得到的具体实现。

    工厂方法:客户端不知道在运行时需要创建哪些具体类,但只想获得可以完成这项工作的类。

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

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

  • 还有,如果可能的话,任何与这些模式相关的Java示例?
  • 工厂和FactoryMethod

    意图:

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

    UML图:

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

    ConcreteProduct:实现产品界面

    创建者:声明工厂方法

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

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

    代码片段:

    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类。

  • Game是所有类型游戏的界面。 它定义了复杂的方法: createGame()

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

  • public Game getGame(String gameName)FactoryMethodIGameFactory

  • GameFactory在构造函数中预先创建不同类型的游戏。 它实现了IGameFactory工厂方法。

  • 游戏名称作为命令行参数传递给NotStaticFactoryDemo

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

  • 与其他创作模式的比较:

  • 设计从使用工厂方法开始(更简单,更可定制,子类更多),并向设计师发现需要更多灵活性的抽象工厂,原型或构建器 (更灵活,更复杂)

  • 抽象工厂类通常使用工厂方法实现,但它们也可以使用Prototype实现

  • 进一步阅读的参考资料:来源制作设计模式

    链接地址: http://www.djcxy.com/p/50115.html

    上一篇: Design Patterns: Factory vs Factory method vs Abstract Factory

    下一篇: Can you explain Liskov Substitution Principle with a good C# example?