什么是 mixin,它为什么有用?

新手上路,请多包涵

Programming Python 中,Mark Lutz 提到了 mixin 一词。我来自 C/C++/C# 背景,之前没有听说过这个词。什么是混音?

这个例子 的两行之间阅读(我已经链接到它,因为它很长),我假设这是使用多重继承来扩展一个类而不是正确的子类化的情况。这是正确的吗?

为什么我要这样做而不是将新功能放入子类中?就此而言,为什么混合/多重继承方法比使用组合更好?

混合继承与多重继承有什么区别?这只是语义问题吗?

原文由 TarkaDaal 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 577
2 个回答

mixin 是一种特殊的多重继承。使用mixin主要有两种情况:

  1. 你想为一个类提供很多可选特性。
  2. 你想在很多不同的类中使用一个特定的特性。

对于第一个示例,请考虑 werkzeug 的请求和响应系统。我可以通过说来制作一个普通的旧请求对象:

 from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

如果我想添加接受标头支持,我会这样做

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

如果我想创建一个支持接受标头、etags、身份验证和用户代理支持的请求对象,我可以这样做:

 from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

区别是微妙的,但在上面的例子中,mixin 类并不是独立存在的。在更传统的多重继承中, AuthenticationMixin (例如)可能更像 Authenticator 。也就是说,该类可能被设计为独立存在。

原文由 Jason Baker 发布,翻译遵循 CC BY-SA 4.0 许可协议

首先,您应该注意 mixin 仅存在于多重继承语言中。您不能在 Java 或 C# 中进行混合。

基本上,mixin 是一种独立的基类型,它为子类提供有限的功能和多态共振。如果您正在考虑使用 C#,请考虑一个您不必实际实现的接口,因为它已经实现了;您只需继承它并从其功能中受益。

Mixin 的范围通常很窄,不打算扩展。

[编辑——至于为什么:]

既然你问了,我想我应该说明原因。最大的好处是您不必一遍又一遍地自己做。在 C# 中,mixin 可以受益的最大地方可能是 Disposal 模式。每当您实施 IDisposable 时,您几乎总是希望遵循相同的模式,但您最终会编写并重写相同的基本代码,但会有细微的变化。如果有一个可扩展的 Disposal mixin,您可以节省很多额外的输入。

[编辑 2——回答你的其他问题]

混合继承与多重继承的区别是什么?这只是语义问题吗?

是的。 mixin 和标准多重继承之间的区别只是语义问题;具有多重继承的类可能会使用 mixin 作为多重继承的一部分。

mixin 的要点是创建一个类型,该类型可以通过继承“混入”任何其他类型,而不影响继承类型,同时仍然为该类型提供一些有益的功能。

再一次,考虑一个已经实现的接口。

我个人不使用 mixins,因为我主要使用一种不支持它们的语言进行开发,所以我很难想出一个像样的例子来提供那个“啊哈!”给你的时刻。但我会再试一次。我将使用一个人为设计的示例——大多数语言已经以某种方式提供了该功能——但希望这将解释应该如何创建和使用 mixins。开始:

假设您有一个类型,您希望能够将其序列化为 XML 或从 XML 序列化。您希望该类型提供一个“ToXML”方法,该方法返回一个字符串,该字符串包含具有该类型数据值的 XML 片段,以及一个“FromXML”,该方法允许该类型从字符串中的 XML 片段重建其数据值。同样,这是一个人为的示例,因此您可能使用文件流或您语言的运行时库中的 XML Writer 类……随便什么。重点是您希望将对象序列化为 XML 并从 XML 中获取一个新对象。

此示例中的另一个重点是您希望以通用方式执行此操作。您不想为要序列化的每个类型都实现“ToXML”和“FromXML”方法,您需要一些通用方法来确保您的类型能够做到这一点并且它能够正常工作。你想要代码重用。

如果您的语言支持它,您可以创建 XmlSerializable 混合宏来为您完成工作。此类型将实现 ToXML 和 FromXML 方法。它将使用一些对示例不重要的机制,能够从它混合的任何类型中收集所有必要的数据,以构建 ToXML 返回的 XML 片段,并且它同样能够在 FromXML 时恢复该数据叫。

而且..就是这样。要使用它,您需要从 XmlSerializable 继承任何需要序列化为 XML 的类型。每当您需要序列化或反序列化该类型时,只需调用 ToXML 或 FromXML。事实上,由于 XmlSerializable 是一个完全成熟的类型和多态性,您可以想象构建一个对您的原始类型一无所知的文档序列化程序,它只接受,比如说,一个 XmlSerializable 类型的数组。

现在想象将此场景用于其他事情,例如创建一个 mixin 以确保将其混合在其中的每个类都记录每个方法调用,或者创建一个 mixin 为混合它的类型提供事务性。列表可以继续下去。

如果您只是将 mixin 视为一种小型基础类型,旨在为一种类型添加少量功能而不影响该类型,那么您就是黄金。

希望。 :)

原文由 Randolpho 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题