Scala设计模式UML图例和代码实现实战 行为模式--空对象设计模式

16 篇文章 2 订阅
16 篇文章 0 订阅

空对象设计模式
在这里插入图片描述
空对象设计模式大多数面向对象的语言都有一种指定某些值不存在的方法。例如,在Scala和Java中,这可以是可以分配给对象的空值。在对象上调用null的任何方法都会导致NullPointerException,因此开发人员应该小心并检查是否存在这种可能性。但是,这些检查可能会使源代码难以遵循和扩展,因为开发人员应始终注意。
这是空对象设计模式有用的地方。

空对象设计模式的目的是定义表示空值并具有中性行为的实际对象。
使用null对象无需检查某些内容是否设置为null。代码变得更易读,易于理解,使错误发生更加困难。

示例类图对于类图,让我们假设我们有一个系统必须轮询队列中的消息。当然,这个队列可能并不总是提供任何东西,因此它将返回null。我们可以简单地返回具有空行为的特殊null对象,而不是检查null。让我们在图中显示这些消息类:使用上图中的类,只要没有要打印的数字,我们将返回一个空行为的NullMessage对象。在某些情况下,出于优化目的,人们可以将NullMessage作为单例实例。
代码示例在我们实际查看代码之前,我们将注意到有关前面图表的一些观察。它表示使用空对象设计模式的经典案例。但是,现在,在Java或Scala中并没有真正使用它。例如,Java现在支持Optional,而是使用Optional(假设人们使用该语言的新版本)。在Scala中,事情是相似的 - 我们可以并且确实使用Option [Message]而不是null对象。此外,我们获得了Option的所有其他不错的功能,例如在模式匹配中使用它们的能力。
因此,如前所述,我们的代码实际上并不会使用前面类图的层次结构。它只是不需要它,它会更简单。相反,我们将使用Option [Message]。首先,让我们看一下Message类的定义:case class Message(number:Int){def print():String = s“这是一个号码为$ number的消息。”我们提到过,我们将轮询队列中的消息,然后显示它们。我们在我们的应用程序中模拟了一个使用不同线程随机填充的队列:

前面的代码显示了将在不同的线程中运行的内容。
队列将以随机间隔填充0(包括)和10(不包括)之间的随机值。然后,可以调用getMessage,并且可以读取队列中的任何内容。由于队列可能为空,因此我们向调用者返回一个Message消息选项。值得一提的是,在Scala中,Option(null)返回None。这正是我们在前面的代码中利用的。
让我们看看在我们的示例中如何将所有内容组合在一起:

前面的程序创建一个生成器并使其在不同的线程上运行。然后,它随机地从生成器请求项目,并在实际返回某些内容时打印它们。由于使用随机生成器,程序每次都会打印不同的东西。下面是一个示例运行:正如您从我们的示例和前面的输出中看到的那样,我们实际上从未检查过空值,并且当队列返回null时,我们的代码不会执行任何操作。这在大型项目中很有效,它使源代码看起来非常优雅且易于理解。
从我们的示例和前面的输出中可以看出,我们实际上从未检查过空值,并且当队列返回null时,我们的代码不执行任何操作。这在大型项目中很有效,它使源代码看起来非常优雅且易于理解。

import scala.util.Random

case class Message(number: Int) {
def print(): String = s"This is a message with number: $number."
}

object MessageExample {
val TIMES_TO_TRY = 10
val MAX_TIME = 5000

def main(args: Array[String]): Unit = {
val generator = new DataGenerator
// start the generator in another thread
new Thread(generator).start()

val random = new Random()
(0 to TIMES_TO_TRY).foreach {
  case time =>
    Thread.sleep(random.nextInt(MAX_TIME))
    System.out.println("Getting next message...")
    generator.getMessage().foreach(m => System.out.println(m.print()))
}

generator.requestStop()

}
}

import java.util.concurrent.ConcurrentLinkedQueue

import scala.util.Random

class DataGenerator extends Runnable {

val MAX_VAL = 10
val MAX_TIME = 10000

private var isStop = false

private val queue: ConcurrentLinkedQueue[Int] = new ConcurrentLinkedQueueInt

override def run(): Unit = {
val random = new Random()
while (!isStop) {
Thread.sleep(random.nextInt(MAX_TIME))
queue.add(random.nextInt(MAX_VAL))
}
}

def getMessage(): Option[Message] =
Option(queue.poll()).map {
case number => Message(number)
}

def requestStop(): Unit = this.synchronized {
isStop = true
}
}
在这里插入图片描述

在现实生活中的应用程序中,前面示例中的代码可能不是一个好主意。 首先,我们可以使用计时器,而不是在线程上调用sleep。 其次,如果我们想要创建生产者 - 消费者应用程序,我们可以使用诸如Akka(https://akka.io/)之类的库,它们允许我们进行反应式编程并拥有真正优化的代码。
它的好处正如您已经看到的那样,通过使用Option(Java中的Optional),空对象设计模式已经包含在Scala(以及更新版本的Java)中。 这使它非常易于使用,并再次显示语言的强大功能。 使用null对象使我们的代码看起来更具可读性,并且在值为null时无需格外小心。 它还可以降低错误的风险。
值得一提的是,只有在实际需要时才使用它,而不是在任何地方使用它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开心自由天使

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值