离散特征和连续特征混合_混合蛋白和特征

2023-10-26

Java语言的开发人员精通C ++和其他包含多重继承的语言,从而使类可以从任意数量的父级继承。 多重继承的问题之一是无法确定派生自哪个父继承功能。 这个问题称为菱形问题 (请参阅参考资料 )。 多重继承中固有的菱形问题和其他复杂性启发了Java语言设计人员选择单一继承加接口。

接口定义语义,但不定义行为。 它们很好地用于定义方法签名和数据抽象,并且所有Java.next语言都支持Java接口,而无需进行必要的更改。 但是,某些跨领域的关注点不适用于单继承+接口模型。 这种错位导致需要Java语言的外部机制,例如面向方面的编程。 两种Java.next语言-Groovy和Scala-通过使用称为mixin或trait的语言构造在另一个扩展级别上处理此类问题。 本文介绍了Groovy mixins和Scala特性,并展示了如何使用它们。 (Clojure通过协议处理了许多相同的功能,我在Java.next中介绍了该协议:没有继承的扩展,第2部分 。)

关于本系列

Java的遗产将是平台,而不是语言。 JVM上运行着200多种语言,不可避免的是,其中之一最终将取代Java语言,成为对JVM进行编程的最佳方法。 本系列探讨了三种下一代JVM语言:Groovy,Scala和Clojure,对新功能和范例进行了比较和对比,以使Java开发人员可以一窥他们不久的将来。

混合蛋白

冰淇淋的灵感

mixin概念起源于Flavors语言(请参阅参考资料 )。 这个概念的灵感来自发生语言发展的办公室附近的一家冰​​淇淋店。 冰淇淋店提供了普通口味的冰淇淋,以及客户想要的任何其他“混搭”(碎糖条,巧克力粉,坚果等)。

一些早期的面向对象的语言在单个代码块中一起定义了类的属性和方法,从而完成了类定义。 用其他语言,开发人员可以在一个地方定义属性,但是将方法定义推迟到以后再在适当的时候将它们“混合”到类中。 随着面向对象语言的发展,mixin如何与现代语言一起工作的细节也随之发展。

在Ruby,Groovy和类似语言中,mixins扩展了现有类的层次结构,作为接口和父类之间的交叉。 像接口一样,mixin都充当instanceof检查的类型,并且遵循相同的扩展规则。 您可以将无限数量的mixin应用于一个类。 与接口不同,mixin不仅可以指定方法签名,还可以实现签名的行为。

在最早包含mixin的语言中,mixin仅包含方法,而没有诸如成员变量之类的状态。 现在,许多语言(其中包括Groovy)都包含有状态的mixin。 斯卡拉特质也表现得很庄重。

Groovy Mixins

Groovy通过metaClass.mixin()方法或@Mixin批注实现了mixins。 ( @Mixin批注依次将Groovy抽象语法树(AST)转换用于必需的元编程管道。)清单1中的示例使用metaClass.mixin()来使File类具有创建压缩ZIP文件的能力:

清单1.将zip()方法混合到File类中
class Zipper {

  def zip(dest) {
      new ZipOutputStream(new FileOutputStream(dest))
          .withStream { ZipOutputStream zos ->
            eachFileRecurse { f ->
              if (!f.isDirectory()) {
                zos.putNextEntry(new ZipEntry(f.getPath()))
                new FileInputStream(f).withStream { s ->
                    zos << s
                    zos.closeEntry()
                }
              }
            }
          }
  }

  static {
    File.metaClass.mixin(Zipper)
  }

}

在清单1中,我创建了一个Zipper类,其中包含新的zip()方法和将该方法添加到现有File类的连线。 zip()方法的(不起眼的)Groovy代码以递归方式创建一个ZIP文件。 清单的最后一部分通过使用静态初始化程序将新方法连接到现有的File类中。 与Java语言一样,静态类初始化程序在类加载时运行。 静态初始化程序是扩充代码的理想位置,因为可以确保初始化程序在依赖于增强功能的任何代码之前运行。 在清单1中mixin()方法将zip()方法添加到File

