Oop 控制的合成与反转

Oop 控制的合成与反转,oop,design-patterns,Oop,Design Patterns,我刚刚遇到了设计松耦合软件体系结构的控制反转方法(使用依赖注入实现)。根据我的理解,IOC方法旨在通过在另一个类中实例化一个类的对象来解决与类之间紧密耦合相关的问题,这在理想情况下是不会发生的(按照模式)。我的理解正确吗 如果上述情况属实,那么组合或has-a关系(OO最基本、最重要的方面)又如何呢。例如,我使用已经定义的链表类编写堆栈类,因此在堆栈类中实例化链表类。但根据国际奥委会的说法,这将导致紧密耦合,从而导致糟糕的设计。这是真的吗?在这里,我有点混淆了作文和国际奥委会之间的关系 据我所知

我刚刚遇到了设计松耦合软件体系结构的控制反转方法(使用依赖注入实现)。根据我的理解,IOC方法旨在通过在另一个类中实例化一个类的对象来解决与类之间紧密耦合相关的问题,这在理想情况下是不会发生的(按照模式)。我的理解正确吗

如果上述情况属实,那么组合或has-a关系(OO最基本、最重要的方面)又如何呢。例如,我使用已经定义的链表类编写堆栈类,因此在堆栈类中实例化链表类。但根据国际奥委会的说法,这将导致紧密耦合,从而导致糟糕的设计。这是真的吗?在这里,我有点混淆了作文和国际奥委会之间的关系

据我所知,国际奥委会的方法旨在解决相关问题 通过实例化 在另一个类中创建一个理想情况下不会发生的类(根据 模式)。我的理解正确吗

接近,但你有点偏离。在定义类(Java中的接口)之间的契约时,会解决紧耦合问题。因为您需要合同(接口)的实现,所以在某些时候必须提供这些实现。国际奥委会是提供实施的一种方式,但不是唯一的方式。所以紧耦合实际上和控制反转是正交的(这意味着它不是直接相关的)

更具体地说,可以使用松耦合,但不使用IoC。IoC的一部分是实现来自组件外部。考虑定义使用接口实现的类的情况。当您测试该类时,您可能会提供一个mock。当您将模拟传递给被测试的类时,您没有使用IoC。但是,当您启动应用程序时,IoC容器决定传递给您的类的内容,这就是IoC

例如,我使用链表类编写堆栈类 已经定义,所以我在堆栈中实例化了一个链表类 班级。但根据国际奥委会的说法,这将导致紧密耦合,因此 糟糕的设计。这是真的吗?在这里,我有点混淆了作文和写作之间的关系 或者和国际奥委会有关系

是和否。一般来说,你不需要完全抽象应用程序中的每一项功能。你可以,而且纯粹主义者可能会,但这可能是乏味和过度的

在这种情况下,您可以将堆栈视为一个黑盒,而不使用IoC进行管理。记住,堆栈本身是松散耦合的,因为堆栈的行为可以抽象出来。此外,考虑以下两个定义

class StackImpl implements Stack {
   private List backingList
vs

第一种方法远远优于第二种方法,正是因为它更容易更改列表实现;i、 e.您已经提供了松耦合


这就是我所能接受的。此外,如果您正在使用组合,您当然可以配置大多数IoC容器(如果不是全部的话)来将内容传递给构造函数或调用setter,这样您仍然可以拥有一个has-a关系。

堆栈示例中的紧密耦合来自于表示特定列表类型的堆栈。IOC允许堆栈类型的创建者提供要使用的确切列表实现(例如,出于性能或测试目的),并意识到堆栈不(至少不应该)关心列表的确切类型,只要它具有特定接口(堆栈想要使用的方法)concere实现提供了所需的语义(例如,遍历列表将允许访问按添加顺序添加到列表中的所有元素)。

良好的IoC实现可以实现“has a”模式,但只是抽象子元素的实现

例如,根据您的设计,每个业务层类可能“有一个”异常处理程序;使用IoC,您可以定义它,以便在运行时实际实例化的异常处理程序在不同的环境中是不同的


IoC的最大价值在于,如果你正在进行大量的自动化测试;在这些场景中,您可以在测试环境中实例化模拟数据访问组件,但在生产环境中实例化真实的数据访问组件,从而保持测试的整洁。IoC的缺点是调试比较困难,因为一切都比较抽象。

我对控制反转的理解也有疑问。(这似乎是一个好的OO设计原则的应用,有一个别致的名字)所以,让我假设你是一个初学者,分析你的例子,并澄清我的想法

我们应该首先定义一个接口
IStack

interface IStack<T>
{
    bool IsEmpty();
    T Pop();
    void Push(T item);
}
所以
StackWithLinkedList
完全拥有
列表
;构建它不需要外部的任何帮助,也不需要任何灵活性(这一行永远不会改变),而且
StackWithLinkedList
的客户端也不在乎(他们无法访问列表)。简而言之,这不是一个讨论控制反转的好例子:我们不需要任何控制反转

让我们讨论一个类似的例子,
PriorityQueue

以便:

  • 如果
    比较(左、右)<0
    则左<右(在某种意义上)

  • 如果
    比较(左、右)>0
    则左>右(在某种意义上)

  • 如果
    CompareTo(left,right)=0,则left=right(在某种意义上)

  • (我们还需要
    比较以保持一致,等等,但这是另一个主题)

问题是如何初始化
进行比较

一个选项可能是,-让我们假设某个地方有一个通用的比较创建者-使用比较创建者。(我同意,这个例子有点傻)

让我们检查一下:

  • <
    interface IStack<T>
    {
        bool IsEmpty();
        T Pop();
        void Push(T item);
    }
    
    class StackWithLinkedList<T> : IStack<T>
    {
       private LinkedList<T> list;
    
       public StackWithLinkedList<T>()
       {
          list = new LinkedList<T>();
       }
    }
    
    interface IPriorityQueue<T>
    {
        bool IsEmpty();
        T Dequeue();
        void Enqueue(T item);
    }
    
    class PriorityQueue<T> : IPriorityQueue<T>
    {
       private Func<T,T,int> CompareTo;
       private LinkedList<T> list;
       //bla bla.
    }
    
    public PriorityQueue()
    {
        this.CompareTo = ComparisonCreator<T>.CreateComparison();
        this.list = new LinkedList<T>();
    }
    
    public PriorityQueue(Func<T,T,int> CompareTo)
    {
        this.CompareTo = CompareTo;
        this.list = new LinkedList<T>();
    }