《设计模式》之复合模式(MVC)

复合模式:就是将多种设计模式融合在一起,实现一个更高阶的功能,一个非常经典的复合模式就是MVC。

MVC模式在过去的十几年里,使用频率非常高,尤其是前后端尚未分离的时候,类似的JSP、PHP、ASP.Net MVC技术,都使用MVC模式,当前后端分离越来越常见后,衍生出很多模式,MVVM、MVP等等,如React、Vue等等框架;

MVC模式是由策略模式 + 观察者模式组合而成,详细如下:

  • Model(模型):
    模型用于获取数据,保存页面的状态;
  • View(视图):
    不同状态下的应用,呈现的视图是不一样的,比如登录页面、个人页面、列表页面;
    接收用户的行为事件,比如点击登录、点击退出、删除等等;
  • Controller(控制器):
    控制器主要是根据应用状态(策略)来切换页面显示;

M、V、C的依赖场景:
C根据应用状态,返回不同的V;
V根据用户的操作产生事件,传递给C;
C接收事件,做出反应,更新M,返回不同的V给前端;

代码:

// 模型(Model)
interface IUserModelAbserver {
    onLoginStateChanged: (isLogin: boolean) => void,
}

class UserModel {
    private isLogin: boolean = false
    public constructor(observer: IUserModelAbserver) {
        this.observer = observer
    }
    private observer: IUserModelAbserver

    public userLogin() {
        return this.isLogin
    }

    public setIsLogin(isLogin: boolean) {
        this.isLogin = isLogin
        this.observer.onLoginStateChanged(isLogin)
    }
}

// 视图(View)
enum ViewEvent {
    Login,
    LoginOut
}

interface IEventHandler {
    onEmitEvent: (event: ViewEvent) => void
}

abstract class View {
    public handler: IEventHandler
    constructor(handler: IEventHandler) {
        this.handler = handler
    }
    abstract render(): string
}

class LoginView extends View {
    public onClickLogin() {
        this.handler.onEmitEvent(ViewEvent.Login)
    }
    public render() {
        return '<登录页面的HTML><点击登录>'
    }
}

class UserProfileView extends View {
    public onClickLogout() {
        this.handler.onEmitEvent(ViewEvent.LoginOut)
    }
    public render() {
        return '<用户个人页面的HTML><点击退出>'
    }
}


// 控制器(Controller)
class Controller implements IUserModelAbserver, IEventHandler {
    private model: UserModel
    private view: View
    
    public constructor() {
        this.model = new UserModel(this)

        console.log('初始为登录界面')
        this.view = new LoginView(this)
    }
    
    public onLoginStateChanged(isLogin: boolean) {
        console.log('登录状态变更...')
        if (this.model.userLogin()) {
            console.log('用户已登录成功 -> 切换为个人页面')
            this.view = new UserProfileView(this)
        } else {
            console.log('用户退出登录 -> 切换为登录页面')
            this.view = new LoginView(this)
        }
    }

    public onEmitEvent(evt: ViewEvent) {
        console.log('用户操作界面,发生事件...')
        if (evt === ViewEvent.Login) {
            console.log('点击登录...')
            this.model.setIsLogin(true)
        } else if (evt === ViewEvent.LoginOut) {
            console.log('点击退出...')
            this.model.setIsLogin(false)
        }
    }

    public render() {
        console.log('渲染页面内容...')
        return this.view.render()
    }
}

// Test
const controller = new Controller()
console.log(controller.render())

// 模拟点击登录
let v: any = controller['view']
v.onClickLogin()
console.log(controller.render())

// 模拟退出登录
v = controller['view']
v.onClickLogout()
console.log(controller.render())

输出结果:

[LOG]: 初始为登录界面 
[LOG]: 渲染页面内容... 
[LOG]: <登录页面的HTML><点击登录> 
[LOG]: 用户操作界面,发生事件... 
[LOG]: 点击登录... 
[LOG]: 登录状态变更... 
[LOG]: 用户已登录成功 -> 切换为个人页面 
[LOG]: 渲染页面内容... 
[LOG]: <用户个人页面的HTML><点击退出> 
[LOG]: 用户操作界面,发生事件... 
[LOG]: 点击退出... 
[LOG]: 登录状态变更... 
[LOG]: 用户退出登录 -> 切换为登录页面 
[LOG]: 渲染页面内容... 
[LOG]: <登录页面的HTML><点击登录> 

你可能感兴趣的:(《设计模式》之复合模式(MVC))