在“ 没有继承的扩展,第1部分 ”中,我介绍了两种Groovy机制ExpandoMetaClass和类别类,可用于在现有类上添加,更改或删除方法。 使用mixin()添加方法与使用ExpandoMetaClass或类别类添加方法具有相同的最终结果,但是实现方式有所不同。 考虑清单2中的mixin示例:

清单2.操作继承层次结构的Mixins
import groovy.transform.ToString

class DebugInfo {
  def getWhoAmI() {
    println "${this.class} <- ${super.class.name} 
    <<-- ${this.getClass().getSuperclass().name}"
  }
}

@ToString class Person {
  def name, age
}

@ToString class Employee extends Person {
  def id, role
}

@ToString class Manager extends Employee {
  def suiteNo
}


Person.mixin(DebugInfo)

def p = new Person(name: "Pete", age: 33)
def e = new Employee(name: "Fred", age: 25, id:"FRE", role:"Manager")
def m = new Manager(name: "Burns", id: "001", suiteNo: "1A")

p.whoAmI
e.whoAmI
m.whoAmI

在清单2中,我创建了一个名为DebugInfo的类,其中包含一个getWhoAmI属性定义。 在此属性中,我打印出该类的一些详细信息,例如当前类以及supergetClass().getSuperClass()属性对父项的观点。 接下来,我创建一个简单的类层次结构,该层次结构由PersonEmployeeManager

然后,我将DebugInfo类混合到Person类中,该类位于层次结构的顶部。 因为whoAmI属性存在于Person ,所以它也存在于其子类中。

在输出中,您可以看到(并且可能会惊讶地看到) DebugInfo类将自身暗示到继承层次结构中:

class Person <- DebugInfo <<-- java.lang.Object
class Employee <- DebugInfo <<-- Person
class Manager <- DebugInfo <<-- Employee

Mixin方法必须适合Groovy已经很复杂的关系才能进行方法解析。 清单2的父类的不同返回值反映了这些关系。 方法解析的详细信息超出了本文的范围。 但是要警惕在mixin方法中依赖thissuper (以各种形式)的值。

使用类别类或ExpandoMetaClass不会影响继承,因为您可以对类进行更改,而不是混入不同的新行为。 缺点是无法将这些更改识别为明显的分类工件。 如果我使用类别类或ExpandoMetaClass将相同的三个方法添加到多个类中,则没有特定的代码工件(例如接口或类签名)标识现在存在的通用性。 mixin的优点是Groovy会将使用mixin作为类别的所有内容都对待。

类别类的实现烦恼之一是严格的类结构。 您必须使用所有静态方法(每个方法至少接受一个参数)来表示正在扩充的类型。 当消除此类样板代码时,元编程最有用。 @Mixin批注的出现使创建类别并将其混合到类中变得更加容易。 清单3(Groovy文档的摘录)说明了类别和mixin之间的协同作用:

清单3.组合类别和混合
interface Vehicle {
    String getName()
}

@Category(Vehicle) class Flying {
    def fly() { "I'm the ${name} and I fly!" }
}

@Category(Vehicle) class Diving {
    def dive() { "I'm the ${name} and I dive!" }
}

@Mixin([Diving, Flying])
class JamesBondVehicle implements Vehicle {
    String getName() { "James Bond's vehicle" }
}

assert new JamesBondVehicle().fly() ==
       "I'm the James Bond's vehicle and I fly!"
assert new JamesBondVehicle().dive() ==
       "I'm the James Bond's vehicle and I dive!"

在清单3中,我创建了一个简单的Vehicle接口和两个类别类( FlyingDiving )。 @Category注释符合样板代码要求。 定义类别后,将它们混合到JamesBondVehicle ,从而附加两种行为。

Groovy中的类ExpandoMetaClass和mixins的交集是激进的语言发展的必然结果。 三种技术有明显的重叠,但每种技术都有其各自的最佳表现。 如果从头开始对Groovy进行重新设计,那么作者可能会将这三种技术的许多功能整合为一个机制。

斯卡拉特质

Scala通过traits实现代码重用, traits是类似于mixin的核心语言功能。 Scala的特点是有状态的-它们可以同时包含方法和字段-和他们玩相同instanceof角色界面在Java语言中播放。 特质和混合素都解决了许多相同的问题,但特质得到了更多语言严格性的支持。

