軟件設(shè)計(jì)模式和代碼優(yōu)化
一丸边、軟件設(shè)計(jì)模式
軟件模式是將模式的一般概念應(yīng)用于軟件開(kāi)發(fā)領(lǐng)域烛恤,是軟件開(kāi)發(fā)的總體指導(dǎo)思路和參照樣板岛宦。軟件模式并非僅局限于設(shè)計(jì)模式阱佛,還包括:架構(gòu)模式帖汞、分析模式和過(guò)程模式等
設(shè)計(jì)模式(Design Pattern),是解決特定問(wèn)題的一系列套路凑术;是一套用來(lái)提高代碼可復(fù)用性翩蘸、可維護(hù)性、可讀性淮逊、穩(wěn)健性以及安全性的解決方案催首;是一套經(jīng)驗(yàn)總結(jié)
設(shè)計(jì)模式本質(zhì)是面向?qū)ο笤O(shè)計(jì)原則的實(shí)際運(yùn)用,是對(duì)類的封裝性泄鹏、繼承性郎任、多態(tài)性,以及類的關(guān)聯(lián)關(guān)系和組合關(guān)系的充分理解
1.七大設(shè)計(jì)原則
1.1 開(kāi)閉原則(OCP)
指一個(gè)軟件實(shí)體如類备籽,模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放舶治,對(duì)修改關(guān)閉,以提高系統(tǒng)的復(fù)用性和可維護(hù)性。在功能改動(dòng)或升級(jí)時(shí)霉猛,盡可能的不修改源碼尺锚,而是通過(guò)繼承實(shí)現(xiàn)類的方式實(shí)現(xiàn)新功能,而這些都可以通過(guò)接口和抽象類實(shí)現(xiàn)韩脏,也就是面向抽象編程
1.2 里氏替換原則(LSP)
指一個(gè)軟件實(shí)體可以如果適用父類缩麸,那么一定適用其子類铸磅。子類可以擴(kuò)展父類的功能赡矢,而不能改變父類原有的功能,即如果將原本父類替換為子類阅仔,程序運(yùn)行結(jié)果不變
1.3 依賴倒置原則(DIP)
指設(shè)計(jì)代碼結(jié)構(gòu)時(shí)吹散,高層模塊不應(yīng)該依賴底層模塊,二者都應(yīng)該依賴其抽象八酒。通過(guò)依賴倒置空民,降低類與類之間的耦合性,面向接口編程羞迷,不要面向?qū)崿F(xiàn)編程界轩,減少類和類之間的耦合性
1.4 接口隔離原則(ISP)
指用多個(gè)專門的接口,而不使用單一的接口衔瓮,避免接口過(guò)于臃腫浊猾。設(shè)計(jì)接口原則:一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上,避免實(shí)現(xiàn)接口時(shí)還要實(shí)現(xiàn)他不需要的方法热鞍。要盡可能的細(xì)化接口葫慎,要符合高內(nèi)聚薇宠,低耦合的設(shè)計(jì)思想
1.5 合成復(fù)用原則(CRP)
指盡可能使用對(duì)象組合或?qū)ο缶酆系姆绞綄?shí)現(xiàn)代碼復(fù)用偷办,而不是用繼承關(guān)系達(dá)到代碼復(fù)用的目的
1.6 單一職責(zé)原則(SRP)
指一個(gè)類應(yīng)該只維護(hù)一個(gè)功能,以防止需求變更時(shí)澄港,修改某個(gè)方法而導(dǎo)致其他方法受影響的情況椒涯,類實(shí)現(xiàn)職責(zé)要單一;控制類的粒度回梧、將對(duì)象解耦废岂、提高內(nèi)聚性,目的是降低程序的復(fù)雜度和耦合性
1.7 迪米特法則(LoD)
最少知識(shí)原則(LKP)漂辐,指一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解泪喊,比如不允許其他類出現(xiàn)在本類的方法中,降低類間的耦合髓涯,通過(guò)中介類袒啼,增加了系統(tǒng)復(fù)雜性
2.全部軟件設(shè)計(jì)模式
設(shè)計(jì)模式有兩種分類方法,即根據(jù)模式的目的來(lái)分和根據(jù)模式的作用的范圍來(lái)分,根據(jù)模式是用來(lái)完成什么工作來(lái)劃分蚓再,這種方式可分為創(chuàng)建型模式滑肉、結(jié)構(gòu)型模式和行為型模式 3 種
類模式
用于處理類與子類之間的關(guān)系,這些關(guān)系通過(guò)繼承來(lái)建立摘仅,是靜態(tài)的靶庙,在編譯時(shí)刻便確定下來(lái)了。GoF 中的工廠方法娃属、(類)適配器六荒、模板方法、解釋器屬于該模式
對(duì)象模式
用于處理對(duì)象之間的關(guān)系矾端,這些關(guān)系可以通過(guò)組合或聚合來(lái)實(shí)現(xiàn)掏击,在運(yùn)行時(shí)刻是可以變化的,更具動(dòng)態(tài)性秩铆。GoF 中除了以上 4 種砚亭,其他的都是對(duì)象模式
前端常用模式
工廠模式,單例模式殴玛,原型模式捅膘,適配器模式,裝飾器模式滚粟,代理模式寻仗,外觀模式,組合模式坦刀,策略模式愧沟,模板模式,觀察者模式鲤遥,迭代器模式沐寺,訪問(wèn)者模式,中介者模式
2.1 創(chuàng)建型模式
描述對(duì)象如何創(chuàng)建盖奈,是為了將對(duì)象的創(chuàng)建與使用分離混坞。包括五種:?jiǎn)卫⒃透痔埂⒐S方法究孕、抽象工廠、建造者
2.1.1 工廠模式 ★
又叫工廠方法模式爹凹,只需要?jiǎng)?chuàng)建一個(gè)工廠接口和多個(gè)工廠實(shí)現(xiàn)類厨诸。工廠模式是我們最常用的實(shí)例化對(duì)象模式了,是用工廠方法代替 new 操作的一種模式
//定義角色接口
interface user {
showIdentify(userType: string): void;
}
//定義產(chǎn)品類
class administrator implements user {
public showIdentify(): void {
console.log("I'm an administrator.");
}
}
//定義產(chǎn)品類
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;
}
}
}
//測(cè)試
let user = new userFactory("administrator").getUser();
user && user.showIdentify();
//結(jié)果
//I'm an administrator.
2.1.2 抽象工廠模式
抽象工廠模式是提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口禾酱,而無(wú)需指定它們具體的類微酬。區(qū)別于工廠方法模式的地方绘趋,工廠方法模式是創(chuàng)建一個(gè)工廠,可以實(shí)現(xiàn)多種對(duì)象颗管;而抽象工廠模式是提供一個(gè)抽象工廠接口陷遮,里面定義多種工廠,每個(gè)工廠可以生產(chǎn)多種對(duì)象垦江,可以理解為工廠的工廠
//定義角色帽馋、性別接口
interface user {
userType(): void;
}
interface sex {
sexType(): void;
}
//定義產(chǎn)品類
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;
}
//創(chuàng)建工廠類
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;
}
}
//創(chuàng)建工廠類
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;
}
}
}
//測(cè)試
let user = new factoryProducer().getFactory("user");
user.getUser("administrator").userType();
let sex = new factoryProducer().getFactory("sex");
sex.getSex("male").sexType();
//結(jié)果
//I'm an administrator.
//I'm a male.
2.1.3 單例模式 ★
單例模式能保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)比吭,同時(shí)在類內(nèi)部創(chuàng)造單一對(duì)象绽族,通過(guò)設(shè)置權(quán)限,使類外部無(wú)法再創(chuàng)造對(duì)象梗逮。單例對(duì)象能保證在運(yùn)行環(huán)境中项秉,該對(duì)象只有一個(gè)實(shí)例存在绣溜,可以通過(guò)設(shè)置構(gòu)造函數(shù)為private實(shí)現(xiàn)
//創(chuàng)建單例類
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;
}
}
//測(cè)試
let obj1 = SingleClass.getSingleClass();
obj1.setName("zs");
console.log(obj1.getName());
2.1.4 建造者模式
使用多個(gè)簡(jiǎn)單的對(duì)象一步一步構(gòu)建成一個(gè)復(fù)雜的對(duì)象慷彤。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式,一個(gè) Builder 類會(huì)一步一步構(gòu)造最終的對(duì)象怖喻。該 Builder 類是獨(dú)立于其他對(duì)象的
//創(chuàng)建食物條目和包裝接口
interface item {
name(): string;
packing(): packing;
price(): number;
}
interface packing {
pack(): string;
}
//創(chuàng)建包裝紙和瓶子類實(shí)現(xiàn)包裝接口
class wrapper implements packing {
public pack(): string {
return "Wrapper";
}
}
class bottle implements packing {
public pack(): string {
return "Bottle";
}
}
//創(chuàng)建實(shí)現(xiàn)食物條目的抽象類和繼承類
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;
}
}
//創(chuàng)建一頓飯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()
);
});
}
}
//創(chuàng)建mealBuilder對(duì)象底哗,負(fù)責(zé)創(chuàng)建meal對(duì)象
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;
}
}
//測(cè)試
let mealHelper = new mealBuilder();
let healthMeal = mealHelper.healthMeal();
healthMeal.showItems();
let happyMeal = mealHelper.happyMeal();
happyMeal.showItems();
//結(jié)果
//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 原型模式 ★
原型模式是用于創(chuàng)建重復(fù)的對(duì)象,同時(shí)又能保證性能锚沸。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式跋选,它提供了一種創(chuàng)建對(duì)象的最佳方式,在 JS 中相當(dāng)于設(shè)置新對(duì)象的__proto__
為原型對(duì)象
let person = {
name: "zs",
age: 24,
};
let newPerson = Object.create(person);
console.log(newPerson.__proto__);
console.log(newPerson.name, newPerson.age);
//結(jié)果
//{name: 'zs', age: 24}
//zs 24
2.2 結(jié)構(gòu)型模式
描述類或?qū)ο笕绾谓M織成更大結(jié)構(gòu)哗蜈,包括 7 種:代理前标、適配器、橋接距潘、裝飾炼列、外觀、享元音比、組合
2.2.1 適配器模式 ★
適配器模式是使得原本由于接口不兼容而不能一起工作的那些類可以一起工作俭尖,銜接兩個(gè)不兼容、獨(dú)立的接口的功能洞翩,使得它們能夠一起工作稽犁,適配器起到中介的作用,適配器是原來(lái)的類不能用
//被適配類
class AC220 {
outputAC220V(): number {
console.log("output AC220V");
return 220;
}
}
//目標(biāo)類
class DC5 {
outPutDC5V(): number {
console.log("output DC5V");
return 5;
}
}
//創(chuàng)建適配器類
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();
}
}
//測(cè)試
let newAdapter = new adapter();
newAdapter.outPutDC5V();
//結(jié)果
//output AC220V
//change input AC220V, to output DC5V
//output DC5V
2.2.2 裝飾器模式 ★
裝飾器模式是動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)骚亿,給一個(gè)對(duì)象增加一些新的功能已亥,要求裝飾對(duì)象和被裝飾對(duì)象實(shí)現(xiàn)同一個(gè)接口,裝飾對(duì)象持有被裝飾對(duì)象的實(shí)例来屠。除了動(dòng)態(tài)的增加虑椎,也可以動(dòng)態(tài)的撤銷秫舌,要做到動(dòng)態(tài)的形式,不可以用繼承實(shí)現(xiàn)绣檬,因?yàn)槔^承是靜態(tài)的足陨,裝飾器是原來(lái)的類還能用
//創(chuàng)建形狀接口
interface shape {
name(): string;
draw(): void;
}
//創(chuàng)建圓類
class circle implements shape {
name(): string {
return "circle";
}
draw(): void {
console.log("draw a circle.");
}
}
//創(chuàng)建裝飾器類
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 + "."
);
}
}
//測(cè)試
let testCircle = new circle();
let decoratorCircle = new decorator(testCircle);
decoratorCircle.draw();
decoratorCircle.setBorder("red");
//結(jié)果
//draw a circle.
//the border of circle has been set in red.
2.2.3 代理模式 ★
代理模式是為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn),也就是創(chuàng)建類的代理類娇未,間接訪問(wèn)被代理類的過(guò)程中墨缘,對(duì)其功能加以控制
let star = {
name: "zs",
age: 18,
};
let proxy = new Proxy(star, {
get(targetObj, propoty, receiver) {
//receiver是代理對(duì)象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 "身高只能是數(shù)字類型的值";
}
}
},
has(targetobj, property) {
return Reflect.has(...arguments);
},
deleteProperty(targetobj, property) {
if (property === "name") {
return false;
} else {
return Reflect.deleteProperty(...arguments);
}
},
});
//測(cè)試
console.log(proxy.name);
proxy.height = 180;
console.log(proxy.height);
console.log("age" in proxy);
delete proxy.name;
console.log(proxy.name);
//結(jié)果
//zs
//190cm
//true
//zs
2.2.4 外觀模式 ★
外觀模式提供了一個(gè)統(tǒng)一的接口,用來(lái)訪問(wèn)子系統(tǒng)中的一群接口零抬,它定義了一個(gè)高層接口镊讼,讓子系統(tǒng)更容易使用,主要是簡(jiǎn)化子系統(tǒng)的接口
//定義子類
interface buyCarStep {
getStep(): void;
}
class carShop implements buyCarStep {
public getStep(): void {
console.log("買車");
}
}
class DMV {
public getStep(): void {
console.log("發(fā)布牌照");
}
}
//定義外觀類
class helper {
private BMW: carShop = new carShop();
private HZDMV: DMV = new DMV();
public buyCar(): void {
this.BMW.getStep();
}
public getPlate(): void {
this.HZDMV.getStep();
}
}
//測(cè)試
let zs = new helper();
zs.buyCar();
zs.getPlate();
//結(jié)果
//買車
//發(fā)布牌照
2.2.5 橋接模式
橋接模式是將抽象部分與實(shí)現(xiàn)部分分離平夜,使它們都可以獨(dú)立的變化蝶棋。橋接模式就是把事物和其具體實(shí)現(xiàn)分開(kāi),使他們可以各自獨(dú)立的變化
//定義抽象cpu類
abstract class CPU {
public abstract work(gpu: GPU):void;
}
//定義CPU實(shí)體類
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;
}
//定義接口實(shí)現(xiàn)類
class NVIDAGPU implements GPU {
public with(): string{
return "RTX 3090TI";
}
}
class AMDGPU implements GPU {
public with():string {
return "RX 6950XT";
}
}
//測(cè)試
let cpu = new IntelCPU();
cpu.work(new (NVIDAGPU));
//結(jié)果
//Core I9 12900KF working withRTX 3090TI
2.2.6 組合模式 ★
組合模式是將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示"部分-整體"的層次結(jié)構(gòu)忽妒,組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性玩裙,簡(jiǎn)單講就是一個(gè)對(duì)象包含另一個(gè)對(duì)象
//定義抽象文件類
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("開(kāi)始播放" + this.getName());
}
}
class VideoFile extends AbstractFile {
constructor(name: string) {
super(name);
}
public open(): void {
console.log("開(kāi)始播放" + 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("打開(kāi)文件夾" + this.getName());
this.fileList.forEach((item) => {
item.open();
});
}
public getFile(index: number): AbstractFile {
return this.fileList[index];
}
}
//測(cè)試
let diskD = new Folder("D盤");
let musicFolder = new Folder("音樂(lè)");
let videoFolder = new Folder("視頻");
let musicOne = new MusicFile("逆戰(zhàn).mp3");
let musicTow = new MusicFile("孤勇者.mp3");
let videoOne = new VideoFile("戰(zhàn)狼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();
//結(jié)果
//打開(kāi)文件夾D盤
//打開(kāi)文件夾音樂(lè)
//開(kāi)始播放逆戰(zhàn).mp3
//開(kāi)始播放孤勇者.mp3
//打開(kāi)文件夾視頻
//開(kāi)始播放戰(zhàn)狼2.mp4
//開(kāi)始播放喜羊羊與灰太狼.avi
2.2.7 享元模式
享元模式是運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。享元模式的主要目的是實(shí)現(xiàn)對(duì)象的共享段直,即共享池吃溅,當(dāng)系統(tǒng)中對(duì)象多的時(shí)候可以減少內(nèi)存的開(kāi)銷,重用現(xiàn)有的同類對(duì)象鸯檬,若未找到匹配的對(duì)象决侈,則創(chuàng)建新對(duì)象,這樣可以減少對(duì)象的創(chuàng)建喧务,降低系統(tǒng)內(nèi)存赖歌,提高效率
//定義形狀接口
interface Shape{
draw():void;
}
//定義實(shí)現(xiàn)接口形狀類
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;
}
}
//測(cè)試
let factory = new ShapeFactory();
let redCircle = factory.getShape("red").draw();
let blueCircle = factory.getShape("blue").draw();
let anotherRedCircle = factory.getShape("red").draw();
//結(jié)果
//Create a red circle
//Draw a red circle
//Create a blue circle
//Draw a blue circle
//Draw a red circle
2.3 行為型模式
描述類或?qū)ο笾g如何協(xié)作完成任務(wù),包括 11 種:模板方法功茴、策略庐冯、命令、職責(zé)鏈痊土、狀態(tài)肄扎、觀察者、中介者赁酝、迭代器犯祠、訪問(wèn)者、備忘錄酌呆、解釋器
2.3.1 策略模式 ★
策略模式是針對(duì)一組算法衡载,將每一個(gè)算法封裝到具有共同接口的獨(dú)立的類中,從而使得它們可以相互替換
//定義策略
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.");
}
}
//定義持有策略的對(duì)象
class Context {
private strategy: Strategy;
constructor(strategy: Strategy) {
this.strategy = strategy;
}
public contextInterface() {
this.strategy.strategyInterface();
}
}
//測(cè)試
let context = new Context(new CarTravel());
let travelMethod = context.contextInterface();
//結(jié)果
//travel with car.
2.3.2 模版模式 ★
定義一個(gè)操作中的算法骨架隙袁,而將算法的一些步驟延遲到子類中痰娱,使得子類可以在不改變?cè)撍惴ńY(jié)構(gòu)的情況下重定義該算法的某些特定步驟
//定義抽象類
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;
}
//取號(hào)
public takeNumber(): void {
console.log("請(qǐng)拿好您的號(hào)碼" + this.number);
}
//排隊(duì)
public queue(): void {
console.log("請(qǐng)排隊(duì)");
}
//業(yè)務(wù)
public abstract work(): void;
//評(píng)分
public evaluation(): void {
console.log("請(qǐng)對(duì)我的服務(wù)評(píng)分" + 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("購(gòu)買" + this.amount + "元的基金");
}
}
//股票類
class Shares extends AbstractClass {
constructor(number: number, amount: number, score: number) {
super(number, amount, score);
}
public work(): void {
console.log("購(gòu)買" + this.amount + "元的股票");
}
}
//測(cè)試
let tom = new Fund(1, 20000, 80);
let jack = new Shares(2, 50000, 90);
tom.process();
jack.process();
//結(jié)果
//請(qǐng)拿好您的號(hào)碼1
//請(qǐng)排隊(duì)
//購(gòu)買20000元的基金
//請(qǐng)對(duì)我的服務(wù)評(píng)分80
//請(qǐng)拿好您的號(hào)碼2
//請(qǐng)排隊(duì)
//購(gòu)買50000元的股票
//請(qǐng)對(duì)我的服務(wù)評(píng)分90
2.3.3 觀察者模式 ★
又叫發(fā)布訂閱模式是定義對(duì)象間的一種一對(duì)多的依賴關(guān)系弃榨,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新
//定義被觀察者抽象類
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("成績(jī)發(fā)布了梨睁,成績(jī)?yōu)? + this.score);
this.notifyObserver(this.score);
}
}
//定義觀察接口
interface Observer {
changeCaptured(score: number): void;
}
//定義具體觀察者
class physics implements Observer {
changeCaptured(score: number): void {
console.log("捕獲到物理成績(jī)鲸睛,結(jié)果為" + score);
if (score < 60) {
console.log("物理不及格");
} else {
console.log("物理及格");
}
}
}
class math implements Observer {
changeCaptured(score: number): void {
console.log("捕獲到數(shù)學(xué)成績(jī),結(jié)果為" + score);
if (score < 90) {
console.log("數(shù)學(xué)不及格");
} else {
console.log("數(shù)學(xué)及格");
}
}
}
//測(cè)試
let finalExam = new examResult(88);
let physicsResult = new physics();
let mathResult = new math();
finalExam.addObserver(physicsResult);
finalExam.addObserver(mathResult);
finalExam.sendScore();
//結(jié)果
//成績(jī)發(fā)布了坡贺,結(jié)果為88
//捕獲到物理成績(jī)官辈,結(jié)果為88
//物理及格
//捕獲到數(shù)學(xué)成績(jī),結(jié)果為88
//數(shù)學(xué)不及格
2.3.4 迭代器模式 ★
迭代器模式是提供一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中各個(gè)元素, 而又無(wú)須暴露該對(duì)象的底層表示
在 JS 中一個(gè)數(shù)據(jù)類型如果有 Symbol.iterator 方法就代表改數(shù)據(jù)類型可以迭代遍坟,forof forin 實(shí)際上為調(diào)用該數(shù)據(jù)類型的 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;
}
}
//測(cè)試
let testContainer = new NameContainer(["張三", "李四", "王五", "趙六"]);
let testIterator = testContainer.getIterator();
while (!testIterator.isDone()) {
console.log(testIterator.currentItem());
testIterator.next();
}
//結(jié)果
//張三
//李四
//王五
//趙六
2.3.5 責(zé)任鏈模式
責(zé)任鏈模式是避免請(qǐng)求發(fā)送者與接收者耦合在一起拳亿,讓多個(gè)對(duì)象都有可能接收請(qǐng)求,將這些對(duì)象連接成一條鏈愿伴,并且沿著這條鏈傳遞請(qǐng)求肺魁,直到有對(duì)象處理它為止。有多個(gè)對(duì)象隔节,每個(gè)對(duì)象持有對(duì)下一個(gè)對(duì)象的引用鹅经,這樣就會(huì)形成一條鏈,請(qǐng)求在這條鏈上傳遞官帘,直到某一對(duì)象決定處理該請(qǐng)求瞬雹,比如事件冒泡
//定義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沒(méi)有綁定click事件");
}
if(this.nextDom) {
this.nextDom.click();
}
}
}
//定義具體實(shí)體類
class ChildDom extends Dom{
constructor(type: string){
super(type);
}
}
class ParentDom extends Dom{
constructor(type: string){
super(type);
}
}
//測(cè)試
let div = new ParentDom("div");
let span = new ChildDom("span");
div.addEventListener("click", "打開(kāi)彈窗");
span.setNextDom(div);
span.click();
//結(jié)果
//該dom沒(méi)有綁定click事件
//打開(kāi)彈窗
2.3.6 命令模式
命令模式是將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而使發(fā)出者可以用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化刽虹。模式當(dāng)中存在調(diào)用者、接收者呢诬、命令三個(gè)對(duì)象涌哲,實(shí)現(xiàn)請(qǐng)求和執(zhí)行分開(kāi);調(diào)用者選擇命令發(fā)布尚镰,命令指定接收者
//定義命令接口
interface Command {
execute():void;
}
//定義命令實(shí)現(xiàn)類
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("打開(kāi)電視");
}
public change():void{
console.log("更換頻道");
}
public close():void{
console.log("關(guān)閉電視");
}
}
//定于命令調(diào)用者遙控器
class Controller {
private commandList: Array<Command>;
constructor(commandList: Array<Command>) {
this.commandList = commandList;
}
public action():void{
this.commandList.forEach(item => {
item.execute();
})
}
}
//測(cè)試
let openCommand = new OpenCommand();
let changeCommand = new ChangeCommand();
let closeCommand = new CloseCommand();
let controller = new Controller([openCommand, changeCommand, closeCommand]);
controller.action();
//結(jié)果
//打開(kāi)電視
//更換頻道
//關(guān)閉電視
2.3.7 備忘錄模式
備忘錄模式是在不破壞封裝性的前提下阀圾,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)狗唉。創(chuàng)建一個(gè)備忘錄類初烘,用來(lái)存儲(chǔ)原始類的信息;同時(shí)創(chuàng)建備忘錄倉(cāng)庫(kù)類分俯,用來(lái)存儲(chǔ)備忘錄類肾筐,主要目的是保存一個(gè)對(duì)象的某個(gè)狀態(tài),以便在適當(dāng)?shù)臅r(shí)候恢復(fù)對(duì)象缸剪,也就是做個(gè)備份
//創(chuàng)建備忘錄發(fā)起對(duì)象
class Originator {
private state: string = "";
public getState():string {
return this.state;
}
public setState(state:string):void {
this.state = state;
}
// 創(chuàng)建一個(gè)備忘錄
public createMemento():Memento {
return new Memento(this.state);
}
// 從備忘錄恢復(fù)
public restoreMemento(memento: Memento):void {
this.setState(memento.getState());
}
}
//創(chuàng)建備忘錄對(duì)象
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;
}
}
//創(chuàng)建管理備忘錄對(duì)象
class Caretaker {
// 備忘錄對(duì)象
private memento: Memento;
constructor(memento: Memento) {
this.memento = memento;
}
public getMemento(): Memento {
return this.memento;
}
public storeMemento(memento: Memento): void {
this.memento = memento;
}
}
//測(cè)試
let originator = new Originator();
originator.setState("狀態(tài)1");
console.log(originator.getState());
let caretaker = new Caretaker(originator.createMemento());
originator.setState("狀態(tài)2");
console.log(originator.getState());
caretaker.storeMemento(originator.createMemento());
originator.setState("狀態(tài)3");
console.log(originator.getState());
originator.restoreMemento(caretaker.getMemento());
console.log(originator.getState());
//結(jié)果
//狀態(tài)1
//狀態(tài)2
//狀態(tài)3
//狀態(tài)2
2.3.8 狀態(tài)模式
狀態(tài)模式是允許對(duì)象在內(nèi)部狀態(tài)發(fā)生改變時(shí)改變它的行為吗铐。對(duì)象具有多種狀態(tài),且每種狀態(tài)具有特定的行為
//創(chuàng)建狀態(tài)抽象類
abstract class State{
public abstract handle(): void;
}
//創(chuàng)建具體狀態(tài)類
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!");
}
}
//創(chuàng)建環(huán)境類
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();
}
}
//測(cè)試
let context = new Content(new PlayerOnline());
context.require();
context.setState(new PlayerOffline());
context.require();
//結(jié)果
//Player is online, can play games!
//Player is offline, can't play games!
2.3.9 訪問(wèn)者模式 ★
訪問(wèn)者模式主要是將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離杏节。在被訪問(wèn)的類里面加一個(gè)對(duì)外提供接待訪問(wèn)者的接口唬渗,訪問(wèn)者封裝了對(duì)被訪問(wèn)者結(jié)構(gòu)的一些雜亂操作典阵,解耦結(jié)構(gòu)與算法,同時(shí)具有優(yōu)秀的擴(kuò)展性镊逝。通俗來(lái)講就是一種分離對(duì)象數(shù)據(jù)結(jié)構(gòu)與行為的方法
//定義抽象硬件類
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!");
}
}
//定義訪問(wèn)者接口
interface Visitor {
visitCPU(cpu: CPU): void;
visitGPU(gpu: GPU): void;
visitSSD(ssd: SSD): void;
}
//定義訪問(wèn)者實(shí)現(xiàn)類
class GTA5 implements Visitor {
visitCPU(cpu: CPU): void {
cpu.run();
}
visitGPU(gpu: GPU): void {
gpu.run();
}
visitSSD(ssd: SSD): void {
ssd.run();
}
}
//定義結(jié)構(gòu)類
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);
}
}
//測(cè)試
let computer = new Computer(
"Intel Core I9 12900KF",
"NVIDA GEFORCE RTX 3090TI",
"SAMSUNG 980 PRO 2TB"
);
computer.runSoftWare(new GTA5());
//結(jié)果
//CPU Intel Core I9 12900KF is running!
//GPU NVIDA GEFORCE RTX 3090TI is running!
//SSD SAMSUNG 980 PRO 2TB is running!
2.3.10 中介者模式 ★
中介者模式是用一個(gè)中介對(duì)象來(lái)封裝一系列的對(duì)象交互壮啊,中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散撑蒜,而且可以獨(dú)立地改變它們之間的交互
//定義中介類聊天室
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);
}
}
//測(cè)試
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.");
//結(jié)果
//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 解釋器模式
解釋器模式是給定一個(gè)語(yǔ)言他巨,定義它的文法表示,并定義一個(gè)解釋器减江,這個(gè)解釋器使用該標(biāo)識(shí)來(lái)解釋語(yǔ)言中的句子染突,基本也就用在這個(gè)范圍內(nèi),適用面較窄辈灼,例如:正則表達(dá)式的解釋等
//創(chuàng)建表達(dá)式接口
interface Expression{
interpreter(): boolean;
}
//創(chuàng)建表達(dá)式實(shí)現(xiàn)類
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();
}
}
//測(cè)試
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);
//結(jié)果
//false