软件设计模式
软件设计模式和代码优化
一、软件设计模式
软件模式是将模式的一般概念应用于软件开发领域,是软件开发的总体指导思路和参照样板。软件模式并非仅局限于设计模式,还包括:架构模式、分析模式和过程模式等
设计模式(Design Pattern),是解决特定问题的一系列套路;是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案;是一套经验总结
设计模式本质是面向对象设计原则的实际运用,是对类的封装性、继承性、多态性,以及类的关联关系和组合关系的充分理解
1.七大设计原则
1.1 开闭原则(OCP)
指一个软件实体如类,模块和函数应该对扩展开放,对修改关闭,以提高系统的复用性和可维护性。在功能改动或升级时,尽可能的不修改源码,而是通过继承实现类的方式实现新功能,而这些都可以通过接口和抽象类实现,也就是面向抽象编程
1.2 里氏替换原则(LSP)
指一个软件实体可以如果适用父类,那么一定适用其子类。子类可以扩展父类的功能,而不能改变父类原有的功能,即如果将原本父类替换为子类,程序运行结果不变
1.3 依赖倒置原则(DIP)
指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。通过依赖倒置,降低类与类之间的耦合性,面向接口编程,不要面向实现编程,减少类和类之间的耦合性
1.4 接口隔离原则(ISP)
指用多个专门的接口,而不使用单一的接口,避免接口过于臃肿。设计接口原则:一个类对另一个类的依赖应该建立在最小的接口上,避免实现接口时还要实现他不需要的方法。要尽可能的细化接口,要符合高内聚,低耦合的设计思想
1.5 合成复用原则(CRP)
指尽可能使用对象组合或对象聚合的方式实现代码复用,而不是用继承关系达到代码复用的目的
1.6 单一职责原则(SRP)
指一个类应该只维护一个功能,以防止需求变更时,修改某个方法而导致其他方法受影响的情况,类实现职责要单一;控制类的粒度、将对象解耦、提高内聚性,目的是降低程序的复杂度和耦合性
1.7 迪米特法则(LoD)
最少知识原则(LKP),指一个对象应该对其他对象保持最少的了解,比如不允许其他类出现在本类的方法中,降低类间的耦合,通过中介类,增加了系统复杂性
2.全部软件设计模式
设计模式有两种分类方法,即根据模式的目的来分和根据模式的作用的范围来分,根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模式 3 种
类模式
用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF 中的工厂方法、(类)适配器、模板方法、解释器属于该模式
对象模式
用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式
前端常用模式
工厂模式,单例模式,原型模式,适配器模式,装饰器模式,代理模式,外观模式,组合模式,策略模式,模板模式,观察者模式,迭代器模式,访问者模式,中介者模式
2.1 创建型模式
描述对象如何创建,是为了将对象的创建与使用分离。包括五种:单例、原型、工厂方法、抽象工厂、建造者
2.1.1 工厂模式 ★
又叫工厂方法模式,只需要创建一个工厂接口和多个工厂实现类。工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替 new 操作的一种模式
//定义角色接口
interface user {
showIdentify(userType: string): void;
}
//定义产品类
class administrator implements user {
public showIdentify(): void {
console.log("I'm an administrator.");
}
}
//定义产品类
class normalUser implements user {
public showIdentify(): void {
console.log("I'm a normal user.");
}
}
//定义工厂类
class userFactory {
private userType: string;
constructor(userType: string) {
this.userType = userType;
}
public getUser() {
if (this.userType === "administrator") {
return new administrator();
} else if (this.userType === "normal user") {
return new normalUser();
} else {
return null;
}
}
}
//测试
let user = new userFactory("administrator").getUser();
user && user.showIdentify();
//结果
//I'm an administrator.
2.1.2 抽象工厂模式
抽象工厂模式是提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。区别于工厂方法模式的地方,工厂方法模式是创建一个工厂,可以实现多种对象;而抽象工厂模式是提供一个抽象工厂接口,里面定义多种工厂,每个工厂可以生产多种对象,可以理解为工厂的工厂
//定义角色、性别接口
interface user {
userType(): void;
}
interface sex {
sexType(): void;
}
//定义产品类
class administrator implements user {
public userType(): void {
console.log("I'm an administrator.");
}
}
class normalUser implements user {
public userType(): void {
console.log("I'm a normal user.");
}
}
class male implements sex {
public sexType(): void {
console.log("I'm a male.");
}
}
class female implements sex {
public sexType(): void {
console.log("I'm a female.");
}
}
//定义抽象工厂
abstract class AbstractFactory {
public abstract getUser(userType: string): any;
public abstract getSex(sexType: string): sex;
}
//创建工厂类
class userFactory extends AbstractFactory {
public getUser(userType: string): any {
if (userType === "administrator") {
return new administrator();
} else if (userType === "normal user") {
return new normalUser();
} else {
return null;
}
}
public getSex(): any {
return null;
}
}
//创建工厂类
class sexFactory extends AbstractFactory {
public getUser(): any {
return null;
}
public getSex(sexType: string): any {
if (sexType === "male") {
return new male();
} else if (sexType === "female") {
return new female();
} else {
return null;
}
}
}
//定义抽象工厂生成类
class factoryProducer {
public getFactory(factoryType: string): any {
if (factoryType === "user") {
return new userFactory();
} else if (factoryType === "sex") {
return new sexFactory();
} else {
return null;
}
}
}
//测试
let user = new factoryProducer().getFactory("user");
user.getUser("administrator").userType();
let sex = new factoryProducer().getFactory("sex");
sex.getSex("male").sexType();
//结果
//I'm an administrator.
//I'm a male.
2.1.3 单例模式 ★
单例模式能保证一个类仅有一个实例,并提供一个访问它的全局访问点,同时在类内部创造单一对象,通过设置权限,使类外部无法再创造对象。单例对象能保证在运行环境中,该对象只有一个实例存在,可以通过设置构造函数为private实现
//创建单例类
class SingleClass {
private name: string = "";
private static singleClass: SingleClass = new SingleClass();
private constructor(){};
static getSingleClass(): SingleClass {
return this.singleClass;
}
public getName(): string {
return this.name;
}
public setName(name: string): void {
this.name = name;
}
}
//测试
let obj1 = SingleClass.getSingleClass();
obj1.setName("zs");
console.log(obj1.getName());
2.1.4 建造者模式
使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的
//创建食物条目和包装接口
interface item {
name(): string;
packing(): packing;
price(): number;
}
interface packing {
pack(): string;
}
//创建包装纸和瓶子类实现包装接口
class wrapper implements packing {
public pack(): string {
return "Wrapper";
}
}
class bottle implements packing {
public pack(): string {
return "Bottle";
}
}
//创建实现食物条目的抽象类和继承类
abstract class Buger implements item {
public abstract name(): string;
public packing(): wrapper {
return new wrapper();
}
public abstract price(): number;
}
abstract class drink implements item {
public abstract name(): string;
public packing(): bottle {
return new bottle();
}
public abstract price(): number;
}
class fishBuger extends Buger {
public name(): string {
return "fishBuger";
}
public price(): number {
return 20;
}
}
class chickenBuger extends Buger {
public name(): string {
return "ChickenBuger";
}
public price(): number {
return 25;
}
}
class coke extends drink {
public name(): string {
return "PepsiCoke";
}
public price(): number {
return 10;
}
}
class tea extends drink {
public name(): string {
return "LiptonTea";
}
public price(): number {
return 12;
}
}
//创建一顿饭meal类
class meal {
private menu: Array<item> = [];
public addItem(item: item): void {
this.menu.push(item);
}
public cost(): number {
let cost = 0;
this.menu.forEach((element) => {
cost += element.price();
});
return cost;
}
public showItems(): void {
this.menu.forEach((element) => {
console.log(
"Item: " +
element.name() +
"; Packing: " +
element.packing().pack() +
"; Price: " +
element.price()
);
});
}
}
//创建mealBuilder对象,负责创建meal对象
class mealBuilder {
public healthMeal(): meal {
let healthMeal = new meal();
healthMeal.addItem(new fishBuger());
healthMeal.addItem(new tea());
return healthMeal;
}
public happyMeal(): meal {
let healthMeal = new meal();
healthMeal.addItem(new chickenBuger());
healthMeal.addItem(new coke());
return healthMeal;
}
}
//测试
let mealHelper = new mealBuilder();
let healthMeal = mealHelper.healthMeal();
healthMeal.showItems();
let happyMeal = mealHelper.happyMeal();
happyMeal.showItems();
//结果
//Item: fishBuger; Packing: Wrapper; Price: 20
//Item: LiptonTea; Packing: Bottle; Price: 12
//Item: ChickenBuger; Packing: Wrapper; Price: 25
//Item: PepsiCoke; Packing: Bottle; Price: 10
2.1.5 原型模式 ★
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,在 JS 中相当于设置新对象的__proto__
为原型对象
let person = {
name: "zs",
age: 24,
};
let newPerson = Object.create(person);
console.log(newPerson.__proto__);
console.log(newPerson.name, newPerson.age);
//结果
//{name: 'zs', age: 24}
//zs 24
2.2 结构型模式
描述类或对象如何组织成更大结构,包括 7 种:代理、适配器、桥接、装饰、外观、享元、组合
2.2.1 适配器模式 ★
适配器模式是使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,衔接两个不兼容、独立的接口的功能,使得它们能够一起工作,适配器起到中介的作用,适配器是原来的类不能用
//被适配类
class AC220 {
outputAC220V(): number {
console.log("output AC220V");
return 220;
}
}
//目标类
class DC5 {
outPutDC5V(): number {
console.log("output DC5V");
return 5;
}
}
//创建适配器类
class adapter extends DC5 {
private inputVol = new AC220();
outPutDC5V(): number {
console.log("change input AC" + this.inputVol.outputAC220V() + "V, to output DC5V");
return super.outPutDC5V();
}
}
//测试
let newAdapter = new adapter();
newAdapter.outPutDC5V();
//结果
//output AC220V
//change input AC220V, to output DC5V
//output DC5V
2.2.2 装饰器模式 ★
装饰器模式是动态地给一个对象添加一些额外的职责,给一个对象增加一些新的功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。除了动态的增加,也可以动态的撤销,要做到动态的形式,不可以用继承实现,因为继承是静态的,装饰器是原来的类还能用
//创建形状接口
interface shape {
name(): string;
draw(): void;
}
//创建圆类
class circle implements shape {
name(): string {
return "circle";
}
draw(): void {
console.log("draw a circle.");
}
}
//创建装饰器类
class decorator implements shape {
protected shape: shape;
constructor(shape: shape) {
this.shape = shape;
}
name(): string {
return this.shape.name();
}
draw(): void {
this.shape.draw();
}
setBorder(color: string): void {
console.log(
"the border of " + this.shape.name() + " has been set in " + color + "."
);
}
}
//测试
let testCircle = new circle();
let decoratorCircle = new decorator(testCircle);
decoratorCircle.draw();
decoratorCircle.setBorder("red");
//结果
//draw a circle.
//the border of circle has been set in red.
2.2.3 代理模式 ★
代理模式是为其他对象提供一种代理以控制对这个对象的访问,也就是创建类的代理类,间接访问被代理类的过程中,对其功能加以控制
let star = {
name: "zs",
age: 18,
};
let proxy = new Proxy(star, {
get(targetObj, propoty, receiver) {
//receiver是代理对象proxy
return targetObj[propoty];
},
set(targetObj, property, value, receiver) {
if (property == "height") {
if (typeof value === "number") {
return Reflect.set(targetObj, property, `${value + 10}cm`);
} else {
throw "身高只能是数字类型的值";
}
}
},
has(targetobj, property) {
return Reflect.has(...arguments);
},
deleteProperty(targetobj, property) {
if (property === "name") {
return false;
} else {
return Reflect.deleteProperty(...arguments);
}
},
});
//测试
console.log(proxy.name);
proxy.height = 180;
console.log(proxy.height);
console.log("age" in proxy);
delete proxy.name;
console.log(proxy.name);
//结果
//zs
//190cm
//true
//zs
2.2.4 外观模式 ★
外观模式提供了一个统一的接口,用来访问子系统中的一群接口,它定义了一个高层接口,让子系统更容易使用,主要是简化子系统的接口
//定义子类
interface buyCarStep {
getStep(): void;
}
class carShop implements buyCarStep {
public getStep(): void {
console.log("买车");
}
}
class DMV {
public getStep(): void {
console.log("发布牌照");
}
}
//定义外观类
class helper {
private BMW: carShop = new carShop();
private HZDMV: DMV = new DMV();
public buyCar(): void {
this.BMW.getStep();
}
public getPlate(): void {
this.HZDMV.getStep();
}
}
//测试
let zs = new helper();
zs.buyCar();
zs.getPlate();
//结果
//买车
//发布牌照
2.2.5 桥接模式
桥接模式是将抽象部分与实现部分分离,使它们都可以独立的变化。桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化
//定义抽象cpu类
abstract class CPU {
public abstract work(gpu: GPU):void;
}
//定义CPU实体类
class IntelCPU extends CPU {
public work(gpu: GPU):void{
console.log("Core I9 12900KF working with" + gpu.with());
}
}
class AMDCPU extends CPU {
public work(gpu: GPU):void{
console.log("Ryzen R9 5950X working with" + gpu.with());
}
}
//定义显卡接口
interface GPU {
with():string;
}
//定义接口实现类
class NVIDAGPU implements GPU {
public with(): string{
return "RTX 3090TI";
}
}
class AMDGPU implements GPU {
public with():string {
return "RX 6950XT";
}
}
//测试
let cpu = new IntelCPU();
cpu.work(new (NVIDAGPU));
//结果
//Core I9 12900KF working withRTX 3090TI
2.2.6 组合模式 ★
组合模式是将对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性,简单讲就是一个对象包含另一个对象
//定义抽象文件类
abstract class AbstractFile {
private name: string;
constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
public add(file: AbstractFile): void {}
public del(file: AbstractFile): void {}
public open(): void {}
public getFile(index: number): any {}
}
//定义具体文件类
class MusicFile extends AbstractFile {
constructor(name: string) {
super(name);
}
public open(): void {
console.log("开始播放" + this.getName());
}
}
class VideoFile extends AbstractFile {
constructor(name: string) {
super(name);
}
public open(): void {
console.log("开始播放" + this.getName());
}
}
//定义文件夹类
class Folder extends AbstractFile {
private fileList: Array<AbstractFile> = new Array();
constructor(name: string) {
super(name);
}
public add(file: AbstractFile): void {
this.fileList.push(file);
}
public del(file: AbstractFile): void {
let index: number = -1;
for (let i = 0; i < this.fileList.length; i++) {
index++;
if (this.fileList[i].getName() === file.getName()) {
break;
}
}
this.fileList[index] = new MusicFile("空文件");
}
public open(): void {
console.log("打开文件夹" + this.getName());
this.fileList.forEach((item) => {
item.open();
});
}
public getFile(index: number): AbstractFile {
return this.fileList[index];
}
}
//测试
let diskD = new Folder("D盘");
let musicFolder = new Folder("音乐");
let videoFolder = new Folder("视频");
let musicOne = new MusicFile("逆战.mp3");
let musicTow = new MusicFile("孤勇者.mp3");
let videoOne = new VideoFile("战狼2.mp4");
let videoTwo = new VideoFile("喜羊羊与灰太狼.avi");
musicFolder.add(musicOne);
musicFolder.add(musicTow);
videoFolder.add(videoOne);
videoFolder.add(videoTwo);
diskD.add(musicFolder);
diskD.add(videoFolder);
diskD.open();
//结果
//打开文件夹D盘
//打开文件夹音乐
//开始播放逆战.mp3
//开始播放孤勇者.mp3
//打开文件夹视频
//开始播放战狼2.mp4
//开始播放喜羊羊与灰太狼.avi
2.2.7 享元模式
享元模式是运用共享技术有效地支持大量细粒度的对象。享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,重用现有的同类对象,若未找到匹配的对象,则创建新对象,这样可以减少对象的创建,降低系统内存,提高效率
//定义形状接口
interface Shape{
draw():void;
}
//定义实现接口形状类
class Circle implements Shape {
private color: string;
constructor(color: string){
console.log("Create a " + color + " circle");
this.color = color;
}
public draw():void{
console.log("Draw a " + this.color + " circle");
}
}
//定义形状工厂
class ShapeFactory {
private map:Map<any, any> = new Map();
public getShape(color: string):Shape{
let shape = this.map.get(color);
if(!shape) {
shape = new Circle(color);
this.map.set(color, shape);
}
return shape;
}
}
//测试
let factory = new ShapeFactory();
let redCircle = factory.getShape("red").draw();
let blueCircle = factory.getShape("blue").draw();
let anotherRedCircle = factory.getShape("red").draw();
//结果
//Create a red circle
//Draw a red circle
//Create a blue circle
//Draw a blue circle
//Draw a red circle
2.3 行为型模式
描述类或对象之间如何协作完成任务,包括 11 种:模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器
2.3.1 策略模式 ★
策略模式是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换
//定义策略
interface Strategy {
strategyInterface(): void;
}
//定义具体策略
class BicycleTravel implements Strategy {
public strategyInterface(): void {
console.log("travel with bicycle.");
}
}
class CarTravel implements Strategy {
public strategyInterface(): void {
console.log("travel with car.");
}
}
//定义持有策略的对象
class Context {
private strategy: Strategy;
constructor(strategy: Strategy) {
this.strategy = strategy;
}
public contextInterface() {
this.strategy.strategyInterface();
}
}
//测试
let context = new Context(new CarTravel());
let travelMethod = context.contextInterface();
//结果
//travel with car.
2.3.2 模版模式 ★
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以在不改变该算法结构的情况下重定义该算法的某些特定步骤
//定义抽象类
abstract class AbstractClass {
public number: number;
public amount: number;
public score: number;
constructor(number: number, amount: number, score: number) {
this.number = number;
this.amount = amount;
this.score = score;
}
//取号
public takeNumber(): void {
console.log("请拿好您的号码" + this.number);
}
//排队
public queue(): void {
console.log("请排队");
}
//业务
public abstract work(): void;
//评分
public evaluation(): void {
console.log("请对我的服务评分" + this.score);
}
//模板方法
public process(): void {
this.takeNumber();
this.queue();
this.work();
this.evaluation();
}
}
//基金类
class Fund extends AbstractClass {
constructor(number: number, amount: number, score: number) {
super(number, amount, score);
}
public work(): void {
console.log("购买" + this.amount + "元的基金");
}
}
//股票类
class Shares extends AbstractClass {
constructor(number: number, amount: number, score: number) {
super(number, amount, score);
}
public work(): void {
console.log("购买" + this.amount + "元的股票");
}
}
//测试
let tom = new Fund(1, 20000, 80);
let jack = new Shares(2, 50000, 90);
tom.process();
jack.process();
//结果
//请拿好您的号码1
//请排队
//购买20000元的基金
//请对我的服务评分80
//请拿好您的号码2
//请排队
//购买50000元的股票
//请对我的服务评分90
2.3.3 观察者模式 ★
又叫发布订阅模式是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
//定义被观察者抽象类
abstract class Subject {
private obsList: Map<any, any> = new Map();
private count: number = 0;
//增加观察者
public addObserver(obs: Observer) {
this.obsList.set(obs, this.count);
this.count++;
}
//删除观察者
public delObserver(obs: Observer) {
let res = this.obsList.delete(obs);
res && this.count--;
}
//通知所有观察者
public notifyObserver(score: number): void {
for (let key of this.obsList.keys()) {
key.changeCaptured(score);
}
}
//被观察者改变方法
public abstract sendScore(): void;
}
//定义具体被观察者
class examResult extends Subject {
private score: number = 0;
constructor(score: number) {
super();
this.score = score;
}
sendScore(): void {
console.log("成绩发布了,成绩为" + this.score);
this.notifyObserver(this.score);
}
}
//定义观察接口
interface Observer {
changeCaptured(score: number): void;
}
//定义具体观察者
class physics implements Observer {
changeCaptured(score: number): void {
console.log("捕获到物理成绩,结果为" + score);
if (score < 60) {
console.log("物理不及格");
} else {
console.log("物理及格");
}
}
}
class math implements Observer {
changeCaptured(score: number): void {
console.log("捕获到数学成绩,结果为" + score);
if (score < 90) {
console.log("数学不及格");
} else {
console.log("数学及格");
}
}
}
//测试
let finalExam = new examResult(88);
let physicsResult = new physics();
let mathResult = new math();
finalExam.addObserver(physicsResult);
finalExam.addObserver(mathResult);
finalExam.sendScore();
//结果
//成绩发布了,结果为88
//捕获到物理成绩,结果为88
//物理及格
//捕获到数学成绩,结果为88
//数学不及格
2.3.4 迭代器模式 ★
迭代器模式是提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的底层表示
在 JS 中一个数据类型如果有 Symbol.iterator 方法就代表改数据类型可以迭代,forof forin 实际上为调用该数据类型的 Symbol.iterator 中的 next 方法
//定义迭代器接口
interface iterator {
next(): void;
isDone(): boolean;
currentItem(): any;
}
//定义具体迭代器类
class NameIterator implements iterator {
private nameContainer: NameContainer;
private index: number = 0;
constructor(nameContainer: NameContainer) {
this.nameContainer = nameContainer;
}
public next(): void {
if (this.index < this.nameContainer.size()) {
this.index++;
}
}
public isDone(): boolean {
if (this.index === this.nameContainer.size()) {
return true;
} else {
return false;
}
}
public currentItem(): string {
return this.nameContainer.get(this.index);
}
}
//定义容器抽象类
abstract class Container {
public abstract getIterator(): iterator;
}
//定义具体容器类
class NameContainer extends Container {
private nameList: Array<string>;
constructor(nameList: Array<string>) {
super();
this.nameList = nameList;
}
public getIterator(): iterator {
return new NameIterator(this);
}
public size(): number {
return this.nameList.length;
}
public get(index: number): string {
let item = "";
if (index < this.nameList.length) {
item = this.nameList[index];
}
return item;
}
}
//测试
let testContainer = new NameContainer(["张三", "李四", "王五", "赵六"]);
let testIterator = testContainer.getIterator();
while (!testIterator.isDone()) {
console.log(testIterator.currentItem());
testIterator.next();
}
//结果
//张三
//李四
//王五
//赵六
2.3.5 责任链模式
责任链模式是避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求,比如事件冒泡
//定义dom接口
abstract class Dom {
public type:string;
public eventList: Array<{event: string, method:string}> = new Array;
protected nextDom: Dom | null = null;
constructor(type:string){
this.type = type;
}
public setNextDom(dom: Dom):void {
this.nextDom = dom;
}
public addEventListener(event: string, method: string):void {
this.eventList.push({ event, method });
};
public click():void{
let hasFound = false;
this.eventList.forEach(item => {
if(item.event === "click") {
console.log(item.method);
hasFound = true;
}
})
if(!hasFound) {
console.log("该dom没有绑定click事件");
}
if(this.nextDom) {
this.nextDom.click();
}
}
}
//定义具体实体类
class ChildDom extends Dom{
constructor(type: string){
super(type);
}
}
class ParentDom extends Dom{
constructor(type: string){
super(type);
}
}
//测试
let div = new ParentDom("div");
let span = new ChildDom("span");
div.addEventListener("click", "打开弹窗");
span.setNextDom(div);
span.click();
//结果
//该dom没有绑定click事件
//打开弹窗
2.3.6 命令模式
命令模式是将一个请求封装成一个对象,从而使发出者可以用不同的请求对客户进行参数化。模式当中存在调用者、接收者、命令三个对象,实现请求和执行分开;调用者选择命令发布,命令指定接收者
//定义命令接口
interface Command {
execute():void;
}
//定义命令实现类
class OpenCommand implements Command{
private tv: TV = new TV();
public execute():void{
this.tv.open();
}
}
class ChangeCommand implements Command{
private tv: TV = new TV();
public execute():void{
this.tv.change();
}
}
class CloseCommand implements Command{
private tv: TV = new TV();
public execute():void{
this.tv.close();
}
}
//定义接收者类
class TV{
public open():void{
console.log("打开电视");
}
public change():void{
console.log("更换频道");
}
public close():void{
console.log("关闭电视");
}
}
//定于命令调用者遥控器
class Controller {
private commandList: Array<Command>;
constructor(commandList: Array<Command>) {
this.commandList = commandList;
}
public action():void{
this.commandList.forEach(item => {
item.execute();
})
}
}
//测试
let openCommand = new OpenCommand();
let changeCommand = new ChangeCommand();
let closeCommand = new CloseCommand();
let controller = new Controller([openCommand, changeCommand, closeCommand]);
controller.action();
//结果
//打开电视
//更换频道
//关闭电视
2.3.7 备忘录模式
备忘录模式是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。创建一个备忘录类,用来存储原始类的信息;同时创建备忘录仓库类,用来存储备忘录类,主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,也就是做个备份
//创建备忘录发起对象
class Originator {
private state: string = "";
public getState():string {
return this.state;
}
public setState(state:string):void {
this.state = state;
}
// 创建一个备忘录
public createMemento():Memento {
return new Memento(this.state);
}
// 从备忘录恢复
public restoreMemento(memento: Memento):void {
this.setState(memento.getState());
}
}
//创建备忘录对象
class Memento {
private state: string;
constructor(state: string){
this.state = state;
}
public getState(): string {
return this.state;
}
public setState(state: string): void {
this.state = state;
}
}
//创建管理备忘录对象
class Caretaker {
// 备忘录对象
private memento: Memento;
constructor(memento: Memento) {
this.memento = memento;
}
public getMemento(): Memento {
return this.memento;
}
public storeMemento(memento: Memento): void {
this.memento = memento;
}
}
//测试
let originator = new Originator();
originator.setState("状态1");
console.log(originator.getState());
let caretaker = new Caretaker(originator.createMemento());
originator.setState("状态2");
console.log(originator.getState());
caretaker.storeMemento(originator.createMemento());
originator.setState("状态3");
console.log(originator.getState());
originator.restoreMemento(caretaker.getMemento());
console.log(originator.getState());
//结果
//状态1
//状态2
//状态3
//状态2
2.3.8 状态模式
状态模式是允许对象在内部状态发生改变时改变它的行为。对象具有多种状态,且每种状态具有特定的行为
//创建状态抽象类
abstract class State{
public abstract handle(): void;
}
//创建具体状态类
class PlayerOnline extends State {
public handle(): void {
console.log("Player is online, can play games!");
}
}
class PlayerOffline extends State {
public handle(): void {
console.log("Player is offline, can't play games!");
}
}
//创建环境类
class Content {
private playerState: State;
constructor(state: State){
this.playerState = state;
}
public setState(state: State):void{
this.playerState = state;
}
public require():void {
this.playerState.handle();
}
}
//测试
let context = new Content(new PlayerOnline());
context.require();
context.setState(new PlayerOffline());
context.require();
//结果
//Player is online, can play games!
//Player is offline, can't play games!
2.3.9 访问者模式 ★
访问者模式主要是将数据结构与数据操作分离。在被访问的类里面加一个对外提供接待访问者的接口,访问者封装了对被访问者结构的一些杂乱操作,解耦结构与算法,同时具有优秀的扩展性。通俗来讲就是一种分离对象数据结构与行为的方法
//定义抽象硬件类
abstract class Hardware {
private type: string;
constructor(type: string) {
this.type = type;
}
public getType(): string {
return this.type;
}
public abstract run(): void;
}
//定义具体硬件类
class CPU extends Hardware {
private cpuType: string;
constructor(cpuType: string) {
super("CPU");
this.cpuType = cpuType;
}
public run(): void {
console.log(super.getType() + " " + this.cpuType + " is running!");
}
}
class GPU extends Hardware {
private gpuType: string;
constructor(gpuType: string) {
super("GPU");
this.gpuType = gpuType;
}
public run(): void {
console.log(super.getType() + " " + this.gpuType + " is running!");
}
}
class SSD extends Hardware {
private ssdType: string;
constructor(ssdType: string) {
super("SSD");
this.ssdType = ssdType;
}
public run(): void {
console.log(super.getType() + " " + this.ssdType + " is running!");
}
}
//定义访问者接口
interface Visitor {
visitCPU(cpu: CPU): void;
visitGPU(gpu: GPU): void;
visitSSD(ssd: SSD): void;
}
//定义访问者实现类
class GTA5 implements Visitor {
visitCPU(cpu: CPU): void {
cpu.run();
}
visitGPU(gpu: GPU): void {
gpu.run();
}
visitSSD(ssd: SSD): void {
ssd.run();
}
}
//定义结构类
class Computer {
private cpu: CPU;
private gpu: GPU;
private ssd: SSD;
constructor(cpu: string, gpu: string, ssd: string) {
this.cpu = new CPU(cpu);
this.gpu = new GPU(gpu);
this.ssd = new SSD(ssd);
}
public runSoftWare(software: Visitor): void {
software.visitCPU(this.cpu);
software.visitGPU(this.gpu);
software.visitSSD(this.ssd);
}
}
//测试
let computer = new Computer(
"Intel Core I9 12900KF",
"NVIDA GEFORCE RTX 3090TI",
"SAMSUNG 980 PRO 2TB"
);
computer.runSoftWare(new GTA5());
//结果
//CPU Intel Core I9 12900KF is running!
//GPU NVIDA GEFORCE RTX 3090TI is running!
//SSD SAMSUNG 980 PRO 2TB is running!
2.3.10 中介者模式 ★
中介者模式是用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
//定义中介类聊天室
class ChatRoom {
public static showMessage(user: User, text: string) {
console.log("user " + user.getName() + " say: " + text);
}
}
//定义用户类
class User {
private name: string;
constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
public sendMessage(text: string): void {
ChatRoom.showMessage(this, text);
}
}
//测试
let tom = new User("tom");
let bob = new User("bob");
tom.sendMessage("Hello, i'm tom.");
tom.sendMessage("Nice to meet you.");
bob.sendMessage("Oh hi, I'm bob");
bob.sendMessage("Nice to meet you, too.");
//结果
//user tom say: Hello, i'm tom.
//user tom say: Nice to meet you.
//user bob say: Oh hi, I'm bob
//user bob say: Nice to meet you, too.
2.3.11 解释器模式
解释器模式是给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子,基本也就用在这个范围内,适用面较窄,例如:正则表达式的解释等
//创建表达式接口
interface Expression{
interpreter(): boolean;
}
//创建表达式实现类
class NormalExpression implements Expression {
private value: any;
constructor(value:any){
this.value = value;
}
public interpreter(): boolean {
return this.value ? true : false;
}
}
class AndExpression implements Expression {
private left: Expression;
private right: Expression;
constructor(left: Expression, right: Expression) {
this.left = left;
this.right = right;
}
public interpreter(): boolean {
return this.left.interpreter() && this.right.interpreter();
}
}
//测试
let arr = [];
let str = "hello";
let left = new NormalExpression(str.length);
let right = new NormalExpression(arr.length);
let res = new AndExpression(left, right).interpreter();
console.log(res);
//结果
//false