在“ Groovy,Scala和Clojure的共同点,第1部分 ”中,我使用了复数类来说明Scala中的运算符重载。 我没有在该类中实现布尔比较运算符,因为Scala的内置Ordered特性使实现变得微不足道。 清单4显示了一个改进的复数类,它利用了Ordered特性:

清单4.可比复数
final class Complex(val real: Int, val imaginary: Int) extends Ordered[Complex] {
  require (real != 0 || imaginary != 0)

  def +(operand: Complex) =
      new Complex(real + operand.real, imaginary + operand.imaginary)

  def +(operand: Int) =
    new Complex(real + operand, imaginary)

  def -(operand: Complex) =
    new Complex(real - operand.real, imaginary - operand.imaginary)

  def -(operand: Int) =
    new Complex(real - operand, imaginary)


  def *(operand: Complex) =
      new Complex(real * operand.real - imaginary * operand.imaginary,
          real * operand.imaginary + imaginary * operand.real)

  override def toString() =
      real + (if (imaginary < 0) "" else "+") + imaginary + "i"

  override def equals(that: Any) = that match {
    case other : Complex => (real == other.real) && (imaginary == other.imaginary)
    case _ => false
  }

  override def hashCode(): Int =
    41 * ((41 + real) + imaginary)

  def compare(that: Complex) : Int = {
    def myMagnitude = Math.sqrt(this.real ^ 2 + this.imaginary ^ 2)
    def thatMagnitude = Math.sqrt(that.real ^ 2 + that.imaginary ^ 2)
    (myMagnitude - thatMagnitude).round.toInt
  }
}

我没有实现清单4中的><<=>=运算符,但是我可以在清单5所示的复数实例上调用它们:

清单5.测试比较
class ComplexTest extends FunSuite {

  test("comparison") {
    assert(new Complex(1, 2) >= new Complex(3, 4))
    assert(new Complex(1, 1) < new Complex(2,2))
    assert(new Complex(-10, -10) > new Complex(1, 1))
    assert(new Complex(1, 2) >= new Complex(1, 2))
    assert(new Complex(1, 2) <= new Complex(1, 2))
  }

}

没有用于比较复数的数学定义方法,因此在清单4中,我使用了一种公认的算法来比较数的大小。 我使用Ordered[Complex]特征extend了类定义,该特征混合了参数化类的布尔运算符。 为了使特征发挥作用,注入的运算符必须比较两个复数,这是compare()方法的目的。 如果您尝试extend Ordered特性但不提供所需的方法,则编译器消息会通知您,由于缺少必需的方法,您的类必须被声明为abstract

特性在Scala中有两个明确定义的角色:丰富接口和执行可堆叠的修改 。

丰富的界面

当Java开发人员设计接口时,他们面临着取决于便利性的难题:您应该创建一个包含许多方法的富接口,还是创建仅包含几个方法的瘦接口? 丰富的界面对其用户来说更为方便,因为它提供了广泛的方法选项,但是大量的方法使该界面更难以实现。 精简接口存在相反的问题。

性状解决了富人与瘦者之间的难题。 您可以在瘦界面中创建核心功能,然后使用特征对其进行扩充以提供更丰富的功能。 例如,在Scala中,“ Set特征实现集合的共享功能,而您选择的子特征( mutableimmutable )确定集合是否可变。

可堆叠修改

在Scala中,特征的另一个常见用法是可堆叠的修改 。 使用特征,您可以更改现有方法并添加新方法,而super提供了将链返回到先前特征的实现的访问权限。

清单6展示了带有数字队列的可堆叠修改:

清单6.构建可堆叠的修改
abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}

import scala.collection.mutable.ArrayBuffer

class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0)
  def put(x: Int) { buf += x }
}

trait Squaring extends IntQueue {
  abstract override def put(x: Int) { super.put(x * x) }
}

