返回介绍

1.2 适配器模式

发布于 2025-01-04 00:44:54 字数 3684 浏览 0 评论 0 收藏 0

适配器模式 (有时叫做包装模式)允许对象用在另一类接口。这一模式有两种

1.2.1 委托范例

假设有以下类:

class SquarePeg {
  def width
}

class RoundPeg {
  def radius
}

class RoundHole {
  def radius
  def pegFits(peg) {
    peg.radius <= radius
  }
  String toString() { "RoundHole with radius $radius" }
}

可以询问 RoundHole 类是否有 RoundPeg 适合它,但询问 SquarePeg 相同的问题则不会成功,因为 SquarePeg 根本就没有 radius 属性(比如并不满足必须的接口)。

要想解决这个问题,就需要创建一个适配器使其具有正确的接口,如下所示:

class SquarePegAdapter {
  def peg
  def getRadius() {
    Math.sqrt(((peg.width / 2) ** 2) * 2)
  }
  String toString() {
    "SquarePegAdapter with peg width $peg.width (and notional radius $radius)"
  }
}

也可以像下面这样来使用适配器:

def hole = new RoundHole(radius: 4.0)
(4..7).each { w ->
  def peg = new SquarePegAdapter(peg: new SquarePeg(width: w))
  if (hole.pegFits(peg)) {
    println "peg $peg fits in hole $hole"
  } else {
    println "peg $peg does not fit in hole $hole"
  }
}

其返回结果如下:

peg SquarePegAdapter with peg width 4 (and notional radius 2.8284271247461903) fits in hole RoundHole with radius 4.0
peg SquarePegAdapter with peg width 5 (and notional radius 3.5355339059327378) fits in hole RoundHole with radius 4.0
peg SquarePegAdapter with peg width 6 (and notional radius 4.242640687119285) does not fit in hole RoundHole with radius 4.0
peg SquarePegAdapter with peg width 7 (and notional radius 4.949747468305833) does not fit in hole RoundHole with radius 4.0

1.2.2 继承范例

下面使用继承来实现同样的范例。首先,原始类如下(没有任何变动):

class SquarePeg {
  def width
}

class RoundPeg {
  def radius
}

class RoundHole {
  def radius
  def pegFits(peg) {
    peg.radius <= radius
  }
  String toString() { "RoundHole with radius $radius" }
}

使用继承的适配器:

class SquarePegAdapter extends SquarePeg {
  def getRadius() {
    Math.sqrt(((width / 2) ** 2) * 2)
  }
  String toString() {
    "SquarePegAdapter with width $width (and notional radius $radius)"
  }
}

使用适配器:

def hole = new RoundHole(radius: 4.0)
(4..7).each { w ->
  def peg = new SquarePegAdapter(peg: new SquarePeg(width: w))
  if (hole.pegFits(peg)) {
    println "peg $peg fits in hole $hole"
  } else {
    println "peg $peg does not fit in hole $hole"
  }
}

输出为:

peg SquarePegAdapter with width 4 (and notional radius 2.8284271247461903) fits in hole RoundHole with radius 4.0
peg SquarePegAdapter with width 5 (and notional radius 3.5355339059327378) fits in hole RoundHole with radius 4.0
peg SquarePegAdapter with width 6 (and notional radius 4.242640687119285) does not fit in hole RoundHole with radius 4.0
peg SquarePegAdapter with width 7 (and notional radius 4.949747468305833) does not fit in hole RoundHole with radius 4.0

1.2.3 使用闭包适配

作为以上范例的变体,我们可以定义下列接口:

interface RoundThing {
  def getRadius()
}

定义一个闭包作为适配器:

def adapter = {
  p -> [getRadius: { Math.sqrt(((p.width / 2) ** 2) * 2) }] as RoundThing
}

然后使用它:

def peg = new SquarePeg(width: 4)
if (hole.pegFits(adapter(peg))) {
  // ... 如前所示  
}

1.2.4. 使用 ExpandoMetaClass 来适配

自从 Groovy 1.1 起,就存在一个内建的 MetaClass,能够自动且动态地添加属性和方法。

下例就用到了这个特性:

def peg = new SquarePeg(width: 4)
peg.metaClass.radius = Math.sqrt(((peg.width / 2) ** 2) * 2)

创建完 peg 对象之后,可以立即添加一个属性。不需要改变原始类,也不需要适配类。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文