设计模式-行为型

Posted 极客学伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-行为型相关的知识,希望对你有一定的参考价值。

设计模式-行为型

行为型设计模式主要用于软件运行时复杂的流程控制。包含:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式和解释器模式

模板方法模式

在软件设计时,很多时候系统的运行流程都是确定的,在整个流程中,可能只有部分环节的具体实现是有差别的,这时我们就可以使用模板方法模式,其具体定义为:定义一个操作流程中的算法骨架,将部分算法环节的实现延迟到子类中,使子类可以在不改变算法骨架的前提下对特定步骤进行定制。

以职员的工作流程为例:

class Management 
    func clockIn() 
        print("上班")
    
    func working() 
        print("工作")
    
    func clockOut() 
        print("下班")
    
    func start() 
        clockIn()
        working()
        clockOut()
    

无论对于任何岗位的职员,这个流程都不变,对于不同的岗位不同的是具体的工作内容,例如添加一位工程师,以模板方法模式设计:

重构后

...
class Engineer: Management 
    override func working() 
        print("软件设计")
    

使用模板方法模式设计后,代码的复用性更强,但是因为子类修改了父类的方法的实现,有悖里氏替换原则,因此在选择时需要根据具体场景进行分析。

策略模式

策略模式核心原则是定义一系列算法,将每个算法独立封装,使用者可以灵活的进行选择替换。

例如现实生活中到某地的出行方式有很多种,可以灵活选择:出租车、公交车、地铁、自行车等,需要根据路程远近和交通状况灵活的选择,这就是一种策略模式。

重构后

protocol Transport 
    func toDestination()

class Taxi: Transport 
    func toDestination() 
        print("出租车")
    

class Bus: Transport 
    func toDestination() 
        print("公交车")
    

class Subway: Transport 
    func toDestination() 
        print("地铁")
    

class Action 
    var destination: String
    var transport: Transport
    init(destination: String, transport: Transport) 
        self.destination = destination
        self.transport = transport
    
    func go() 
        self.transport.toDestination()
    

let action = Action(destination: "北京", transport: Subway())
action.go()

通过策略模式,不同的Action对象调用go方法很容易根据场景实现不同的行为。

命令模式

命令模式的核心是将请求封装为对象,使得请求的发起与执行分开,发起方和执行方通过命令进行交互。
以教务系统为例,

struct Teacher 
    var name: String
    var subject: String
    func log() 
        print("\\(name) + \\(subject)")
    

class School 
    var teachers = [Teacher]()
    func addTeacher(name: String, subject: String) 
        teachers.append(Teacher(name: name, subject: subject))
    
    func deleteTeacher(name: String) 
        teachers = teachers.filter $0.name != name
    
    func show() 
        for teacher in teachers 
            teacher.log()
        
    

let school = School()
school.addTeacher(name: "学伟", subject: "计算机")
school.addTeacher(name: "张三", subject: "体育")
school.addTeacher(name: "李四", subject: "数学")
school.show()
school.deleteTeacher(name: "李四")
school.show()

其中,School 提供了展示所有教师信息的方法,也提供了添加和删除教师的方法,通过这种方式对教师的操作难以维护,可以使用命令模式对其重构,将添加和删除教师、展示所有教师的逻辑都封装成一种命令。

重构后

struct Teacher 
    var name: String
    var subject: String
    func log() 
        print("\\(name) + \\(subject)")
    

class SchoolCommand 
    enum ActionType 
        case add
        case delete
        case show
    
    var type: ActionType
    var name: String?
    var subject: String?
    init(type: ActionType, name: String? = nil, subject: String? = nil) 
        self.type = type
        self.name = name
        self.subject = subject
    

class School 
    var teachers = [Teacher]()
    func runCommand(command: SchoolCommand) 
        switch command.type 
        case .add:
            addTeacher(name: command.name!, subject: command.subject!)
        case .delete:
            deleteTeacher(name: command.name!)
        case .show:
            show()
        
    
    private func addTeacher(name: String, subject: String) 
        teachers.append(Teacher(name: name, subject: subject))
    
    private func deleteTeacher(name: String) 
        teachers = teachers.filter $0.name != name
    
    private func show() 
        for teacher in teachers 
            teacher.log()
        
    

let school = School()
school.runCommand(command: SchoolCommand(type: .add, name: "学伟", subject: "计算机"))
school.runCommand(command: SchoolCommand(type: .add, name: "张三", subject: "体育"))
school.runCommand(command: SchoolCommand(type: .add, name: "李四", subject: "数学"))
school.runCommand(command: SchoolCommand(type: .show))
school.runCommand(command: SchoolCommand(type: .delete,name: "李四"))
school.runCommand(command: SchoolCommand(type: .show))

使用命令模式重构后,对于 School 的操作都通过 命令 SchoolCommand 触发,代码扩展性更强,且命令可以作为对象直接被存储、传输、重复和撤销,在某些场景下会非常有用。

职责链模式

一个请求被发出,从低层向高层依次寻找可以处理此请求的对象,直到找到处理者才结束责任链。

重构后

struct Requet 
    enum Level 
        case low
        case middle
        case high
    
    var level: Level

protocol Handler 
    var nextHandler: Handler?  get 
    func handlerRequest(request: Requet)
    func nextHanderDo(request: Requet)

extension Handler 
    func nextHanderDo(request: Requet) 
        if let nextHandler = nextHandler 
            nextHandler.handlerRequest(request: request)
         else 
            print("无法处理请求")
        
    

class HighHandler: Handler 
    var nextHandler: Handler? = nil
    func handlerRequest(request: Requet) 
        if request.level == .high 
            print("HighHandler 处理请求")
         else 
            nextHanderDo(request: request)
        
    