在清单6中,我创建了一个简单的IntQueue类。 然后,我构建一个包含ArrayBuffer的可变版本。 Squaring特征扩展任何IntQueue并在将值插入队列时自动平方值。 对Squaring特征中的super的调用提供了对堆栈中先前特征的访问。 只要第一个被覆盖的方法(第一个方法除外)都调用super ,这些修改就会彼此堆叠,如清单7所示:

清单7.构建堆叠的实例
object Test {
  def main(args: Array[String]) {
    val queue = (new BasicIntQueue with Squaring)
    queue.put(10)
    queue.put(20)
    println(queue.get()) // 100
    println(queue.get()) // 400
  }
}

清单6super的使用说明了特性和mixin之间的重要区别。 由于在原始类创建之后(从字面上看)将它们混合在一起,因此,Mixins必须解决类层次结构中当前位置的潜在歧义。 特性在创建类时线性化; 编译器毫无疑问地解决了什么是super 。 复杂,严格定义的规则(不在本文的讨论范围内)控制着Scala中线性化的工作方式。 特性还解决了Scala的钻石问题。 当Scala跟踪方法的来源和解决方案时,就不会有任何歧义,因为该语言定义了明确的规则来处理解决方案。

结论

在本期中,我探讨了混合(在Groovy中)和特征(在Scala中)之间的异同。 Mixins和trait提供许多相似的功能,但是实现细节在说明不同语言哲学的重要方式上有所不同。 在Groovy中,mixins作为注释存在,并使用AST转换提供的强大的元编程功能。 Mixins,类别类和ExpandoMetaClass在功能上都有重叠,但有细微(但很重要)的差异。 Scala中的诸如Ordered构成了一种核心语言功能,Scala中的许多内置功能都依赖于此。

在下一期中,我将介绍Java.next语言中的currying和部分应用程序。

翻译自: https://www.ibm.com/developerworks/java/library/j-jn8/index.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

离散特征和连续特征混合_混合蛋白和特征 的相关文章

