oop - 在 Dart 中什么时候使用 mixins 以及什么时候使用接口(interface)?

标签 oop interface dart abstract-class mixins

我非常熟悉接口(interface)和抽象类的概念,但不太熟悉mixins的概念。

现在,在 Dart 中,每个类 A 都定义了一个隐式接口(interface),该接口(interface)可以由另一个类 B 通过使用 implements 来实现关键词。没有明确的方法来声明接口(interface),例如在 Java 中,接口(interface)仅包含未实现的方法(最终包含静态变量)。在 Dart 中,由于接口(interface)是由类定义的,因此接口(interface) A 的方法实际上可能已经实现,但实现 B 的类仍然需要重写这些实现。

我们可以从下面的代码中看到这种情况:

class A {
  void m() {
    print("method m");
  }
}

// LINTER ERROR: Missing concrete implementation of A.m
// Try implementing missing method or make B abstract.
class B implements A {
}

在 Dart 中,mixin 也是通过普通的类声明来定义的...

... In principle, every class defines a mixin that can be extracted from it. However, in this proposal, a mixin may only be extracted from a class that has no declared constructors. This restriction avoids complications that arise due to the need to pass constructor parameters up the inheritance chain.

mixin 基本上是一个可以定义未实现或已实现方法的类。这是一种向另一个类添加方法而无需逻辑上使用继承的方法。在 Dart 中,mixin 应用于父类(super class),该父类(super class)通过“正常”继承进行扩展,如下例所示:

class A {
  void m() {
    print("method m");
  }
}

class MyMixin {
  void f(){
    print("method f");
  }
}

class B extends A with MyMixin {
}

在这种情况下,我们应该注意 B 不必实现 AMyMixin 的任何其他方法。

将 mixin 应用于类和从类继承之间有明显的区别,至少在仅支持单父继承的语言中是这样,因为在这种情况下,我们可以应用许多mixins 到一个类,但一个类可以从另一个类继承。

实现接口(interface)和从类继承之间也有明显的区别。实现接口(interface)的类需要强制实现该接口(interface)定义的所有方法。

所以,总而言之,实现接口(interface)的概念更多的是与实现接口(interface)的类建立契约,而 mixins 的概念(顾名思义)更多的是重用代码(不会重复继承)层次结构)。

在 Dart 中什么时候使用 mixins 以及什么时候使用接口(interface)?在设计软件时,至少有一些特殊的循环模式的经验法则,最好定义一个 mixin 并将其应用于父类(super class),而不是让我们的类实现一个接口(interface)?我很欣赏在可以使用接口(interface)和 mixins 的上下文中设计决策的具体示例,但其中一个被使用而不是另一个(出于某种原因)。

最佳答案

Mixins 是关于一个类如何做它所做的事情,它继承并共享具体的实现。 接口(interface)是关于类是什么的,它是类必须满足的抽象签名和 promise 。这是一种类型

采用一个实现为 class MyList<T> extends Something with ListMixin<T> ... 的类。您可以将此类用作 MyList<int> l = new MyList<int>();List<int> l = new MyList<int>() ,但你永远不应该写 ListMixin<int> l = new MyList<int>() 。你可以,但你不应该,因为那是治疗ListMixin作为一种类型,但它实际上并不是一种类型。 这与您应该始终写 Map m = new HashMap(); 的原因相同。而不是HashMap m = new HashMap(); - 类型Map ,这是一个实现细节,它是 HashMap .

如果您混入一个类(或者更确切地说,从类派生的 mixin),那么您将在新的 mixin 类中获得该类的所有具体成员。 如果您实现一个类(或者更确切地说,类的隐式接口(interface)),那么您根本没有任何具体成员,但抽象签名成为您的接口(interface)的一部分。

有些类可以同时用作两者,但只有当某个类打算用作 mixin 时才应将其用作 mixin(并记录为此类)。类作者可以对类进行许多更改,从而破坏其作为 mixin 的用途。我们不想禁止任何此类更改,这对于非 mixin 类来说可能是完全合理的更改,因此使用非 mixin 类作为 mixin 很脆弱,并且将来可能会崩溃。

另一方面,打算用作 mixin 的类通常都是关于实现的,因此很可能也声明了一个类似的接口(interface),这就是您应该在 Implements 子句中使用的接口(interface)。

所以,如果你想实现一个列表,你可以实现 List类并自己完成所有实现,或者混合在 ListMixin 中类来重用一些基本功能。您仍然可以写implements List<T> ,但是你可以通过继承 ListMixin 得到它.

Mixins 不是一种获得经典意义上的多重继承的方法。 Mixins 是一种抽象和重用一系列操作和状态的方法。 它类似于通过扩展类获得的重用,但它与单继承兼容,因为它是线性的。 如果您有多重继承,您的类有两个(或更多)父类(super class),您需要以某种方式处理它们之间的冲突,包括菱形继承。

Dart 中的 Mixin 通过创建一个新类来工作,该新类将 mixin 的实现分层在父类(super class)之上以创建一个新类 - 它不是父类(super class)的“侧面”而是“顶部”,因此有如何解决查找问题没有任何歧义。

示例:

class Counter {
  int _counter = 0;
  int next() => ++_counter;
}
class Operation {
  void operate(int step) { doSomething(); }
}
class AutoStepOperation extends Operation with Counter {
  void operate([int step]) {
    super.operate(step ?? super.next());
  }
}

真正发生的是您创建了一个新类“Operation with Counter”。它相当于:

示例:

class Counter {
  int _counter = 0;
  int next() => ++_counter;
}
class Operation {
  void operate(int step) { doSomething(); }
}
class $OperationWithCounter = Operation with Counter;
class AutoStepOperation extends $OperationWithCounter {
  void operate([int step]) {
    super.operate(step ?? super.next());
  }
}

Counter的mixin应用至Operation创建一个新类,该类出现在AutoStepOperation的父类(super class)链中.

如果你这样做class X extends Y with I1, I2, I3 { ... }然后你创建四个类。如果你这样做class X extends Y implements I1, I2, I3 { ... }那么你只创建一个类。即使全部I1 , I2I3是完全空的抽象接口(interface),使用 with应用它们相当于:

class $X1 extends Y implements I1 { /* no members in I1 */ }
class $X2 extends $X1 implements I2 { /* no members in I2 */ }
class $X3 extends $X2 implements I3 { /* no members in I3 */ }
class X extends $X3 { /* members of X */ }

你不会直接写它,所以你不应该使用 with 来写它要么

关于oop - 在 Dart 中什么时候使用 mixins 以及什么时候使用接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45901297/

相关文章:

php - 哪个更好 : Acting on an object or from within an object with a dependency injected?

c++ - OOP - 什么是类层次结构的顶部

dart - 如何动态实例化一个类(Function.apply for class)?

flutter - 如何在Flutter中正确添加共享插件

Python 上下文对象更好地使用字典或属性?

java - Java 中的 "static{}"是什么?

C++接口(interface)编译

c# - 为什么接口(interface)不起作用,但抽象类可以使用泛型类约束?

C# 接口(interface)实现

javascript - 如何在 Dart 中使用 onbeforeunload