什么时候在Dart中使用mixins和何时使用接口? [英] When to use mixins and when to use interfaces in Dart?

查看:118
本文介绍了什么时候在Dart中使用mixins和何时使用接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对接口和抽象类的概念非常熟悉,但对 mixins 的概念却不甚了解.

I'm very familiar with the concepts of interfaces and abstract classes, but not super familiar with the concepts of mixins.

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

Right now, in Dart, every class A defines an implicit interface, which can be implemented by another class B by using the implements keyword. There's no explicit way of declaring interfaces as, for example, in Java, where an interface contains only unimplemented methods (and eventually static variables). In Dart, since interfaces are defined by classes, the methods of the interface A may actually already be implemented, but the class that implements B still needs to override these implementations.

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

We can see that situation from the following piece of code:

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 Dart, a mixin is also defined via ordinary class declarations...

...原则上,每个类都定义一个可以从中提取的mixin.但是,在此建议中,只能从没有声明的构造函数的类中提取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应用于超类,该类通过常规"继承进行扩展,如以下示例所示:

A mixin is basically a class that can define both unimplemented or implemented methods. It's a way to add methods to another class without needing to logically use inheritance. In Dart, a mixin is applied to a super class, that is extended via "normal" inheritance, like in the following example:

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

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

class B extends A with MyMixin {
}

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

In this case, we should note that B does not have to implement any further methods both of A and MyMixin.

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

There's a clear distinction between applying a mixin to a class and inheriting from a class, at least in a language that supports only single-parent inheritance, since, in that case, we could apply many mixins to a class, but a class could just inherit from another class.

实现接口和从类继承之间也存在明显的区别.实现接口的类需要强制实现接口定义的所有方法.

There's also a clear distinction between implementing an interface and inheriting from a class. The class that implements an interface needs to mandatorily implement all methods defined by the interface.

因此,总而言之,实现接口的概念更多地是与实现该接口的类建立契约,而mixins(顾名思义)的概念更多地是重用代码(无需继承)等级).

So, in summary, the concept of implementing an interface is more about establishing a contract with the class that implements the interface, and the concept of mixins (as the name suggests) is more about reusing code (without recurring to an inheritance hierarchy).

何时在Dart中使用mixins和何时使用接口?在设计软件时,是否存在一些至少适用于特殊循环模式的经验法则,那就是最好定义一个mixin并将其应用于超类而不是使我们的类实现一个接口?我希望在可以同时使用接口和mixin,但又使用一个和另一个(出于某种原因)的情况下,进行设计决策的具体示例.

When to use mixins and when to use interfaces in Dart? Are there some rules of thumb for at least special recurrent patterns when designing software where it would be better to define a mixin and applying it to a super class rather than making our class implement an interface? I would appreciate concrete examples of design decisions in a context where both interfaces and mixins could be used, but one is used over the other (for some reason).

推荐答案

Mixins就是关于一个类如何做的事情,它继承并共享了具体的实现. 接口是关于什么是类的全部,它是抽象签名,并保证该类必须满足.这是类型.

Mixins is all about how a class does what it does, it's inheriting and sharing concrete implementation. Interfaces is all about what a class is, it is the abstract signature and promises that the class must satisfy. It's a type.

采用一个实现为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.

Take a class that is implemented as class MyList<T> extends Something with ListMixin<T> .... You can use this class as MyList<int> l = new MyList<int>(); or List<int> l = new MyList<int>(), but you should never write ListMixin<int> l = new MyList<int>(). You can, but you shouldn't, because that is treating ListMixin as a type, and it really isn't intended as one. It's the same reason you should always write Map m = new HashMap(); and not HashMap m = new HashMap(); - the type is Map, it's an implementation detail that it's a HashMap.

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

If you mix in a class (or rather, the mixin derived from a class), then you get all the concrete members of that class in your new mixin class. If you implement a class (or rather, the implicit interface of a class), then you get no concrete members at all, but the abstract signature becomes part of your interface.

某些类可以同时使用,但只有在有意用作混合类(并以此为文档)的情况下,才应使用一个类作为混合类.类作者可以对类进行很多更改,这将破坏它们作为混合的用途.我们不想禁止任何此类更改,对于非mixin类而言,这可能是完全合理的更改,因此将non-mixin类用作mixin很脆弱,并且将来可能会中断.

Some classes can be used as both, but you should only ever use a class as a mixin if it is intended to be used as a mixin (and documented as such). There are many changes that an class author can do to a class that would break their use as a mixin. We don't want to disallow any such change, which could be perfectly reasonable changes for a non-mixin class, so using a non-mixin class as a mixin is fragile and likely to break in the future.

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

On the other hand, a class intended to be used as a mixin is usually all about implementation, so it is likely that there is a similar interface declared as well, and that's what you should use in the implements clause.

因此,如果要实现列表,则可以实现List类并自己完成所有实现,也可以混入ListMixin类以重用某些基本功能.您仍然可以编写implements List<T>,但是可以通过从ListMixin继承而获得.

So, if you want to implement a list, you can either implement the List class and do all the implementation yourself, or mix in the ListMixin class to reuse some base functionality. You can still write implements List<T>, but you get that by inheritance from ListMixin.

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

Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear. If you have multiple inheritance, your class has two (or more) superclasses, and you need to handle conflicts between them, including diamond inheritance, in some way.

Dart中的Mixins通过创建一个新类来工作,该新类将mixin的实现层放在超类之上以创建一个新类-它不是超类的侧面",而是上层",因此在解析查询方面没有任何歧义.

Mixins in Dart work by creating a new class that layers the implementation of the mixin on top of a superclass to create a new class - it is not "on the side" but "on top" of the superclass, so there is no ambiguity in how to resolve lookups.

示例:

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());
  }
}

真正发生的是,您创建了一个新类带计数器的操作".等效于:

What really happens is that you create a new class "Operation with Counter". It's equivalent to:

示例:

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());
  }
}

CounterOperation的mixin应用程序创建一个新类,该类出现在AutoStepOperation的超类链中.

The mixin application of Counter to Operation create a new class, and that class appears in the superclass chain of AutoStepOperation.

如果执行class X extends Y with I1, I2, I3 { ... },则将创建四个类.如果只执行class X extends Y implements I1, I2, I3 { ... },则只能创建一个类.即使I1I2I3都是完全空的抽象接口,使用with来应用它们也等同于:

If you do class X extends Y with I1, I2, I3 { ... } then you create four classes. If you just do class X extends Y implements I1, I2, I3 { ... } then you only create one class. Even if all of I1, I2 and I3 are completely empty abstract interfaces, using with to apply them is equivalent to:

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编写它

You wouldn't write that directly, so you shouldn't write it using with either

这篇关于什么时候在Dart中使用mixins和何时使用接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