为什么我们需要通过InterfaceFactory来获取对象而不是只传递具体的对象

Why we need to pass the InterfaceFactory to get the object rather than just pass the specific object

"Thinking In Java"中有一个Interface and Factories的例子如下:

(1) 定义游戏和 GameFactory 接口

interface Game { boolean move(); }
interface GameFactory { Game getGame(); }

(2)写出它们的实现

class Checkers implements Game {
     private int moves = 0;
     private static final int MOVES = 3;
     public boolean move() {
        System.out.println("Checkers move " + moves);
        return ++moves != MOVES;
     }
}

class CheckersFactory implements GameFactory {
    public Game getGame() { return new Checkers(); }
}

class Chess implements Game {
    private int moves = 0;
    private static final int MOVES = 4;
    public boolean move() {
       print("Chess move " + moves);
       return ++moves != MOVES;
    }
}

class ChessFactory implements GameFactory {
    public Game getGame() { return new Chess(); }
}

(3) 和客户端代码

public class Games {
    public static void playGame(GameFatory factory) {
        Game s = factory.getGame();
        while (s.move());
    }
    public static void main(String[] args) {
        playGame(new CheckersFactory());
        playGame(new ChessFactory());
    }
}

那么对于客户端代码,我们何必把GameFactory传给playGame的函数呢?

我们可以直接设置Game作为参数如下:

public class Games {
    public static void playGame(Game game) {
        while (game.move());
    }
    public static void main(String[] args) {
        playGame(new Checkers());
        playGame(new Chess());
    }
}

因此我们无需创建 GameFactory 即可获得 Game

所以我想知道工厂方法的优点是什么?

该站点的问题过于宽泛,因为它是关于理论而不是要解决的问题。

但简而言之:这是一种模式,您可以随意使用其他模式。

接口的主要目的是让相同方法的不同实现具有不同的 类。因此,工厂提供了以不同方式创建对象的能力,而不是处理更复杂的构造函数。例如,您需要不同的代码来构造具有相同参数的对象,可能基于 OS 或运行代码的应用程序服务器。那么,你会怎么做呢?然后有一种方法可以为 Linux 提供工厂,另一种方法可以为 Windows 提供工厂,依此类推。

你不需要到处都有...

另一个优点是关于内存管理和垃圾收集器。通过在方法内部使用 new ,很可能会以孤立实例结束,该实例只能通过非常昂贵的完整 GC 进行清理。工厂作为单例永远不会发生,

顺便说一句:在您的简单示例中,既不需要接口也不需要工厂。

同样有多种样式可供选择以适应实际需要。

工厂模式的存在是为了提供函数式编程习惯用法的面向对象版本:提供生成值的仿函数。大多数情况下,您会看到 Factory 与诸如 Strategy 模式之类的东西相结合,其中您有一个接口表示一种做某事的方式,以及该接口的多个具体实现,表示不同的方式来做那件事。工厂的价值在于它抽象了策略的创建

在实践中,我发现这在两种情况下很有用:

  1. 当客户端代码需要选择策略,但库代码需要控制何时以及多久使用该策略时。这与您的游戏示例相匹配:GameFactory 代表 种类 游戏(国际象棋、跳棋等),而 Game 实例代表特定游戏。如果你正在编写一个 class 来玩不同玩家之间的比赛锦标赛,你需要用 GameFactory 来构造它来告诉它玩什么样的游戏,但锦标赛本身会决定开始多少场比赛以及如何操纵每场比赛。 Tournament 不能只做 new Chess()new Checkers() 因为目标是让 Tournament class 独立于游戏类型,这样它就可以重复使用。

  2. 当创建一个值很复杂并且您基本上希望对构造函数进行部分应用时,工厂也很有用。这种方法通常与依赖注入模式一起使用效果很好。例如,假设您现在添加了第三种游戏 PokerPoker 游戏需要一个随机数生成器,以便它知道如何洗牌。您如何将其融入您现有的 GameFactory/Game/Tournament 结构? PokerFactory 对象会将随机数生成器作为参数,并负责将随机数生成器传递给它创建的任何 PokerGame 对象。使用 GameFactory/Game API 的 class,例如 Tournament,不需要知道有些游戏需要随机数生成器,有些则不需要;这些知识将被抽象掉。

退一步说:像大多数面向对象设计模式一样,工厂模式的全部目的是减少耦合增加内聚 .您不希望您的锦标赛 class 与任何特定游戏 耦合 ;解耦代码使程序的不同部分可以相互独立地更改。

更进一步:软件工程的大部分知识和最佳实践都来自大型软件项目,代码行太多,没有人能记住所有的代码这种情况无处不在,而且有这么多人参与这个项目,协调项目不同部分之间的工作成为需要解决的最重要的问题之一。之所以存在如此多的设计模式,是因为它们在程序的不同部分之间定义了 "seams" 以划分您需要同时牢记在脑中的概念。这允许两个或多个程序员同时在不同的隔间上工作,并使您更容易确保每个隔间的正确性。

在您学习编程语言或首次学习编程时编写的那种 "toy" 程序中,这些划分程序的策略可能看起来是多余的或只是令人困惑。事实上,如果你不必要地应用这些类型的模式,那么它们实际上会使事情变得更糟,而不是更好。但是,当您处理大量代码时,这些技术 "tools" 是您的工具带:既可以让您更好地理解现有代码是如何划分的,也可以划分您编写的代码。

TL;DR: "Everything should be made as simple as possible, but no simpler."