class MiddleHandler: Handler 
    var nextHandler: Handler? = HighHandler()
    func handlerRequest(request: Requet) 
        if request.level == .middle 
            print("MiddleHandler 处理请求")
         else 
            nextHanderDo(request: request)
        
    

class LowHandler: Handler 
    var nextHandler: Handler? = MiddleHandler()
    func handlerRequest(request: Requet) 
        if request.level == .low 
            print("LowHandler 处理请求")
         else 
            nextHanderDo(request: request)
        
    

class Chain: Handler 
    var nextHandler: Handler? = LowHandler()
    func handlerRequest(request: Requet) 
        nextHandler?.handlerRequest(request: request)
    

var request = Requet(level: .low)
Chain().handlerRequest(request: request)
request = Requet(level: .middle)
Chain().handlerRequest(request: request)
request = Requet(level: .high)
Chain().handlerRequest(request: request)

外界只需传入指定等级的请求,责任链内部即可根据等级选择相应的处理逻辑。

责任链模式的核心是将请求发送到责任链上,链上的每一个处理者可以根据实际情况决定是否处理此请求,如果不能处理则将请求继续向上发送,直到被某个处理者处理或者没有处理者为止。这种结构可以灵活地向责任链中增加或删除处理者,对于不同种类的请求,发出方只需要将其发送到责任链上,不需要关心具体被哪一个处理者处理。降低了对象间的耦合性,并且使责任的分担更加清晰。

状态模式

状态模式的核心是:当控制一个对象行为的状态转换过于复杂时,把状态处理的逻辑分离出到单独的状态类中。
在软件设计中,对象在不同的情况下会表现出不同的行为,被称为有状态的对象。影响对象行为的属性被称为状态,影响对象行为的属性被称为状态。对有状态的对象进行编程时,使用状态设计模式可以使代码的内聚性更强。

重构后

class StateContent 
    var currentState: State
    init(_ currentState: State) 
        self.currentState = currentState
    
    func changeState(curState: State) 
        self.currentState = curState
    

protocol State 
    func info()
    func doAction(content: StateContent)

class Open: State 
    func info() 
        print("开灯")
    
    func doAction(content: StateContent) 
        content.currentState = Open()
    

class Close: State 
    func info() 
        print("关灯")
    
    func doAction(content: StateContent) 
        content.currentState = Close()
    

class LightButton 
    var stateContent: StateContent
    init(state: State) 
        self.stateContent = StateContent(state)
    
    func change(state: State) 
        self.stateContent.changeState(curState: state)
    
    func log() 
        stateContent.currentState.info()
    

let light = LightButton(state: Close())
light.log()
light.change(state: Open())
light.log()

其中 StateContent 定义了状态的上下文,用来维护当前开关的状态。而 OpenClose 则是对状态的封装。

观察者模式

观察者模式又被称为发布-订阅模式,在观察者模式中,一个对象发生变化会通知到所有依赖它的对象,依赖它的对象可以根据情况进行自身行为的更改。
ios开发中,通知中心和键值监听系统的实现都使用了观察者模式。如下代码通过实现一个简易的通知中心演示观察者模式

重构后

typealias XWNotificationCallback = (XWNotification) -> Void
struct XWNotification 
    var name: String
    var data: String
    var object: AnyObject?
    func info() 
        print("name: \\(name), data: \\(data), object: \\(String(describing: object))")
    

struct XWObsever 
    var object: AnyObject
    var callback: XWNotificationCallback

class XWNotificationCenter 
    static let shared = XWNotificationCenter()
    private var observers = Dictionary<String, Array<XWObsever>>()
    private init() 
    func addObserver(name: String, object: AnyObject, callback: @escaping XWNotificationCallback) 
        let observer = XWObsever(object: object, callback: callback)
        if var curObserver = observers[name] 
            curObserver.append(observer)
         else 
            observers[name] = [observer]
        
    
    func removeObserver(name: String) 
        observers.removeValue(forKey: name)
    
    func postNotification(notification: XWNotification) 
        if let array = observers[notification.name] 
            var postNotification = notification
            for observer in array 
                postNotification.object = observer.object
                observer.callback(postNotification)
            
        
    

let key = "KEY"
XWNotificationCenter.shared.addObserver(name: key, object: "监听者A" as AnyObject)  noti in
    noti.info()

//XWNotificationCenter.shared.removeObserver(name: key)
XWNotificationCenter.shared.postNotification(notification: XWNotification(name: key, data: "通知内容"))

以上就是一个简易通知中心的实现,当添加了监听之后,一旦通知被发出,回调方法就会立刻执行,对于相同名称的通知,可以添加多个观察者。

中介者模式

中介者模式的核心是将网状的对象交互结构改为星形结构,即所有的对象都与一个中介者进行交互。使用中介者模式可以使原本耦合性很强的对象间的耦合变得松散,提高系统的灵活性和扩展性。

如下代码演示了网状的对象交互结构

class ServerA 
    func handleClientA() 
        print("ServerA 处理 ClientA 的请求")
    
    func handleClientB() 
        print("ServerA 处理 ClientB 的请求")
    

class ServerB 
    func handleClientA() 
        print("ServerB 处理 ClientA 的请求")
    
    func handleClientB() 
        print(JavaScript设计模式读书笔记=;架构型设计模式,MVC,MVP,MVVM

JavaScript设计模式读书笔记=;架构型设计模式,MVC,MVP,MVVM

OOP设计模式Python实现--行为型模式之模板模式

OOP设计模式Python实现--行为型模式之状态模式

选型设计模式的应用

设计模式面试行为型设计模式你清楚几个?