js 设计模式2
3.行为型模式
>命令模式:数据驱动的设计模式,将被操作对象的方法包装成命令类,然后打包给调度类选择统一执行
// 命令接口 interface Order { execute(); } // 请求类,目标对象 class Stock { private name = "ABC"; private quantity = 10; buy() { console.log( `%cstock name:${this.name} quantity:${this.quantity} bought`, "color:green" ); } sell() { console.log( `%cstock name:${this.name} quantity:${this.quantity} sold`, "color:red" ); } } // 实现order接口 class BuyStock implements Order { private stock; constructor(stock) { this.stock = stock; } execute() { this.stock.buy(); } } class SellStock implements Order { private stock; constructor(stock) { this.stock = stock; } execute() { this.stock.sell(); } } // 命令调用类 class Broker { private orderList: any = []; takeOrder(order) { this.orderList.push(order); } placeOrders() { this.orderList.forEach((element) => { element.execute(); }); this.orderList = []; } } // 执行 const abcStock = new Stock(); // 目标对象 const buyStock = new BuyStock(abcStock); // 购买命令类 const sellStock = new SellStock(abcStock); // 出售命令类 const broker = new Broker() // 调度站类 broker.takeOrder(buyStock) // 命令加入执行队列 broker.takeOrder(sellStock) broker.placeOrders() // 统一执行命令
>解释器模式:实现一个表达式接口,解释一个特定的上下文,被用在sql解析,符号处理引擎,将特定字符串解析为true或者false用于计算机识别。
// 表达式接口 interface Expression { interpret(context); } // 表达式实体 class TermialExpression implements Expression { data; constructor(data) { this.data = data; } interpret(context) { if (context.indexOf(this.data) != -1) { return true; } return false; } } class OrExpression implements Expression { expr1; expr2; constructor(expr1, expr2) { this.expr1 = expr1; this.expr2 = expr2; } interpret(context) { return this.expr1.interpret(context) || this.expr2.interpret(context); } } class AndExpression implements Expression { expr1; expr2; constructor(expr1, expr2) { this.expr1 = expr1; this.expr2 = expr2; } interpret(context) { return this.expr1.interpret(context) && this.expr2.interpret(context); } } // 使用 const getMaleExpression = () => { const robert = new TermialExpression("Robert"); const john = new TermialExpression("John"); return new OrExpression(robert, john); }; const getMarriedWomanExpression = () => { const julie = new TermialExpression("Julie"); const married = new TermialExpression("Married"); return new OrExpression(julie, married); }; const isMale = getMaleExpression(); const isMarriedWoman = getMarriedWomanExpression(); console.log("John is male? " + isMale.interpret("John")); console.log( "Julie is married women? " + isMarriedWoman.interpret("Married Julie") );
>迭代器模式:顺序访问集合对象的元素,不需要知道集合对象的底层表示,把在元素之间游走的责任交给迭代器
// 接口 interface Iterator { hasNext(); next(); } interface Container { getInterator(); } // 实体,实现Container接口实体,并有实现Iterator接口的内部类,额,js没有内部类 // 名字仓库 class NameRepository implements Container { names: any = []; index; addNames(name) { this.names.push(name); } getNames() { return this.names; } getInterator() { return new NameIterator(); } } // 迭代器迭代类 class NameIterator implements Iterator { index = 0; hasNext(names: any = []) { return this.index < names.length; } next(names = []) { if (this.hasNext(names)) { return names[this.index++]; } return null; } } //使用 const nameRepository = new NameRepository(); nameRepository.addNames({ xiaoming: 11 }); nameRepository.addNames({ xiaoliu: 22 }); nameRepository.addNames({ xiaohua: 33 }); nameRepository.addNames({ xiaofang: 44 }); const interator = nameRepository.getInterator(); const names = nameRepository.getNames(); do { console.log("name: ", interator.next(names)); } while (interator.hasNext(names));
>中介者模式:用来降低多个对象和类之间的通信复杂性,提供中介类处理不同类之间的通信,支持松耦合,将网状结构分离为星型结构。mvc框架,c控制器就是m模型和v视图的中介者
// 聊天室 // 中介类 class ChatRoom { static showMessage(user, message) { // 或者发布给所有的用户 console.log(new Date().toString() + user.getName() + " : " + message); } } // 用户类 class User{ name constructor(name){ this.name = name } getName(){ return this.name } setName(name){ this.setName = name } sendMessage(message){ ChatRoom.showMessage(this,message) } } // 使用 const robert = new User('Robert'); const john = new User('John'); robert.sendMessage('Hi John!') john.sendMessage('Hello Robert!')
>备忘录模式:不破坏封装的前提下,在对象之外保存一个对象的某个状态,以便在适当的时候恢复对象,数据库的事务管理(为了节约内存,可使用原型模式+备忘录模式)
// 保存记录的对象 class Memento { state; constructor(state) { this.state = state; } getState() { return this.state; } } // 需要保存记录的对象 class Originator { state; setState(state) { this.state = state; } getState() { return this.state; } saveStateToMemento() { return new Memento(this.state); } getStateFromMemento(state) { this.state = state; } } // 日志记录管理类 class CareTaker { mementoList:any = []; add(memento) { this.mementoList.push(memento); } // 取第几次保存的记录 get(index) { return this.mementoList[index-1].getState(); } } // 使用 const originator = new Originator(); const careTaker = new CareTaker(); originator.setState("state #1"); originator.setState("state #2"); careTaker.add(originator.saveStateToMemento()); originator.setState("state #3"); careTaker.add(originator.saveStateToMemento()); originator.setState("state #4"); console.log("current state " + originator.getState()); originator.getStateFromMemento(careTaker.get(1)); console.log("first saved state: " + originator.getState()); originator.getStateFromMemento(careTaker.get(2)); console.log("second saved state: " + originator.getState());
>观察者模式:对象存在一对多关系时使用,当一个对象被修改,会自动通知依赖它的对象。也是给当前类加观察锚点和循环执行方法
// 执行调用 class Subject { observers:any = []; state; getstate() { return this.state; } setState(state) { this.state = state; this.notifyAllObservers(); } attach(observer) { this.observers.push(observer); } notifyAllObservers() { this.observers.forEach((element) => { element.update(); }); } } // 观察者接口 interface Observer { subject update(); } // 观察者 class FirstObserver implements Observer{ subject constructor(subject){ this.subject = subject this.subject.attach(this) } update(){ console.log('First Observer '+ this.subject.getstate()) } } class SecondObserver implements Observer{ subject constructor(subject){ this.subject = subject this.subject.attach(this) } update(){ console.log('Second Observer '+ this.subject.getstate()) } } // 使用 const subject = new Subject(); new FirstObserver(subject); new SecondObserver(subject); subject.setState(123456789)
>状态模式:类的行为基于状态改变,对象看起来好像修改了它的类,就是加了几个类作为它的状态和方法。
interface State{ doAction(context) } // 状态类提供更新的方法和更新状态方法 class StartState implements State{ doAction(context){ console.log('this is in start state') context.setState(this) } toString(){ return 'Start State' } } class StopState implements State{ doAction(context){ console.log('this is in stop state') context.setState(this) } toString(){ return 'Stop State' } } // 应用类 class Context{ state constructor(){ this.state = null } setState(state){ this.state = state } getState(){ return this.state } } // 使用 const context = new Context() const startState = new StartState(); const stopState = new StopState(); startState.doAction(context); console.log(context.getState().toString()) stopState.doAction(context) console.log(context.getState().toString())
>空对象模式:一个空对象取代 NULL 对象实例的检查。Null对象不是检查空值,而是反应一个不做任何动作的关系。这样的Null对象也可以在数据不可用的时候提供默认的行为。默认对象
interface AbstractCustomer { name; isNil(); getName(); } // 实体类 class RealCustomer implements AbstractCustomer { name; constructor(name) { this.name = name; } isNil() { return false; } getName() { return this.name; } } // 空对象类 class NullCustomer implements AbstractCustomer { name; isNil() { return true; } getName() { return "Not Available in Customer Database"; } } // 工厂类 class CustomerFactory { static names = ["Rob", "Joe", "Julie"]; static getCustomer(name) { for (let i in this.names) { if (this.names[i] == name) { return new RealCustomer(name); } }; return new NullCustomer(); } } const customer1 = CustomerFactory.getCustomer("Rob"); const customer2 = CustomerFactory.getCustomer("Bob"); const customer3 = CustomerFactory.getCustomer("Julie"); const customer4 = CustomerFactory.getCustomer("Laura"); console.log("customers"); console.log(customer1.getName()); console.log(customer2.getName()); console.log(customer3.getName()); console.log(customer4.getName());
>策略模式:一个类的行为或其算法可以再运行时更改,定义一系列算法,把它们一个个封装起来,并使它们可互相替换(如果策略类多于四个,就考虑混合模式,解决策略类膨胀问题),创建对象时注入策略
// 策略类接口 interface Strategy { doOperation(num1, num2); } // 实体 class OperationAdd implements Strategy { doOperation(num1, num2) { return num1 + num2; } } class OperationSubtract implements Strategy { doOperation(num1, num2) { return num1 - num2; } } class OperationMultiply implements Strategy { doOperation(num1, num2) { return num1 * num2; } } class Context{ strategy constructor(strategy){ this.strategy = strategy } executeStrategy(num1,num2){ return this.strategy.doOperation(num1,num2) } } // 执行 let context = new Context(new OperationAdd) console.log("10 + 5 = "+context.executeStrategy(10,5)) context = new Context(new OperationSubtract) console.log("10 - 5 = "+context.executeStrategy(10,5)) context = new Context(new OperationMultiply) console.log("10 * 5 = "+context.executeStrategy(10,5))
>模板模式:一个抽象类公开定义了执行它的方式/模板,子类按需重写,但调用以抽象类中定义的方式进行,通用算法抽离出来
// 抽象类 abstract class Game { abstract initialize(); abstract startPlay(); abstract endPlay(); play() { this.initialize(); this.startPlay(); this.endPlay(); } } // 实体(板球,蟋蟀) class Cricket extends Game { initialize() { console.log("Cricket Games Initialized! Start playing."); } startPlay() { console.log("Cricket play Started"); } endPlay() { console.log("Cricket Games Finished!"); } } class Football extends Game { initialize() { console.log("Football Games Initialized! Start playing."); } startPlay() { console.log("Football play Started"); } endPlay() { console.log("Football Games Finished!"); } } // 使用 let game = new Cricket(); game.play(); game = new Football(); game.play();
>访问者模式:使用了一个访问者类,改变了元素类的执行算法。将数据结构与数据操作分离,处理稳定的数据结构和易变的操作耦合问题,被访问的类中加一个对外提供接待访问者的接口
// 表示元素的接口 interface ComputerPart { accept(computerPartVisitor); } class Computer implements ComputerPart{ accept(computerPartVisitor){ computerPartVisitor.visit(this) } } // 访问者接口 interface ComputerPartVisitor{ visit(computerPart) } // 访问实体,操作使用computer类 class ComputerPartDisplayVisitor implements ComputerPartVisitor{ visit(computer){ console.log(computer,'hhh i\'m visitor') } } // 访问实体,其它的操作使用computer类 class ComputerPartDisplayVisitor1 implements ComputerPartVisitor{ visit(computer){ console.log(computer,'hhh i\'m visitor1') } } // 使用 const computer = new Computer() computer.accept(new ComputerPartDisplayVisitor()) console.log('%c------------------------------','color:green') const computer1 = new Computer() computer1.accept(new ComputerPartDisplayVisitor1())
>发布—订阅模式(行为型)
class Publisher { observers; constructor() { this.observers = []; } // 添加订阅者 add(observer) { this.observers.push(observer); } // 通知所有订阅者 notify() { this.observers.forEach((element) => { element.update(this); //通知订阅者 }); } } class Observer{ name constructor(name){ this.name = name; } update(){ console.log(this.name,'Observer h h h') } } const shop = new Publisher(); const customer = new Observer('小明'); const customer1 = new Observer('小刘'); shop.add(customer); shop.add(customer1); shop.notify();
4.J2EE模式: 这些设计模式特别关注表示层,由 Sun Java Center 鉴定的
> MVC:Model,代表一个存取数据的对象,也可以带有逻辑,在数据变化时更新控制器;View,代表模型包含的数据的可视化;Controller,作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
// 模型 class Student { private rollNo; private name; getRollNo() { return this.rollNo; } setRollNo(rollNo) { this.rollNo = rollNo; } getName() { return this.name; } setName(name) { this.name = name; } } // 视图 class StudentView { printStudentDetails(studentName, studentRollNo) { console.log("Student:"); console.log("Name: " + studentName); console.log("RollNo: " + studentRollNo); } } // 控制器 class StudentController { private model; private view; constructor(model, view) { this.model = model; this.view = view; } setStudentName(name) { this.model.setName(name); } getStudentName() { this.model.getName(); } setStudentRollNo(RollNo) { this.model.setRollNo(RollNo); } getStudentRollNo() { this.model.getRollNo(); } updateView() { this.view.printStudentDetails(this.model.getName(), this.model.getRollNo()); } } const getStudentFromDatabase = () => { const student = new Student(); student.setName("李四"); student.setRollNo("22"); return student; }; // 执行 const model = getStudentFromDatabase(); // 一般是数据库记录 const view = new StudentView(); const controller = new StudentController(model, view); controller.updateView(); controller.setStudentName("zhang san"); controller.updateView();
>业务代表模式:用于对表示层和业务层解耦。业务层有以下实体:客户端,业务代表,查询服务,业务服务。(客户端依赖服务,服务代表通过设置提供不同的服务,将自身提供给客户端代表其他服务,客户端->业务代表->服务) delegate/代表
interface BusinessService { doProcessing(); } // 实体服务类 class EJBService implements BusinessService { doProcessing() { console.log("Processing task by invoking EJB Service"); } } class JMSService implements BusinessService { doProcessing() { console.log("Processing task by invoking JMS Service"); } } // 业务查询服务 class BusinessLookUp { getBusinessService(serviceType) { if (serviceType == "EJB") { return new EJBService(); } else { return new JMSService(); } } } // 业务代表 class BusinessDelegate { private lookupService = new BusinessLookUp(); private businessService; private serviceType; setServiceType(serviceType) { this.serviceType = serviceType; } // 代表其他服务执行操作 doTask() { this.businessService = this.lookupService.getBusinessService( this.serviceType ); this.businessService.doProcessing(); } } // 客户端 class Client { businessService; constructor(businessService) { this.businessService = businessService; } doTask() { this.businessService.doTask(); } } // 使用 const businessDelegate = new BusinessDelegate(); businessDelegate.setServiceType("EJB"); const client = new Client(businessDelegate); client.doTask(); businessDelegate.setServiceType("JMS"); client.doTask();
>组合实体模式:更新一个组合实体时,内部依赖对象beans会自动更新。组合实体:是主要的实体bean,可以使粗粒的,或者包含一个粗粒对象,用于持续生命周期;粗粒度对象:包含依赖对象,有自己的生命周期,也能管理依赖对象的生命周期;依赖对象:是一个持续生命周期依赖于粗粒度对象的对象;策略:如何实现组合实体。(就是一组相似对象组合捆绑在一起操作)entity/实体
// 依赖对象 class DependentObject1 { data; setData(data) { this.data = data; } getData() { return this.data; } } class DependentObject2 { data; setData(data) { this.data = data; } getData() { return this.data; } } // 粗粒度对象 class CoarseGrainedObject { do1 = new DependentObject1(); do2 = new DependentObject2(); setData(data1, data2) { this.do1.setData(data1); this.do2.setData(data2); } getData() { return [this.do1.getData(), this.do2.getData()]; } } // 组合实体(这不是俄罗斯套娃???) class CompositeEntity { private cgo = new CoarseGrainedObject(); setData(data1, data2) { this.cgo.setData(data1, data2); } getData() { return this.cgo.getData(); } } // 使用组合实体的客户端类 class Client { private compositeEntity = new CompositeEntity(); printData() { this.compositeEntity.getData().forEach((element) => { console.log("Data:" + element.getData()); }); } setData(data1, data2) { this.compositeEntity.setData(data1, data2); } } // 使用 const client = new Client(); client.setData("Test", "Data"); client.printData(); client.setData("second Test", "Data1"); client.printData();
>数据访问对象模式:DAO,用于把低级的数据访问API或操作从高级的业务服务中分离出来。数据访问对象接口:定义了在一个模型对象上要执行的标准操作;数据访问对象实体类:实现上述接口,负责从数据源获取数,数据源可以是数据库,也可以是xml,或者其他;模型对象/数值对象:简单的POJO,包含get/set方法来存储通过使用DAO类检索到的数据。(有幸碰到过这个系统,在控制器controller和模型model质检加了DAO层和service层,从控制器到数据库质检加了三层重复的数据对象,做个项目就像跑马拉松,疲于奔命。个人觉得,若非异常庞大的项目,要求异常严格,控制器和模型就够了,甚至只有控制器也够了,而且检索应该是按需检索,需要一个字段没必要把整条数据都查出莱。)
// 数值对象 class Student { private name; private rollNo; constructor(name, rollNo) { this.name = name; this.rollNo = rollNo; } getName() { return this.name; } setName(name) { this.name = name; } getRollNo() { return this.rollNo; } setRollNo(rollNo) { this.rollNo = rollNo; } } // 数访问对象接口 interface StudentDao { getAllStudents(); getStudent(rollNo); updateStudent(student); deleteStudent(student); } // 数据访问对象实体 class StudentDaoTmpl implements StudentDao { students: any; constructor() { this.students = []; const student1 = new Student("Robert", 0); const student2 = new Student("John", 1); this.students.push(student1); this.students.push(student2); } deleteStudent(student) { let rollNo = student.getRollNo() this.students.splice( this.students.findIndex((item) => item == student), 1 ); console.log("student roll no " + rollNo + " 已删除"); } getAllStudents() { return this.students; } getStudent(rollNo) { return this.students.find((item) => item.getRollNo() == rollNo); } updateStudent(student) { const index = this.students.findIndex( (item) => item.getRollNo() == student.getRollNo() ); this.students[index].setName = student.getName(); console.log("student rollNo " + student.getRollNo() + " has been updated"); } } // 使用 const studentDao = new StudentDaoTmpl(); // 输出所有学生 studentDao.getAllStudents().forEach((element) => { console.log( "student: rollNo " + element.getRollNo() + " name " + element.getName() ); }); // 更新学生 let student = studentDao.getAllStudents()[0]; student.setName("Michael"); // studentDao.updateStudent(student) // 引用啊,不用更新吧? // 获取学生 studentDao.getStudent(0); studentDao.deleteStudent(student) console.log(student,studentDao.getAllStudents())
>前端控制器模式:用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理。比如认证/授权/记录日志,或者跟踪请求,然后传给相应的处理程序。前端控制器:处理所有请求的单个处理程序,基于web或桌面;调度器:前端控制器可能使用一个调度器对象来调度请求到相应的具体处理程序;视图:视图是为请求而创建的对象(权限鉴定,路由分发)
// 视图 class HomeView { show() { console.log("Displaying Home Page"); } } class StudentView { show() { console.log("Displaying Student Page"); } } // 调度器 class Dispatcher { private studentView; private homeView; constructor() { this.studentView = new StudentView(); this.homeView = new HomeView(); } dispatch(request) { if (request == "STUDENT") { this.studentView.show(); } else { this.homeView.show(); } } } // 前端控制器 class FrontController { private dispatcher; constructor() { this.dispatcher = new Dispatcher(); } private isAuthenticUser() { console.log("User is authenticated successfully."); return true; } private trackRequest(request) { console.log("Page requested:" + request); } public dispatchRequest(request) { // 记录 this.trackRequest(request); if (this.isAuthenticUser()) { this.dispatcher.dispatch(request); } } } // 使用 const frontController = new FrontController() frontController.dispatchRequest('HOME') frontController.dispatchRequest('STUDENT')
>拦截过滤器模式:用于对应用程序的请求响应做一些预处理/后处理。做认证/授权/记录日志/跟踪请求。过滤器,过滤器链,Target,过滤管理器,客户端
// 过滤器接口 interface Filter { execute(request); } // 过滤器 class AuthenticationFilter implements Filter { execute(request) { console.log("Authentication request:" + request); } } class DebugFilter implements Filter { execute(request) { console.log("request log:" + request); } } // Target class Target { execute(request) { console.log("Execute request: " + request); } } // 过滤器链 class FilterChain{ private filters:any = [] private target addFilter(filter){ this.filters.push(filter) } execute(request){ this.filters.forEach(element => { element.execute(request) }); this.target.execute(request) } setTarget(target){ this.target = target } } // 过滤管理器(又在套娃了) class FilterManager{ filterChain constructor(target){ this.filterChain = new FilterChain() this.filterChain.setTarget(target) } setFilter(filter){ this.filterChain.addFilter(filter) } filterRequest(request){ this.filterChain.execute(request) } } // 客户端 class Client{ filterManager setFilterManager(filterManager){ this.filterManager = filterManager } sendRequst(request){ this.filterManager.filterRequest(request) } } // 使用 const filterManager = new FilterManager(new Target()) filterManager.setFilter(new AuthenticationFilter()) filterManager.setFilter(new DebugFilter()) const client = new Client() client.setFilterManager(filterManager) client.sendRequst('HOME')
>服务定位器模式:使用服务对象的缓存(就是在请求和响应之间加缓存)。服务,Context,服务定位器,缓存,客户端
// 服务接口 interface Service { getName(); execute(); } // 服务 class Service1 implements Service { execute() { console.log("Execute Service1"); } getName() { return "service1"; } } class Service2 implements Service { execute() { console.log("Execute Service2"); } getName() { return "service2"; } } // 为 JNDI 查询创建 InitialContext。 class InitialContext { lookup(jndiName) { if (jndiName == "service1") { console.log("Looking up and creating a new Service1 object"); return new Service1(); } if (jndiName == "service2") { console.log("Looking up and creating a new Service2 object"); return new Service2(); } return null; } } // Cache class Cache { private services; constructor() { this.services = []; } getService(serviceName) { this.services.forEach((element) => { if (serviceName == element.getName()) { console.log("Returning cached " + serviceName + "Object"); return element; } }); return null; } addService(newService) { let exists = false; this.services.forEach((element) => { if (newService.getName() == element.getName()) { exists = true; } }); if (!exists) { this.services.push(newService); } } } // 服务定位器(查询缓存,如果没有就新增缓存) class ServiceLocator { private static cache; static { this.cache = new Cache(); } static getService(jndiName) { const service = this.cache.getService(jndiName); if (service != null) { return service; } const context = new InitialContext(); const service1 = context.lookup(jndiName); this.cache.addService(service1); return service1; } } // 使用 let service = ServiceLocator.getService('service1') service.execute() service = ServiceLocator.getService('service2') service.execute() service = ServiceLocator.getService('service1') service.execute() service = ServiceLocator.getService('service2') service.execute()
>传输对象模式:用于从客户端向服务器一次性传递带有多个属性的数据,传输对象也被称为数值对象。业务对象,传输对象,客户端(数据通过对象传输,业务对象可以看成一个数据保存和处理的操作类)
// 传输对象 class StudentVO { private name; private rollNo; constructor(name, rollNo) { this.name = name; this.rollNo = rollNo; } getName() { return this.name; } setName(name) { this.name = name; } getRollNo() { return this.rollNo; } setRollNo(rollNo) { this.rollNo = rollNo; } } // 业务对象(保存了所有的数据对象) class StudentBO { students; constructor() { this.students = []; let student1 = new StudentVO("Robert", 0); let student2 = new StudentVO("John", 1); this.students.push(student1); this.students.push(student2); } deleteStudent(student) { let rollNo = student.getRollNo(); this.students.splice( this.students.findIndex((item) => item == student), 1 ); console.log("Student: Roll No " + rollNo + "has been deleted"); } getAllStudents() { return this.students; } getStudent(rollNo) { return this.students.find((item) => item.getRollNo() == rollNo); } updateStudent(student) { let index = this.students.findIndex((item) => item == student); this.students[index].setName(student.getName()); console.log("updated"); } } // 使用(客户端) const sutdentBusinessObject = new StudentBO(); // 查询所有输出 sutdentBusinessObject.getAllStudents().forEach((element) => { console.log( "student:rollno " + element.getRollNo() + " name " + element.getName() ); }); // 获取 const student = sutdentBusinessObject.getAllStudents()[0]; // 更新 student.setName("Michael"); // sutdentBusinessObject.updateStudent(student); //没必要 console.log("all students", sutdentBusinessObject.getAllStudents());