为了账号安全,请及时绑定邮箱和手机立即绑定

告诉低级对象使用哪些工厂的好方法是什么?

告诉低级对象使用哪些工厂的好方法是什么?

潇潇雨雨 2021-10-28 15:44:02
我最近学习了很多关于设计模式的知识,特别是依赖注入。我很确定抽象工厂是实例化具有依赖关系的对象的好方法。但是我不确定如何告诉低级对象他们应该使用哪些工厂。考虑以下简化示例:我有一个类 MainProgram (我只是为了表示我的程序中还有其他代码......)在运行时的某个时刻,我想用抽象工厂实例化 IGeneticAlgorithm:public class MainProgram{    private AbstractGeneticAlgorithm geneticAlgorithm;    private IGeneticAlgorithmFactory geneticAlgorithmFactory;    public MainProgram(IGeneticAlgorithmFactory geneticAlgorithmFactory){        this.geneticAlgorithmFactory = geneticAlgorithmFactory;    }    private void makeGeneticAlgorithm(){        geneticAlgorithm = geneticAlgorithmFactory.getInstance();    }    public static void main(String[] args){        MainProgram mainProgramm = new MainProgram(new FastGeneticAlgorithmFactory());        //...    }}public interface IGeneticAlgorithmFactory{    public IGeneticAlgorithm getInstance();}public class FastGeneticAlgorithmFactory implements IGeneticAlgorithmFactory{    public IGeneticAlgorithm getInstance(){        return new FastGeneticAlgorithm();    }}public abstract class AbstractGeneticAlgorithm{    private IIndividual individual;    private IIndividualFactory individualFactory;    private void makeIndividual(){        individual = individualFactory.getInstance();    }    //...}在运行时的某个时刻,我想在我的 GeneticAlgorithm 中实例化一个 IIndividual。IIndividual 不能在启动时实例化。能够在运行时实例化 IIndividual 的需要来自遗传算法的工作方式,基本上在选择-重组-变异的每个步骤之后,必须实例化新的个体。(有关更多信息,请参阅https://en.wikipedia.org/wiki/Genetic_algorithm)。我选择在这里只给 AbstractGeneticAlgorithm 一个 IIndividual 以保持这个例子简单。public class FastGeneticAlgorithm implements AbstractGeneticAlgorithm{    private IIndividual individual;     private IIndividualFactory individualFactory;}使 SmallIndividualFactory 成为 FastGeneticAlgorithm 中的静态变量在我看来并不是好的做法。并将 SmallIndividualFactory 传递给 Main,以便 Main 可以将其传递给 FastGeneticAlgorithm 似乎也不正确。我的问题是如何解决这个问题?谢谢你。
查看完整描述

1 回答

?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

在使用依赖注入时,抽象工厂模式经常被过度使用。这并不意味着它本身就是一个糟糕的模式,但在许多情况下,抽象工厂模式有更合适的替代方案。这在依赖注入原则、实践和模式(第6.2段)中有详细描述,其中描述:

  • 不应该使用抽象工厂来创建短期的、有状态的依赖项,因为依赖项的使用者应该无视它的生命周期;从消费者的角度来看,概念上应该只有一个服务实例。

  • 抽象工厂通常违反依赖倒置原则 (DIP),因为它们的设计通常不适合消费者,而 DIP 声明:“抽象由上层/策略层拥有”,这意味着抽象的消费者应该决定其以最适合其需求的方式塑造和定义抽象。让消费者同时依赖工厂依赖和它产生的依赖会使消费者变得复杂。

这意味着:

  • Abstract 应避免使用无参数 create 方法的工厂,因为这意味着依赖项是短暂的,并且其生命周期由消费者控制。相反,应该为概念上需要创建运行时数据(由消费者提供)的依赖项创建抽象工厂。

  • 但即使工厂方法包含参数,也必须小心以确保确实需要抽象工厂。代理模式通常(但不总是)更适合,因为它允许消费者有一个单一的依赖,而不是依赖于工厂和它的产品。

依赖注入促进了应用程序启动路径中类的组合,本书将这一概念称为组合根。组合根是靠近该应用程序入口点(您的Main方法)的位置,它了解系统中的每个其他模块。

因为 Composition Root 依赖于系统中的所有其他模块,所以在 Composition Root 中消耗 Abstract Factories 通常意义不大。例如,如果您定义了一个IXFactory抽象来产生IX依赖关系,但 Composition Root 是该IXFactory抽象的唯一使用者,那么您正在解耦一些不需要解耦的东西:Composition Root 本质上以任何方式了解系统的所有其他部分.

您的IGeneticAlgorithmFactory抽象似乎就是这种情况。它的唯一消费者似乎是您的组合根。如果这是真的,则可以简单地删除此抽象及其实现,并且可以简单地将其getInstance方法中的代码移动到MainProgram类中(该类用作您的组合根)。

我很难理解你的IIndividual实现是否需要一个工厂(至少 14 年前我在大学实现了遗传算法),但它们看起来更像是运行时数据而不是“真正的”依赖项。所以工厂在这里可能有意义,尽管要验证它们的创建和实现是否必须隐藏在抽象之后。当直接FastGeneticAlgorithm创建SmallIndividual实例时,我可以想象应用程序是足够松散耦合的。然而,这只是一个疯狂的猜测。

最重要的是,最佳实践是应用构造函数注入。这可以防止时间耦合。此外,不要像您AbstractGeneticAlgorithm一样在定义的抽象中指定实现依赖项。这使抽象成为泄漏抽象(这是 DIP 违规)。相反,通过将它们声明为实现上的构造函数参数来声明依赖项(FastGeneticAlgorithm在您的情况下)。

但即使存在IIndividualFactory,您的代码也可以通过以下最佳实践来简化:

// Use interfaces rather than base classes. Prefer Composition over Inheritance.

public interface IGeneticAlgorithm { ... }

public interface IIndividual { ... }

public interface IIndividualFactory {

    public IIndividual getInstance();

}


// Implementations

public class FastGeneticAlgorithm implements IGeneticAlgorithm {

    private IIndividualFactory individualFactory;


    // Use constructor injection to declare the implementation's dependencies

    public FastGeneticAlgorithm(IIndividualFactory individualFactory) {

        this.individualFactory = individualFactory;

    }

}


public class SmallIndividual implements IIndividual { }

public class SmallIndividualFactory implements IIndividualFactory {

    public IIndividual getInstance() {

        return new SmallIndividual();

    }

}


public static class Program {

    public static void main(String[] args){

        AbstractGeneticAlgorithm algoritm = CreateAlgorithm();

        algoritm.makeIndividual();

    }


    private AbstractGeneticAlgorithm CreateAlgorithm() {

        // Build complete object graph inside the Composition Root

        return new FastGeneticAlgorithm(new SmallIndividualFactory());

    }

}


查看完整回答
反对 回复 2021-10-28
  • 1 回答
  • 0 关注
  • 139 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信