随机推荐

  • python中dtypes_Dataframe创建及index,columns,values,dtypes等属性介绍

    DataFrame概念 可以通俗理解为excel中一片数据 表格型数据结构 带有标签的二维数组 有行标签 index 和列标签 columns 其值可以是数值 字符串 布尔值等 1 index 行标签 2 columns 列标签 3 val
  • Layui之动态选项卡&iframe使用

    目录 tab选项卡 方法层 实体类 User web层 登录界面代码 tab选项卡 我们顺着上篇的博客内容 在那个基础上加一个选项卡 首先我们打开Layui的在线文档 网址如下 Tab选项卡 在线演示 Layuihttp layui org
  • LeetCode之螺旋矩阵 II 简单易懂与晦涩难懂两种方法解决

    目录 题目 方法一 简单易懂 四方步步紧逼法 代码 方法二 复杂一点 上下法 代码 题目 给你一个正整数 n 生成一个包含 1 到 n2 所有元素 且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 示例 1 输入 n 3
  • ptv服务器系统,红狮PTV安灯管理服务器系统有效提升国内某知名车企生产效率

    国内某知名汽车企业 在其以往的日常生产管理中 由于汽车生产各产线设备间没有实现互联 工位间信息不流通 每天都需要安排设备管理员定时巡视各个工位 检查设备运行状况 记录生产现状 这不仅造成了时间 人力成本的浪费 更制约了该企业生产效率的提升
  • 修改远程桌面登陆端口的方法

    Windows系统中的远程终端服务是一项功能非常强大的服务 其默认的端口号3839很容易成为入侵者长驻主机的通道 使用户电脑成为通常称为的 肉鸡 受入侵者远程操控 盗取用户重要资料和隐私信息 是非常严重的网络安全隐患 因此 在使用远程终端服
  • 小程序的开放能力、分享及组件的传参

    一 小程序开放功能 1 获取网络状态wx getNetworkType 2 从网络上下载文档wx downloadFile 3 下载成功之后进行预览文档wx openDocument Page 点击 预览文档 的按钮 触发tap回调 tap
  • python解析xml

    import xml dom minidom dom xml dom minidom parse r K identify voc to coco cache annotations 0 xml 打开xml文件 送到dom解析
  • 【网络基础】通俗易懂的搞明白什么是子网掩码(大白话版)

    目录 前言 什么是子网掩码 子网 如何判断是否在同一个子网 子网掩码的功能总结 子网掩码的分类 可变长子网掩码 总结 前言 本次的文章内容均为个人在网络上搜罗知识点并梳理而来 尽量用浅显易懂的方式讲解 但不会讲的很深入 因为只想给刚入行的人
  • webrtc.lib(m74) 链接的 obj 文件[应该与编译选项有关,备忘]

    01F68076 0 obj test fake video codecs fake vp8 encoder obj 01F680A6 48 obj test fake video codecs fake vp8 decoder obj 0
  • Android监听程序的安装和卸载

    在android系统中 安装和卸载都会发送广播 当应用安装完成后系统会发android intent action PACKAGE ADDED广播 可以通过intent getDataString 获得所安装的包名 当卸载程序时系统发and
  • 数据库——SQL语句(其它)

    目录 1 数据类型 2 查询条件 1 数据类型 数据类型 含义 CHAR n CHARACTER n 长度为n的定长字符串 VARCHAR n CHARACTERVARYING n 最大长度为n的变长字符串 CLOB 字符串大对象 BLOB
  • 基于体系结构架构设计-架构真题(十五)

    基于体系结构开发设计 Architecture Base Software Design ABSD 是指构成体系结构的 组合驱动 ABSC方法是一个自项向下 递归细化的方法 软件系统的体系结构通过该方法细化 直到能产生 产品 功能需求和设计
  • CSS实现悬浮提示(通用)

    没有废话 先看效果 为id选择器 如果有id可以直接确认到指定控件最好 如果class固定也可以只通过class选择器指向控件 不会取的也可以通过浏览器检查页面找到 代码如下 deep xmly ant select selection r
  • matlab 集成学习方法,集成学习(ensemble learning)

    本章参考西瓜书第八章编写 从个体和集成之间的关系出发 引出了集成学习的遵循的两大标准 基学习器的准确定和多样性 然后开始介绍具体的集成学习算法 串行的Boosting和并行的Bagging 前者通过对错判训练样本重新赋权来重复训练 以提高基
  • 统计机器学习---主成分分析(PCA)

    主成分分析的基本了解 主成分分析方法 是一种使用最广泛的数据降维算法 PCA的主要思想是将高维的特征映射到k维上 这k维就是主成分 并能保留原始变量的大部分信息 这里的信息是指原始变量的方差 如果用坐标系进行直观解释 一个坐标系表示一个变量
  • Air724+HC32L176做的电能集中器——JSY-1039单相4G集中器

    很多朋友在很多地方都听到过 集中器 但是对集中器还没有隔概念 那么什么是集中器呢 问 什么是集中器 集中器 concentrator device 是连接终端 计算机或通信设备的中心连接点设备 它成为电缆汇合的中心点 在若干终端密集区内 通
  • virtualbox 主机ping不通虚拟机解决办法

    场景描述 virtualbox虚拟机可以ping通主机和外网 但是主机一直无法ping通虚拟机ip 10 0 2 15 虚拟机的网络设置为nat 自己添加的nat网络 这样可以使得不通的虚拟机ip不一样 否则都选择NAT网络地址转发这个选项
  • 用deconstructSigs来做cosmic的mutation signature图

    用deconstructSigs来做cosmic的mutation signature图 作者的英文文档对这个包的用法描述的非常清楚 我只是记录一下自己学习该包用法的一点感悟 安装并加载必须的packages 如果你还没有安装 就运行下面的
  • Mac电脑使用:桌面底部莫名出现白色输入框解决的解决办法

    转自 https blog csdn net CC1991 article details 82965981 关闭Finder快速搜索输入框的方法 用鼠标单击输入框 点击进去 然后按电脑键盘的 Esc 键 即可关闭这个输入框
  • 离散特征和连续特征混合_混合蛋白和特征

    Java语言的开发人员精通C 和其他包含多重继承的语言 从而使类可以从任意数量的父级继承 多重继承的问题之一是无法确定派生自哪个父继承功能 这个问题称为菱形问题 请参阅参考资料 多重继承中固有的菱形问题和其他复杂性启发了Java语言设计人员