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中使用類而不是混合特徵。這實際上取決於需求並且應該產生相同的結果。