設計模式總結 之 行為型
設計模式總結 之 行為型
本文代碼為scala代碼
參考:
http://blog.csdn.net/jason0539
設計模式和原則 強烈推薦 http://blog.csdn.net/zhengzhb/article/category/926691
總共有24中設計模式,分為3類:
建立型模式,共六種:單例模式、簡單工廠、抽象工廠模式、工廠方法模式、建造者模式、原型模式。
結構型模式,共七種:擴充卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:政策模式、模闆方法模式、觀察者模式、疊代子模式、責任鍊模式、指令模式、備忘錄模式、狀态模式、
通路者模式、中介者模式、解釋器模式。
1.政策模式、
政策模式屬于對象的行為模式。其用意是針對一組算法,将每一個算法封裝到具有共同接口的獨立的類中,進而使得它們可以互相替換。 政策模式使得算法可以在不影響到用戶端的情況下發生變化。 結構: 環境類(Context):用一個ConcreteStrategy對象來配置。維護一個對Strategy對象的引用。可定義一個接口來讓Strategy通路它的資料。抽象政策類(Strategy):定義所有支援的算法的公共接口。 Context使用這個接口來調用某ConcreteStrategy定義的算法。具體政策類(ConcreteStrategy):以Strategy接口實作某具體算法。
public class Context {
//持有一個具體政策的對象
private Strategy strategy;
/**
* 構造函數,傳入一個具體政策對象
* @param strategy 具體政策對象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 政策方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
抽象政策類
public interface Strategy {
/**
* 政策方法
*/
public void strategyInterface();
}
具體政策類
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//相關的業務
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
//相關的業務
}
}
public class ConcreteStrategyC implements Strategy {
@Override
public void strategyInterface() {
//相關的業務
}
}
2.模闆方法模式、
/**
* 定義:定義一個操作中算法的架構,而将一些步驟延遲到子類中,使得子類可以不改變算法的結構即可重定義該算法中的某些特定步驟。
* 大部分剛步入職場的畢業生應該都有類似B的經曆。一個複雜的任務,由公司中的牛人們将主要的邏輯寫好,然後把那些看上去比較簡單的方法寫成抽象的,
* 交給其他的同僚去開發。這種分工方式在程式設計人員水準層次比較明顯的公司中經常用到。比如一個項目組,有架構師,進階工程師,初級工程師,
* 則一般由架構師使用大量的接口、抽象類将整個系統的邏輯串起來,實作的編碼則根據難度的不同分别交給進階工程師和初級工程師來完成。
*
* 模版方法模式由一個抽象類和一個(或一組)實作類通過繼承結構組成,抽象類中的方法分為三種:
*
* 抽象方法:父類中隻聲明但不加以實作,而是定義好規範,然後由它的子類去實作。
* 模版方法:由抽象類聲明并加以實作。一般來說,模版方法調用抽象方法來完成主要的邏輯功能,并且,模版方法大多會定義為final類型,指明主要的邏輯功能在子類中不能被重寫。
* 鈎子方法:由抽象類聲明并加以實作。但是子類可以去擴充,子類可以通過擴充鈎子方法來影響模版方法的邏輯。
* 抽象類的任務是搭建邏輯的架構,通常由經驗豐富的人員編寫,因為抽象類的好壞直接決定了程式是否穩定性。
*/
/**
* 模版方法模式
* Created by ctao on 2015/9/2.
*/
trait Account {
/**
* 驗證帳号
* @param account 使用者名
* @param pass 密碼
* @return 是否合法
*/
def validate(account: String, pass: String): Boolean = {
val params = ArrayBuffer[Any](account)
val result = AccessDAO.checkUser(params)
result.head.getOrElse("name", "null") == account && result.head.getOrElse("pass", "null") == pass
}
/**
* 計算利息的方式
*/
def calculateInterest(): Unit
/**
* 顯示方法
*/
def display() = println("顯示利息")
/**
* 模版方法
* @param account 賬戶
* @param pass 密碼
*/
def handle(account: String, pass: String): Unit = validate(account, pass) match {
case true =>
calculateInterest()
display()
case false =>
println("賬戶或密碼錯誤")
}
}
/**
* 活期帳戶
*/
case object CurrentAccount extends Account {
override def calculateInterest(): Unit = println("按照活期計算利息")
}
/**
* 定期帳戶
*/
case object SavingAccount extends Account {
override def calculateInterest(): Unit = println("按照定期計算利息")
}
//****************************************
//***************************************
object md22template extends App{
val account1: Account = SavingAccount
account1.handle("ct", "123")
val account2: Account = SavingAccount
account2.handle("ct", "1233")
val account3: Account = CurrentAccount
account3.handle("ct", "123")
//鈎子:
val dataView1 = XMLDataViewer
val dataView2 = JSONDataViewer
dataView1.process()
}
/**
* 鈎子方法的使用
* Created by ctao on 2015/9/2.
*/
sealed trait DataViewer {
/**
* 擷取資料格式
*/
def data(): Unit
/**
* 轉化方法
*/
private def convertData() = println("将資料轉化為XML格式")
/**
* 展示方法
*/
private def displayData(): Unit = println("以XML形式顯示資料")
/**
* 是否為xml格式
* @return 判斷結果
*/
protected def isNotXmlData = true
/**
* 模版方法
*/
def process(): Unit = {
data()
/**
* 鈎子
*/
if (isNotXmlData) {
convertData()
}
displayData()
}
}
/**
* XML格式資料
*/
case object XMLDataViewer extends DataViewer {
override def data(): Unit = println("從XML檔案中擷取資料")
override def isNotXmlData = false
}
/**
* JSON格式資料
*/
case object JSONDataViewer extends DataViewer {
override def data(): Unit = println("從JSON檔案中擷取資料")
}
3.觀察者模式、
/**
*
* 定義:定義對象間一種一對多的依賴關系,使得當每一個對象改變狀态,則所有依賴于它的對象都會得到通知并自動更新。
*
* 結構:
* 在最基礎的觀察者模式中,包括以下四個角色:
*
* 被觀察者:從類圖中可以看到,類中有一個用來存放觀察者對象的Vector容器(之是以使用Vector而不使用List,是因為多線程操作時,Vector在是安全的,而List則是不安全的),這個Vector容器是被觀察者類的核心,另外還有三個方法:attach方法是向這個容器中添加觀察者對象;detach方法是從容器中移除觀察者對象;notify方法是依次調用觀察者對象的對應方法。這個角色可以是接口,也可以是抽象類或者具體的類,因為很多情況下會與其他的模式混用,是以使用抽象類的情況比較多。
* 觀察者:觀察者角色一般是一個接口,它隻有一個update方法,在被觀察者狀态發生變化時,這個方法就會被觸發調用。
* 具體的被觀察者:使用這個角色是為了便于擴充,可以在此角色中定義具體的業務邏輯。
* 具體的觀察者:觀察者接口的具體實作,在這個角色中,将定義被觀察者對象狀态發生變化時所要處理的邏輯。
*/
/**
* 觀察者模式
* Created by ctao on 2015/9/2.
* 抽象觀察類
*/
abstract class Observer(var name: String) {
/**
* 支援盟友的方法
*/
def help(): Unit
/**
* 被攻擊的方法
* @param allControlCenter 目标類
*/
def beAttacked(allControlCenter: AllControlCenter): Unit
}
/**
* 具體觀察者
* @param name 姓名
*/
class Player(name: String) extends Observer(name) {
/**
* 支援方法
*/
override def help(): Unit = println(s"堅持住,${name}來救你!")
/**
*
* @param allControlCenter 目标類
*/
override def beAttacked(allControlCenter: AllControlCenter): Unit = {
println(s"${name}被攻擊")
allControlCenter.notifyObserver(name)
}
}
/**
* 抽象目标類,戰隊控制中心
* @param allyName 戰隊名稱
*/
abstract class AllControlCenter(allyName: String) {
/**
* 觀察者隊列
*/
protected var players = new ArrayBuffer[Observer]()
/**
* 添加觀察者
* @param observer 觀察者
*/
def join(observer: Observer):Unit = observer match {
case o if players.exists(_.eq(o)) => println(s"${o.name}已加入${allyName}戰隊")
case o: Observer => println(s"${o.name}加入${allyName}戰隊")
players += observer
case _ => println("異常")
}
/**
* 删除觀察者
* @param observer 觀察者
*/
def quit(observer: Observer):Unit = observer match {
case o if players.exists(o.eq(_)) => println(s"${o.name}退出${allyName}戰隊")
players -= observer
case o if !players.exists(_.eq(o)) => println(s"${o.name}已退出${allyName}戰隊")
case _ => println("異常")
}
/**
* 通知方法
* @param oName 觀察者姓名
*/
def notifyObserver(oName: String): Unit
}
/**
* 具體目标類
* @param name 戰隊名
*/
class ConcreteAllyControlCenter(name: String) extends AllControlCenter(name) {
override def notifyObserver(oName: String): Unit = oName match {
case o if players.exists(_.name == o) => println(s"${name}戰隊緊急通知,盟友${oName}遭到攻擊")
players.filterNot(_.name == oName).foreach(_.help())
case _ => println(s"$oName,您已不是戰隊${name}成員,無法通知戰隊您被攻擊的消息")
}
}
object md21Observer extends App{
/**
* 目标
*/
val acc: AllControlCenter = new ConcreteAllyControlCenter("justSo")
/**
* 觀察者對象
*/
val play1: Observer = new Player("a")
val play2: Observer = new Player("b")
val play3: Observer = new Player("c")
val play4: Observer = new Player("d")
val play5: Observer = new Player("e")
/**
*
* 注冊
*/
acc.join(play1)
acc.join(play2)
acc.join(play3)
acc.join(play3)
acc.join(play4)
acc.join(play5)
acc.quit(play1)
acc.quit(play1)
play1.beAttacked(acc)
}
4.疊代子模式、
/**
* 疊代器模式 (用的最多的模式)
* 定義:提供一種方法通路一個容器對象中各個元素,而又不暴露該對象的内部細節。
*
* 疊代器模式的結構
*
* 抽象容器:一般是一個接口,提供一個iterator()方法,例如java中的Collection接口,List接口,Set接口等。
* 具體容器:就是抽象容器的具體實作類,比如List接口的有序清單實作ArrayList,List接口的連結清單實作LinkList,
* Set接口的哈希清單的實作HashSet等。
* 抽象疊代器:定義周遊元素所需要的方法,一般來說會有這麼三個方法:取得第一個元素的方法first(),
* 取得下一個元素的方法next(),判斷是否周遊結束的方法isDone()(或者叫hasNext()),移出目前對象的方法remove(),
* 疊代器實作:實作疊代器接口中定義的方法,完成集合的疊代。
*/
//抽象疊代器
trait AbstractIterator {
def next(): Unit
def isLast(): Boolean
def previous(): Unit
def isFirst(): Boolean
def getNextItem: Any
def getPreviousItem: Any
}
//抽象容器 抽象集合
abstract class AbstractAnyArrayBuffer(objects: ArrayBuffer[Any]) {
def addAny(any: Any) = objects += any
def removeAny(any: Any) = objects -= any
def getAny = this.objects
def createIterator: AbstractIterator
}
/**
* 商品聚合類
* @param objects 存放元素
*/
class ProductArrayBuffer(objects: ArrayBuffer[Any]) extends AbstractAnyArrayBuffer(objects) {
override def createIterator = new ProductIterator
/**
* 内部類實作
*/
protected class ProductIterator extends AbstractIterator {
/**
* 正向周遊遊标
*/
private var cursor1: Int = 0
/**
* 反向周遊遊标
*/
private var cursor2: Int = objects.length - 1
override def next(): Unit = {
if (cursor1 < objects.length) {
cursor1 += 1
}
}
override def isLast: Boolean = cursor1 == objects.length
override def previous(): Unit = {
if (cursor2 > -1) {
cursor2 -= 1
}
}
override def isFirst: Boolean = cursor2 == -1
override def getNextItem = objects(cursor1)
override def getPreviousItem = objects(cursor2)
}
}
/**
* 不采用内部類
* @param objects 存放元素
*/
class ProductArrayBuffer2(objects: ArrayBuffer[Any]) extends AbstractAnyArrayBuffer(objects) {
override def createIterator = new ProductIterator2(this)
}
/**
* 不采用内部類
* @param productArrayBuffer2 商品聚合類
*/
class ProductIterator2(productArrayBuffer2: ProductArrayBuffer2) extends AbstractIterator {
private val products = productArrayBuffer2.getAny
private var cursor1: Int = 0
private var cursor2: Int = products.length - 1
override def next(): Unit = {
if (cursor1 < products.length) {
cursor1 += 1
}
}
override def isLast: Boolean = cursor1 == products.length
override def previous(): Unit = {
if (cursor2 > -1) {
cursor2 -= 1
}
}
override def isFirst: Boolean = cursor2 == -1
override def getNextItem = products(cursor1)
override def getPreviousItem = products(cursor2)
}
object md19Iterator extends App{
var products = new ArrayBuffer[Any]()
products += "a"
products += "b"
products += "c"
products += "d"
products += "e"
println("正向周遊")
products.foreach(x => print(x + ", "))
println()
println("-------------------------")
println("反向周遊")
products.reverse.foreach(x => print(x + ", "))
println()
val arrayBuffer1: AbstractAnyArrayBuffer = new ProductArrayBuffer(products)
arrayBuffer1.removeAny("a")
arrayBuffer1.addAny("cc")
val iterator1: AbstractIterator = arrayBuffer1.createIterator
println("正向周遊")
while (!iterator1.isLast) {
print(iterator1.getNextItem + ", ")
iterator1.next()
}
println()
println("---------------------------")
println("逆向周遊")
while (!iterator1.isFirst) {
print(iterator1.getPreviousItem + ", ")
iterator1.previous()
}
println()
val arrayBuffer2: AbstractAnyArrayBuffer = new ProductArrayBuffer2(products)
arrayBuffer2.removeAny("b")
arrayBuffer2.addAny("cca")
val iterator2: AbstractIterator = arrayBuffer2.createIterator
println("正向周遊")
while (!iterator2.isLast) {
print(iterator2.getNextItem + ", ")
iterator2.next()
}
println()
println("---------------------------")
println("逆向周遊")
while (!iterator2.isFirst) {
print(iterator2.getPreviousItem + ", ")
iterator2.previous()
}
}
5.責任鍊模式、
定義:使多個對象都有機會處理請求,進而避免請求的發送者和接受者之間的耦合關系, 将這個對象連成一條鍊,并沿着這條鍊傳遞該請求,直到有一個對象處理他為止。
結構分析:
抽象處理者角色(Handler):定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設定和傳回對下家的引用。 這個角色通常由一個Java抽象類或者Java接口實作。 具體處理者角色(ConcreteHandler):具體處理者接到請求後,可以選擇将請求處理掉,或者将請求傳給下家。 由于具體處理者持有對下家的引用,是以,如果需要,具體處理者可以通路下家。 每一個具體處理者都會含有下一處理者 以及set處理者的方法
/**
* 職責鍊模式
* 使多個對象都有機會處理請求,進而避免請求的發送者和接受者之間的耦合關系,
* 将這個對象連成一條鍊,并沿着這條鍊傳遞該請求,直到有一個對象處理他為止。
*
* 角色
* 抽象處理者角色(Handler):定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設定和傳回對下家的引用。
* 這個角色通常由一個Java抽象類或者Java接口實作。
* 具體處理者角色(ConcreteHandler):具體處理者接到請求後,可以選擇将請求處理掉,或者将請求傳給下家。
* 由于具體處理者持有對下家的引用,
* 是以,如果需要,具體處理者可以通路下家。
* 抽象處理者角色
*/
/**
* 審批對象
*
*/
case class PurchaseRequest(amount: Double, number: Int, purpose: String)
// 抽象處理類 審批者類
abstract class Approve(name: String) {
protected var sucessor: Approve = _ //用于持有下一處理對象
def setSucessor(approve: Approve) = sucessor = approve
def processRequest(request: PurchaseRequest): Unit
}
//主任類
class Director(name: String) extends Approve(name) {
override def processRequest(request: PurchaseRequest) = request.amount match {
case x: Double if (x < 5000) => {
println(s"主任$name 審批采購單:" + request.number + ",金額:" + request.amount + "元,采購目的:" + request.purpose)
}
case _ => this.sucessor.processRequest(request)
}
}
//副董事
class VicePresident(name: String) extends Approve(name) {
override def processRequest(request: PurchaseRequest) = request.amount match {
case x: Double if x < 100000 =>
println(s"副董事長$name 審批采購單:" + request.number + ",金額:" + request.amount + "元,采購目的:" + request.purpose)
case _ => this.sucessor.processRequest(request)
}
}
//懂事
class President(name: String) extends Approve(name) {
override def processRequest(request: PurchaseRequest) = {
println(s"董事長$name 審批采購單:" + request.number + ",金額:" + request.amount + "元,采購目的:" + request.purpose)
}
}
object Client14 extends App {
val ZH: Approve = new Director("周華")
val YJY: Approve = new VicePresident("遊建友")
val WZX: Approve = new President("吳志雄")
ZH.setSucessor(YJY)
YJY.setSucessor(WZX)
ZH.processRequest(PurchaseRequest(4000, 1001, "大資料卡口項目"))
ZH.processRequest(PurchaseRequest(60000, 1002, "伺服器購置"))
ZH.processRequest(PurchaseRequest(145000, 1003, "星環開科技專利購買"))
ZH.processRequest(PurchaseRequest(1145000, 1004, "公司并購"))
}
result:
主任周華 審批采購單:1001,金額:4000.0元,采購目的:大資料卡口項目
副董事長遊建友 審批采購單:1002,金額:60000.0元,采購目的:伺服器購置
董事長吳志雄 審批采購單:1003,金額:145000.0元,采購目的:星環開科技專利購買
董事長吳志雄 審批采購單:1004,金額:1145000.0元,采購目的:公司并購
6.指令模式、
将一個請求封裝為一個對象,進而可用不同的請求對客戶進行參數化;對請求排隊或記錄日志,以及支援可撤銷的操作
将”送出請求的對象”和”接收與執行這些請求的對象”分隔開來
結構分析: 1)、Command
聲明執行操作的接口
2)、ConcreteCommand
将一個接收者對象綁定于一個動作
調用接收者相應的操作,以實作execute
3)、Client
建立一個具體指令對象并設定它的接收者
4)、Invoker
要求該指令執行這個請求
5)、Receiver
知道如何實施與執行一個請求相關的操作。任何類都可能作為一個接收者
/**
* 1. 概述
*
* 将一個請求封裝為一個對象(即我們建立的Command對象),進而使你可用不同的請求對客戶進行參數化;
對請求排隊或記錄請求日志,以及支援可撤銷的操作。
*
* 2. 解決的問題
*
* 在軟體系統中,行為請求者與行為實作者通常是一種緊耦合的關系,但某些場合,
比如需要對行為進行記錄、撤銷或重做、事務等處理時,這種無法抵禦變化的緊耦合的設計就不太合适。
*
* 3. 模式中角色
*
* 3.1 抽象指令(Command):定義指令的接口,聲明執行的方法。
*
* 3.2 具體指令(ConcreteCommand):具體指令,實作要執行的方法,它通常是“虛”的實作;
通常會有接收者,并調用接收者的功能來完成指令要執行的操作。
*
* 3.3 接收者(Receiver):真正執行指令的對象。任何類都可能成為一個接收者,隻要能實作指令要求實作的相應功能。
*
* 3.4 調用者(Invoker):要求指令對象執行請求,通常會持有指令對象,可以持有很多的指令對象。
這個是用戶端真正觸發指令并要求指令執行相應操作的地方,也就是說相當于使用指令對象的入口。
*
* 3.5 用戶端(Client):指令由用戶端來建立,并設定指令的接收者。
*/
//TODO
//将請求封裝為對象
//接收者 :真正執行指令的對象
class Adder {
//電腦初始值
private var num: Int = 0
def add(value: Int): Int = {
num += value
num
}
}
//抽象指令
abstract class AbstractCommand {
def execute(value: Int): Int
def undo(): Int //撤銷操作
def redo(): Int //二次撤銷
}
//具體指令
class AddCommand extends AbstractCommand {
private var add = new Adder //指令接受者
private var values = new ArrayBuffer[Int]() //記錄value的棧
private var redovalue = new ArrayBuffer[Int]() //記錄redo數值
override def execute(value: Int): Int = {
values += value
add.add(value)
}
override def undo(): Int = {
values.length match {
case 0 =>
println("cannot undo"); add.add(0)
case _ =>
val temp = values.remove(values.length - 1)
redovalue += temp
add.add(-temp)
}
}
override def redo(): Int = {
redovalue.length match {
case 0 =>
println("cannot redo"); add.add(0)
case _ =>
val temp = redovalue.remove(redovalue.length - 1)
values += temp
add.add(temp)
}
}
}
//調用者
class InvokeCalculatorForm(command: AbstractCommand) {
def compute(value: Int): Unit = {
val i = command.execute(value)
println(s"執行運算,運算結果為: $i")
}
def undo(): Unit = {
val i = command.undo()
println(s"執行undo,運算結果為: $i")
}
def redo(): Unit = {
val i = command.redo()
println(s"執行redo,運算結果為: $i")
}
}
object md15Command extends App {
val command: AbstractCommand = new AddCommand
val form = new InvokeCalculatorForm(command)
form.compute(10)
form.compute(5)
form.undo()
form.undo()
form.redo()
form.redo()
form.redo()
form.undo()
form.undo()
form.undo()
form.redo()
form.compute(100)
}
7.備忘錄模式、
/**
* 備忘錄模式
* 定義:在不破壞封裝性的前提下,捕獲一個對象的内部狀态,并在該對象之外儲存這個狀态。這樣就可以将該對象恢複到原先儲存的狀态
*
* 備忘錄模式的結構
*
* 發起人:記錄目前時刻的内部狀态,負責定義哪些屬于備份範圍的狀态,負責建立和恢複備忘錄資料。 Chessman
* 備忘錄:負責存儲發起人對象的内部狀态,在需要的時候提供發起人需要的内部狀态。 ChessMemeto
* 管理角色:對備忘錄進行管理,儲存和提供備忘錄。
*/
/**
* 下棋方法特質
*/
trait ChessmanFunction {
/**
* 存放多個備忘錄
*/
private var mementoArrayBuffer = new ArrayBuffer[ChessMemento]()
/**
* 定義初始位置索引
*/
private var index = -1
/**
* 設定備忘錄
* @param memento 備忘錄
*/
def setMemento(memento: ChessMemento): Unit = mementoArrayBuffer += memento
/**
* 下棋
* @param chessman 棋子
*/
def play(chessman: Chessman): Unit = {
setMemento(chessman.save)
index += 1
println(s"棋子${chessman.label} 目前位置為第${chessman.x}行,第${chessman.y}列")
}
/**
* 悔棋
* @param chessman 棋子
*/
def undo(chessman: Chessman): Unit = {
println("******悔棋******")
index match {
case -1 => println("已經在最初位置,無法撤銷")
case 0 => index -= 1
println("已經在最初位置,無法撤銷")
case length: Int if length > 0 => index -= 1
chessman.restore(mementoArrayBuffer(index))
println(s"棋子${chessman.label} 目前位置為第${chessman.x}行,第${chessman.y}列")
case _ => println("出現異常")
}
}
/**
* 撤銷悔棋
* @param chessman 棋子
*/
def redo(chessman: Chessman): Unit = {
println("******撤銷悔棋******")
index match {
case -1 => index = 1
chessman.restore(mementoArrayBuffer(index))
println(s"棋子${chessman.label} 目前位置為第${chessman.x}行,第${chessman.y}列")
case length: Int if -1 < length && length < mementoArrayBuffer.length - 1 => index += 1
chessman.restore(mementoArrayBuffer(index))
println(s"棋子${chessman.label} 目前位置為第${chessman.x}行,第${chessman.y}列")
case length: Int if length >= mementoArrayBuffer.length - 1 => println("已經在最終位置,無法恢複")
case _ => println(s"異常$index")
}
}
}
case class Chessman(var label: String, var x: Int, var y: Int) extends ChessmanFunction {
/**
* 儲存狀态
* @return 備忘錄
*/
def save: ChessMemento = ChessMemento(this.label, this.x, this.y)
/**
* 恢複狀态
* @param chessMemento 備忘錄
*/
def restore(chessMemento: ChessMemento): Unit = {
label = chessMemento.label
x = chessMemento.x
y = chessMemento.y
}
}
/**
* 備忘錄樣例類
* @param label 标簽
* @param x x坐标
* @param y y坐标
*/
case class ChessMemento( label: String, x: Int, y: Int)
object memento extends App{
val chess = new Chessman("馬",1,1)
chess.undo(chess)
chess.play(chess)
chess.y = 4
chess.play(chess)
chess.x = 5
chess.play(chess)
chess.undo(chess)
chess.undo(chess)
chess.undo(chess)
chess.redo(chess)
chess.redo(chess)
chess.redo(chess)
chess.redo(chess)
chess.undo(chess)
chess.undo(chess)
chess.undo(chess)
chess.undo(chess)
chess.undo(chess)
chess.redo(chess)
}
8.狀态模式、
/**
* 狀态模式
*
* 當一個對象的内在狀态改變時允許改變其行為,這個對象看起來像是改變了其類。
*
* 2. 解決的問題
*
* 主要解決的是當控制一個對象狀态轉換的條件表達式過于複雜時的情況。把狀态的判斷邏輯轉移到表示不同的一系列類當中,可以把複雜的邏輯判斷簡單化。
*
* 3. 模式中的角色
*
* 3.1 上下文環境(Context):它定義了客戶程式需要的接口并維護一個具體狀态角色的執行個體,将與狀态相關的操作委托給目前的Concrete State對象來處理。
*
* 3.2 抽象狀态(State):定義一個接口以封裝使用上下文環境的的一個特定狀态相關的行為。
*
* 3.3 具體狀态(Concrete State):實作抽象狀态定義的接口。
*/
/**
* 抽象狀态
* sealed關鍵字可以修飾類和特質(特質)。密封類提供了一種限制:不能在類定義的檔案之外定義任何新的子類
*/
sealed abstract class ScreenState {
def display(): Unit = {}
}
//具體狀态
case class NormalScreenState(screen: Screen) extends ScreenState {
override def display(): Unit = {
println(s"正常大小,長:${screen.wide},寬:${screen.long}")
}
}
/**
* 放大兩倍狀态
* @param screen 螢幕
*/
case class LargerScreenState(screen: Screen) extends ScreenState {
override def display(): Unit = {
println(s"兩倍大小,長:${screen.wide},寬:${screen.long}")
}
}
/**
* 放大四倍狀态
* @param screen 螢幕
*/
case class LargestScreenState(screen: Screen) extends ScreenState {
override def display(): Unit = {
println(s"四倍大小,長:${screen.wide},寬:${screen.long}")
}
}
class Screen(var long: Int = 1, var wide: Int = 1) {
/**
* 初始化螢幕狀态
*/
private var screenState: ScreenState = NormalScreenState(this)
/**
* 顯示長寬
*/
show()
/**
* 點選事件,點選觸發狀态的改變
*/
def onClick(): Unit = screenState match {
case NormalScreenState(_) =>
this.wide += this.wide
this.long += this.long
screenState = LargerScreenState(this)
print("點選:")
screenState.display()
case LargerScreenState(_) =>
this.wide += this.wide
this.long += this.long
screenState = LargestScreenState(this)
print("點選:")
screenState.display()
case LargestScreenState(_) =>
this.wide = this.wide / 4
this.long = this.long / 4
screenState = NormalScreenState(this)
print("點選:")
screenState.display()
}
/**
* 展示
*/
def show(): Unit = {
print("顯示:")
screenState.display()
}
}
object md20State extends App{
val screen = new Screen
screen.show()
screen.onClick()
screen.show()
screen.onClick()
screen.onClick()
screen.onClick()
}
9.通路者模式、
/**
* 定義:封裝某些作用于某種資料結構中各元素的操作,它可以在不改變資料結構的前提下定義作用于這些元素的新的操作
*
* 1.抽象通路者:抽象類或者接口,聲明通路者可以通路哪些元素,具體到程式中就是visit方法中的參數定義哪些對象是可以被通路的。
* 2. 通路者:實作抽象通路者所聲明的方法,它影響到通路者通路到一個類後該幹什麼,要做什麼事情。
* 3.抽象元素類:接口或者抽象類,聲明接受哪一類通路者通路,程式上是通過accept方法中的參數來定義的。抽象元素一般有兩類方法,一部分是本身的業務邏輯,另外就是允許接收哪類通路者來通路。
* 4. 元素類:實作抽象元素類所聲明的accept方法,通常都是visitor.visit(this),基本上已經形成一種定式了。
* 結構對象:一個元素的容器,一般包含一個容納多個不同類、不同接口的容器,如List、Set、Map等,在項目中一般很少抽象出這個角色。
*
*
*
* 通路者模式可能是行為類模式中最複雜的一種模式了,但是這不能成為我們不去掌握它的理由。我們首先來看一個簡單的例子,代碼如下:
* [java] view plain copy
*
* class A {
* public void method1(){
* System.out.println("我是A");
* }
*
* public void method2(B b){
* b.showA(this);
* }
* }
*
* class B {
* public void showA(A a){
* a.method1();
* }
* }
*
* 我們主要來看一下在類A中,方法method1和方法method2的差別在哪裡,方法method1很簡單,就是列印出一句“我是A”;
* 方法method2稍微複雜一點,使用類B作為參數,并調用類B的showA方法。再來看一下類B的showA方法,showA方法使用類A作為參數,
* 然後調用類A的method1方法,可以看到,method2方法繞來繞去,無非就是調用了一下自己的method1方法而已,它的運作結果應該也是“我是A”,
* 分析完之後,我們來運作一下這兩個方法,并看一下運作結果:
* [java] view plain copy
*
* public class Test {
* public static void main(String[] args){
* A a = new A();
* a.method1();
* a.method2(new B());
* }
* }
*
* 運作結果為:
*
* 我是A
* 我是A
*
* 看懂了這個例子,就了解了通路者模式的90%,在例子中,對于類A來說,類B就是一個通路者。但是這個例子并不是通路者模式的全部,
* 雖然直覺,但是它的可擴充性比較差,下面我們就來說一下通路者模式的通用實作,通過類圖可以看到,在通路者模式中
*/
/**
* 通路者模式
* 員工特質:抽象元素類
* Created by ctao on 2015/9/2.
*/
trait Employee {
/**
* 接受一個抽象的通路者
* @param handler 抽象通路者
*/
def accept(handler: Department)
}
/**
* 正式員工:具體元素類
* @param name 姓名
* @param weeklyWage 周薪
* @param workTime 工作時間
*/
case class FullTimeEmployee(name: String, weeklyWage: Double, workTime: Int) extends Employee {
override def accept(handler: Department): Unit = handler.visit(this)
}
/**
* 兼職員工:具體元素類
* @param name 姓名
* @param hourWage 時薪
* @param workTime 工作時間
*/
case class PartTimeEmployee(name: String, hourWage: Double, workTime: Int) extends Employee {
override def accept(handler: Department): Unit = handler.visit(this)
}
/**
* 部門特質,抽象通路者特質
*/
trait Department {
/**
* 通路正式員工
* @param employee 正式員工
*/
def visit(employee: FullTimeEmployee): Unit
/**
* 通路兼職員工
* @param employee 兼職員工
*/
def visit(employee: PartTimeEmployee): Unit
}
/**
* 财務部,具體通路者類
*/
class FADepartment extends Department {
override def visit(employee: FullTimeEmployee): Unit = {
var weekWage = employee.weeklyWage
val workTime = employee.workTime
workTime match {
case x if x >= 40 => weekWage = weekWage + (workTime - 40) * 100
case x if x < 40 => weekWage = weekWage - (40 - workTime) * 80
if (weekWage < 0) {
weekWage = 0
}
}
println(s"正式員工${employee.name}實際工資為${weekWage}元")
}
override def visit(employee: PartTimeEmployee): Unit = {
val workTime = employee.workTime
println(s"兼職員工${employee.name}實際工資為${employee.hourWage * workTime}元")
}
}
/**
* 人力資源部,具體通路者
*/
class HRDepartment extends Department {
override def visit(employee: FullTimeEmployee): Unit = {
val workTime = employee.workTime
println(s"正式員工${employee.name}實際上班時間為${workTime}小時")
workTime match {
case x if x >= 40 => println(s"正式員工${employee.name}加班時間為${workTime - 40}")
case x if x < 40 => println(s"正式員工${employee.name}請假時間為${40 - workTime}")
}
}
override def visit(employee: PartTimeEmployee): Unit =
println(s"兼職員工${employee.name}實際上班時間為${employee.workTime}")
}
/**
* 員工清單類,對象結構
*/
class EmployeeArray {
private var employees = new ArrayBuffer[Employee]()
/**
* 添加員工
* @param employee 員工
*/
def addEmployee(employee: Employee) = employee match {
case e if employees.exists(e.eq(_)) => println("已經添加")
case _ => employees += employee
}
/**
* 通路
* @param department 部門
*/
def accept(department: Department) = employees.foreach(_.accept(department))
}
object md23Visitor extends App{
val fte1: Employee = FullTimeEmployee("a", 500, 40)
val fte2: Employee = FullTimeEmployee("b", 600, 38)
val fte3: Employee = FullTimeEmployee("c", 550, 44)
val fte4: Employee = PartTimeEmployee("d", 15, 33)
val fte5: Employee = PartTimeEmployee("e", 17, 20)
val employeeBuffer = new EmployeeArray
/**
* 添加員工
*/
employeeBuffer.addEmployee(fte1)
employeeBuffer.addEmployee(fte1)
employeeBuffer.addEmployee(fte2)
employeeBuffer.addEmployee(fte3)
employeeBuffer.addEmployee(fte4)
employeeBuffer.addEmployee(fte5)
/**
* 部門
*/
val dep: Department = new HRDepartment
/**
* 通路
*/
employeeBuffer.accept(dep)
}
10.中介者模式、
/**
* 中介者模式
* 定義:用一個中介者對象封裝一系列的對象互動,中介者使各對象不需要顯示地互相作用,進而使耦合松散,
而且可以獨立地改變它們之間的互動
*
* 抽象中介者:定義好同僚類對象到中介者對象的接口,用于各個同僚類之間的通信。一般包括一個或幾個抽象的事件方法,
并由子類去實作。
* 中介者實作類:從抽象中介者繼承而來,實作抽象中介者中定義的事件方法。從一個同僚類接收消息,然後通過消息影響其他同時類。
* 同僚類:如果一個對象會影響其他的對象,同時也會被其他對象影響,那麼這兩個對象稱為同僚類。在類圖中,同僚類隻有一個,
這其實是現實的省略,\
*
* 在實際應用中,同僚類一般由多個組成,他們之間互相影響,互相依賴。同僚類越多,關系越複雜。
* 并且,同僚類也可以表現為繼承了同一個抽象類的一組實作組成。在中介者模式中,同僚類之間必須通過中介者才能進行消息傳遞。
*/
//抽象中介
abstract class AbstractSoftWare(val name: String) {
private val persons = new ArrayBuffer[Person]()
def addPerson(person: Person): Unit = {
if (persons.forall(!person.eq(_))) {
println(s"群 $name 添加了成員:${person.name}")
persons += person
} else {
println(s"${person.name} 已經在群中了")
}
}
def removePerson(person: Person) {
if (persons.exists(person.eq(_))) {
println(s"群 $name 删除了成員:${person.name}")
persons -= person
} else {
println(s"${person.name} 不在群中了")
}
}
//群發
def notify(person: Person, message: String): Unit = {
if (persons.exists(person.eq(_))) {
persons.filter(!person.eq(_)).foreach(p => println(s"${p.name}從${person.name}接收到資訊:$message"))
} else {
println(s"${person.name}您已經不在群組:$name")
}
}
//私聊
def pm(send: Person, receive: Person, message: String): Unit = send match {
case s if persons.exists(s.eq(_)) => receive match {
case r if persons.exists(r.eq(_)) => {
println(s"${send.name} 發送消息 給 ${receive.name} 的消息為: ${message}")
}
case _ => {
println(s"${receive.name}沒有使用權限 ")
}
}
case _ => println(s"${send.name}沒有使用權限 ")
}
}
//具體中介 qq
class QQSoftware(name: String) extends AbstractSoftWare(name) {
override def notify(person: Person, message: String): Unit = {
println(s"這裡是qq群:$name")
super.notify(person, message)
}
override def pm(send: Person, receive: Person, message: String): Unit = {
println(s"使用qq軟體進行私聊")
super.pm(send, receive, message)
}
}
/**
* msn,具體中介者
* @param name 群名
*/
class MSNSoftware(name: String) extends AbstractSoftWare(name) {
override def notify(person: Person, message: String): Unit = {
println(s"這裡是msn群:$name")
super.notify(person, message)
}
override def pm(send: Person, receive: Person, message: String): Unit = {
println(s"使用msn軟體進行私聊")
super.pm(send, receive, message)
}
}
//抽象同僚
abstract class Person(val name: String) {
def setAbstractSoftware(software: AbstractSoftWare)
/**
* 發言
* @param message 資訊
*/
def speak(message: String): Unit
/**
* 删除使用者
* @param person 使用者
*/
def remove(person: Person): Unit
/**
* 增加使用者
* @param person 使用者
*/
def add(person: Person): Unit
/**
* 私聊
* @param person 接收者
* @param message 資訊
*/
def privateChat(person: Person, message: String): Unit
}
/**
* 管理者角色,屬于同僚
* @param name 名稱
*/
class Admin(name: String) extends Person(name) {
private var abstractSoftware: AbstractSoftWare = null
def setAbstractSoftware(software: AbstractSoftWare) = abstractSoftware = software
override def speak(message: String) = abstractSoftware.notify(this, message)
/**
* 删除
* @param person 使用者
*/
def remove(person: Person) = abstractSoftware.removePerson(person)
/**
* 增加
* @param person 使用者
*/
def add(person: Person) = {
println(s"${name}進行添加使用者${person.name}的操作")
abstractSoftware.addPerson(person)
}
/**
* 私聊
* @param person 接收者
* @param message 資訊
*/
def privateChat(person: Person, message: String) = abstractSoftware.pm(this, person, message)
}
/**
* 普通使用者角色,屬于同僚
* @param name 名稱
*/
class Member(name: String) extends Person(name) {
private var abstractSoftware: AbstractSoftWare = null
def setAbstractSoftware(software: AbstractSoftWare) = abstractSoftware = software
override def speak(message: String) = abstractSoftware.notify(this, message)
/**
* 增加使用者
* @param person 使用者
*/
override def add(person: Person): Unit = {
println(s"${name}您不是管理者,不具備增加使用者權限")
}
/**
* 判斷是否為删除自己,如果是删除自己則為退群
* @param person 使用者
*/
override def remove(person: Person): Unit = {
if (person.eq(this)) {
println(s"$name,您将退出${abstractSoftware.name}")
abstractSoftware.removePerson(person)
} else {
println(s"${name}您不是管理者,不具備删除使用者權限")
}
}
/**
* 私聊
* @param person 接收者
* @param message 資訊
*/
def privateChat(person: Person, message: String) = abstractSoftware.pm(this, person, message)
}
object mediator extends App {
val admin: Person = new Admin("admin")
val member1: Person = new Member("member1")
val member2: Person = new Member("member2")
val member3: Person = new Member("member3")
val member4: Person = new Member("member4")
val qqSoftware: AbstractSoftWare = new QQSoftware("研發中心")
admin.setAbstractSoftware(qqSoftware)
member1.setAbstractSoftware(qqSoftware)
member2.setAbstractSoftware(qqSoftware)
member3.setAbstractSoftware(qqSoftware)
member4.setAbstractSoftware(qqSoftware)
admin.add(admin)
admin.add(member1)
admin.add(member2)
admin.add(member3)
admin.add(member4)
admin.add(member1)
admin.speak("hello")
admin.remove(member1)
member1.speak("hi")
member2.add(member1)
member2.remove(member2)
member2.speak("admin")
member3.privateChat(admin, "你好")
member3.privateChat(member2, "你好")
member2.privateChat(admin, "加我")
println("------------------------------------------")
val msnSoftware: AbstractSoftWare = new MSNSoftware("通研事業部")
admin.setAbstractSoftware(msnSoftware)
member1.setAbstractSoftware(msnSoftware)
member2.setAbstractSoftware(msnSoftware)
member3.setAbstractSoftware(msnSoftware)
member4.setAbstractSoftware(msnSoftware)
admin.add(admin)
admin.add(member1)
admin.add(member2)
admin.add(member3)
admin.add(member4)
admin.add(member1)
admin.speak("hello")
admin.remove(member1)
member1.speak("hi")
member2.add(member1)
member2.speak("admin")
member2.privateChat(member3, "test")
}
11.解釋器模式
/**
*
* 解釋器模式的結構 行為模式
*
* 下面就以一個示意性的系統為例,讨論解釋器模式的結構。系統的結構圖如下所示:
*
*
*
* 模式所涉及的角色如下所示:
*
* (1)抽象表達式(Expression)角色:聲明一個所有的具體表達式角色都需要實作的抽象接口。這個接口主要是一個interpret()方法,稱做解釋操作。
*
* (2)終結符表達式(Terminal Expression)角色:實作了抽象表達式角色所要求的接口,主要是一個interpret()方法;文法中的每一個終結符都有一個具體終結表達式與之相對應。比如有一個簡單的公式R=R1+R2,在裡面R1和R2就是終結符,對應的解析R1和R2的解釋器就是終結符表達式。
*
* * (3)非終結符表達式(Nonterminal Expression)角色:文法中的每一條規則都需要一個具體的非終結符表達式,非終結符表達式一般是文法中的運算符或者其他關鍵字,比如公式R=R1+R2中,“+"就是非終結符,解析“+”的解釋器就是一個非終結符表達式。
*
* (4)環境(Context)角色:這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1指派100,給R2指派200。這些資訊需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。
*/
//http://blog.csdn.net/chenssy/article/details/12719973 按照java例子寫為scala
//抽象表達
trait Node {
def interpret(): Int
}
//非終結表達
class ValueNode(value: Int) extends Node {
override def interpret() = value
}
//終結表達式抽象類
abstract class SymbolNode(left: Node, right: Node) extends Node {
}
//終結表達式 乘 除 取餘
class MulNode(left: Node, right: Node) extends SymbolNode(left, right) {
override def interpret(): Int = {
left.interpret() * right.interpret()
}
}
class DivNode(left: Node, right: Node) extends SymbolNode(left, right) {
override def interpret(): Int = {
left.interpret() / right.interpret()
}
}
class ModNode(left: Node, right: Node) extends SymbolNode(left, right) {
override def interpret(): Int = {
left.interpret() % right.interpret()
}
}
class Calcutor {
private var statement: String = null
private var node: Node = null
def build(statement: String) {
var left: Node = null
var right: Node = null
var stack = new Stack[Node]
val statementArr: Array[String] = statement.split(" ")
var i = 0
while (i < statementArr.length) {
if (statementArr(i).equalsIgnoreCase("*")) {
left = stack.pop
val value = Integer.parseInt(statementArr(i + 1));
i = i + 1
right = new ValueNode(value);
stack.push(new MulNode(left, right));
} else if (statementArr(i).equalsIgnoreCase("/")) {
left = stack.pop
val value = Integer.parseInt(statementArr(i + 1));
i = i + 1
right = new ValueNode(value);
stack.push(new DivNode(left, right));
} else if (statementArr(i).equalsIgnoreCase("%")) {
left = stack.pop
val value = Integer.parseInt(statementArr(i + 1));
i = i + 1
right = new ValueNode(value);
stack.push(new ModNode(left, right));
} else {
stack.push(new ValueNode(Integer.parseInt(statementArr(i))));
}
i = i + 1
}
this.node = stack.pop
}
def compute(): Int = {
node.interpret()
}
}
object md16Interpreter extends App {
val statement = "3 * 2 * 4 / 6 % 5"
val calc = new Calcutor
calc.build(statement)
val result = calc.compute()
println(result)
}