Scala设计模式UML图例和代码实现实战 结构模式--外观设计模式
外观设计模式 (facade design mode)
每当我们构建库或大型系统时,我们通常都依赖于其他库和功能。实现方法有时需要同时使用多个类。
这需要知识。每当我们为某人建立一个图书馆时,我们通常会尝试通过假设他们没有(并且不需要)像我们那样广泛的知识来使用户更简单。
此外,开发人员确保组件在整个应用程序中易于使用。这是外观设计模式可以变得有用的地方。
外观设计模式的目的是用一个简单的界面包装一个复杂的系统,以隐藏使用的复杂性并简化客户端的交互。
我们已经研究了基于包装的其他设计模式。
虽然适配器设计模式将一个接口转换为另一个接口,而装饰器增加了额外的功能,但外观使事情变得更简单。
示例类图对于类图,让我们假设以下设置 - 我们希望我们的用户能够从服务器下载一些数据并以对象的形式对其进行反序列化。服务器以编码形式返回我们的数据,因此我们应首先解码它,然后解析它,最后返回正确的对象。这涉及许多操作并使事情变得复杂。这就是我们使用外观设计模式的原因:
当客户端使用上述应用程序时,他们只需要与DataReader进行交互。 在内部,它将负责下载,解码和反序列化数据。
代码示例上图将DataDownloader,DataDecoder和DataDeserializer显示为DataReader中的组合对象。 这很容易实现 - 它们可以使用默认构造函数创建,也可以作为参数传递。 但是,对于我们示例的代码表示,我们选择使用traits而不是类,并将它们与DataReader类混合使用。
我们先来看看DataDownloader,DataDecoder和DataDeserializer特性:
package com.ivan.nikolov.structural.facade.model
case class Person(name: String, age: Int)
package com.ivan.nikolov.structural.facade
import java.util.Base64
trait DataDecoder {
def decode(data: Array[Byte]): String =
new String(Base64.getDecoder.decode(data), "UTF-8")
}
package com.ivan.nikolov.structural.facade
import org.json4s._
import org.json4s.jackson.JsonMethods
trait DataDeserializer {
implicit val formats = DefaultFormats
def parse[T](data: String)(implicit m: Manifest[T]): T =
JsonMethods.parse(StringInput(data)).extract[T]
}
package com.ivan.nikolov.structural.facade
import com.typesafe.scalalogging.LazyLogging
trait DataDownloader extends LazyLogging {
def download(url: String): Array[Byte] = {
logger.info("Downloading from: {}", url)
Thread.sleep(5000)
// {
// "name": "Ivan",
// "age": 26
// }
// the string below is the Base64 encoded Json above.
"ew0KICAgICJuYW1lIjogIkl2YW4iLA0KICAgICJhZ2UiOiAyNg0KfQ==".getBytes
}
}
package com.ivan.nikolov.structural.facade
import com.ivan.nikolov.structural.facade.model.Person
class DataReader extends DataDownloader with DataDecoder with DataDeserializer {
def readPerson(url: String): Person = {
val data = download(url)
val json = decode(data)
parse[Person](json)
}
}
object FacadeExample {
def main(args: Array[String]): Unit = {
val reader = new DataReader
System.out.println(s"We just read the following person: ${reader.readPerson("https://www.ivan-nikolov.com/")}")
}
}
//前面的实现非常简单,它们彼此分开,因为它们处理不同的任务。
//任何人都可以使用它们 然而,它需要一些知识并使事情变得更复杂。 这就是为什么我们有一个名为DataReader的Facade类:
class DataReader extends DataDownloader with DataDecoder with
DataDeserializer {
def readPerson(url: String): Person = {
val data = download(url)
val json = decode(data)
parse[Person](json)
}
}
//这个例子清楚地表明,我们现在有一个简单的调用方法,而不是使用三个不同的接口。 所有复杂性都隐藏在此方法中。 以下清单显示了我们班级的示例用法:
object FacadeExample {
def main(args: Array[String]): Unit = {
val reader = new DataReader
System.out.println(s"We just read the following person:
${reader.readPerson("https://www.ivan-nikolov.com/")}")
}
}
//上面的代码使用我们的库,这些库对客户端是隐藏的,非常简单。 这是一个示例输出:
当然,在前面的例子中,我们可以在DataReader中使用类而不是混合特征。这实际上取决于需求并且应该产生相同的结果。