在大三上学期,学校开设了软件设计模式这门课程(学位课),可惜当时并没有重视这门课程,一直视为水课,但是学得越深入(前端方向),才发现软件设计模式这么重要,好像写代码就离不开软件设计模式,它决定了你要怎样设计你的代码,将所有串联起来,同样也涉及到了很多得代码优化,优化结构,增加代码得可读性和结构性,如果你和当时的我一样还没有搞懂什么时软件设计模式,希望从此刻开始,通过这篇文章,能够加深你对软件设计模式的理解。此致,敬礼!
/* 单例模式是一种常见的设计模式,其目的是确保一个类只有一个实例,并提供全局访问点。
单例模式的目的是限制某个类的实例化次数,确保整个应用中只存在一个实例(如vuex和redux中的store) */
var Singleton = (function(){
var instance;//存储单例实例
function init(){
//私有变量和方法
var privateVariable = 'I am private';
function privateMethod(){
console.log('This is a private method');
}
return {
// 共有变量和方法
publicVariable :'I am public',
publicMethod: function(){
console.log('This is a public method');
},
getPrivateVariable:function(){
return {privateVariable,privateMethod}
},
};
}
return {
//获取单例实例方法
getInstance:function(){
if(!instance){
instance = init();
}
return instance;
},
};
})();
//获取单例实例
var mySingleton = Singleton.getInstance();
class Singleton{
static instance;//存储单例实例
constructor(){}
//获取单例实例方法
static getInstance(){
if(!Singleton.instance){
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
//获取单例实例
var mySingleton1 = Singleton.getInstance();
var mySingleton2 = Singleton.getInstance();
console.log(mySingleton1 === mySingleton2);
/* 工厂模式是一种创建对象的设计模式,它提供了一种封装对象创建过程的方式,使得代码无需关心具体的实例化过程,
提高代码的灵活性和可维护性。在实际应用中,工厂模式经常用于对象的创建和封装逻辑 */
//例如Vue中的虚拟DOM和vue-router创建模式(hash模式和history模式)
class Car{
constructor(type,model){
this.type = type
this.model = model
}
}
class CarFactory{
createCar(type,model){
return new Car(type,model)
}
}
const factory = new CarFactory();
const myCar = factory.createCar('SUV','MODEL')
/* 构造函数模式是一种创建对象的方式,它使用构造函数来实例化对象,并使用new关键字调用构造函数
构造函数模式允许创建具有相似属性和方法的多个对象 */
//构造函数
function Animal(name,species){
this.name = name
this.species = species
this.eat = function(){
console.log('eating');
}
}
const cat = new Animal('Tom','Cat')
const dog = new Animal('Pluto','Dog');
/* 原型模式是一种创建对象的设计模式,它通过使用原型对象作为对象的模板,允许通过原型链共享属性和方法
JS中,每个对象都有一个指向其原型的链接,通过整个链接,对象可以继承原型的属性和方法。原型模式的优势
在于可以实现属性和方法的共享,节省内存,并且可以在运行时动态地添加或修改原型上的方法和属性,这使得原型模式
成为JS中实现继承地基础 */
function Animal(name,species){
this.name = name
this.species = species
}
Animal.prototype.eat = function(){
console.log('eating');
}
const cat = new Animal('Tom','Cat')
const dog = new Animal('Pluto','Dog')
// 模块模式是一种封装和组织JS代码地设计模式,它使用闭包来创建私有作用域,从而实现信息隐藏和模块化
var MyModule = (function () {
//私有变量和方法
var privateVariable = 'I am private';
function privateMethod() {
console.log('This is a private method');
}
return {
// 共有变量和方法
publicVariable: 'I am public',
publicMethod: function () {
console.log('This is a public method');
},
getPrivateVariable: function () {
return { privateVariable, privateMethod }
},
};
})();
class ComputerBuilder{
constructor(){
this.computer = {}
}
addCPU(cpu){
this.computer.cpu = cpu;
return this //返回构造器实例,以支持链式调用
}
addRAM(ram){
this.computer.ram = ram
return this
}
addStorage(storage){
this.computer.storage = storage
return this
}
build(){
return this.computer
}
}
//使用构造器创建对象
const myComputer = new ComputerBuilder().addCPU('Intel i7').addRAM('16GB').addStorage('512GB SSD').build()
/* 装饰器模式允许通过将对象包在装饰器类的实例中来动态地扩展对象地行为
在JS中,装饰器模式通常使用函数或类来实现 */
class Car{
drive(){
console.log('Driving the car');
}
}
//装饰器类 - 加速装置
class TurboDecorator{
constructor(car){
this.car = car
}
drive(){
this.car.drive()
console.log('Turbo boost activated!');
}
}
//装饰器类 - 音响系统
class StereDecorator{
constructor(car){
this.car = car
}
drive(){
this.car.drive()
console.log('Enjoying music with the stereo system');
}
}
//创建基础汽车对象
const basicCar = new Car()
//使用装饰器扩展对象
const turboCar = new TurboDecorator(basicCar)
const luxuryCar = new StereDecorator(turboCar)
//调用装饰后地汽车对象的方法
luxuryCar.drive()
console.log(luxuryCar);
/* 外观模式提供一个简化的接口,用于访问一个或多个复杂子系统,通过隐藏系统的复杂性,提供一个更简单和一致的接口
使客户端更容易使用,目标是简化接口,隐藏复杂性 */
//子系统 - 播放器
class Player{
play(){
console.log('Playing music');
}
stop(){
console.log('Stopping music');
}
}
//子系统 - 音响
class Stereo{
turnOn(){
console.log('Turning on the stereo');
}
turnOff(){
console.log('Turning off the stereo');
}
}
//外观类 - 音响系统外观
class AudioSystemFacade{
constructor(){
this.player = new Player();
this.stereo = new Stereo();
}
playMusic(){
this.stereo.turnOn();
this.player.play();
}
stopMusic(){
this.player.stop();
this.stereo.turnOff();
}
}
//使用外观模式 简化接口
const audioFacade = new AudioSystemFacade();
audioFacade.playMusic();
audioFacade.stopMusic();
// 设配器模式允许接口不兼容的对象之间进行合作,适配器模式通过创建一个包装对象(适配器),使得原本不兼容的接口变得兼容
//例如vue中的计算属性
//Axios 的用来发送请求的 adapter 本质上是封装浏览器提供的 API XMLHttpRequest。
//旧的计算器对象
class OldCalculator{
getTotal(){
return 100;
}
}
//新的系统期望的接口
class NewCalculator{
calculate(){
return 200;
}
}
//设配器类
class CalculatorAdapter{
constructor(oldCalculator) {
this.oldCalculator = oldCalculator
}
//适配方法
calculate(){
return this.oldCalculator.getTotal()
}
}
//使用设配器链接新旧系统
const oldCalculator = new OldCalculator();
const adapter = new CalculatorAdapter(oldCalculator);
console.log('Total using adapter:' , adapter.calculate());//100
// 桥接模式将一个抽象部分与具体实现部分分离,使他们可以独立化,这种模式通过使用组合而不是继承,来将抽象和实现解耦
//通过桥接模式,我们可以独立的改变颜色和形状,而不必修改彼此之间的继承关系
//颜色实现类
class RedColor{
applyColor(){
console.log('Applying red color');
}
}
class BlueColor{
applyColor(){
console.log('Applying blue color');
}
}
//形状抽象类
class Shape{
constructor(color){
this.color = color
}
applyColor(){
this.color.applyColor();
}
draw(){
//具体的形状绘制逻辑
}
}
//具体形状类
class Circle extends Shape{
draw(){
console.log('Drawing circle');
}
}
class Square extends Shape{
draw(){
console.log('Drawing square');
}
}
//使用桥接模式链接形状和颜色
const redCircle = new Circle(new RedColor());
const blueSquare = new Square(new BlueColor());
//调用具体形状的方法,委托给颜色实现类
redCircle.draw();//Drawing circle
redCircle.applyColor();//Applying red color
// 组合模式将对象组合成树形结构以表示"部分-整体"的层次结构
//抽象图形类
class Graphic{
draw(){
//抽象方法,由具体子类实现
}
}
//具体图形类 - 圆形
class Circle extends Graphic{
constructor(name){
super()
this.name = name
}
draw(){
console.log(`Drawing Circle : ${this.name}`);
}
}
//具体图形类 - 矩形
class Rectangle extends Graphic{
constructor(name){
super()
this.name = name
}
draw(){
console.log(`Drawing Rectangle : ${this.name}`);
}
}
//复合图形类
class CompositeGraphic extends Graphic {
constructor(name){
super();
this.name = name
this.graphics = []
}
add(graphic){
this.graphics.push(graphic)
}
draw(){
console.log('Drawing Composite: ${this.name}');
this.graphics.forEach((graphic)=>{
graphic.draw()
})
}
}
//使用组合模式创建图形结构
const circle1 = new Circle('Circle 1');
const circle2 = new Circle('Circle 2');
const rectangle = new Rectangle('Rectangle 1');
const composite = new CompositeGraphic('Composite 1')
composite.add(circle1)
composite.add(rectangle)
const rootComposite = new CompositeGraphic('Root Composite')
rootComposite.add(composite)
rootComposite.add(rectangle)
rootComposite.draw()
// 观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新
// 在JS中观察者模式通常使用回调函数或事件机制来实现,通过此模式我们可以实现对象之间的松耦合。
//主题类,负责维护观察者列表,并提供添加、移除和通知观察者的方法
class Subject{
constructor(){
this.observers = []
}
//添加观察者
addObserver(observer){
this.observers.push(observer)
}
//移除观察者
removeObserver(observer){
this.observers = this.observers.filter((o) => o !== observer)
}
//通知所有观察者
notify(){
this.observers.forEach((observer) =>{
observer.update();
})
}
}
//观察者类,具有一个update方法,用于在收到通知时执行相应的操作
class observer{
constructor(name){
this.nam = name
}
//更新方法
update(){
console.log(`${this.name} has been notified and updated`);
}
}
//创建主题和观察者
const subject = new Subject()
const observer1 = new observer('Observer 1');
const observer2 = new observer('Observer 2');
//添加观察者到主题
subject.addObserver(observer1)
subject.addObserver(observer2)
//通知所有观察者
subject.notify();
/* 策略模式定义了一系列的算法,将每个算法封装起来,并使他们可以互相替换
此模式使得算法的变化独立于使用算法的客户端。通过此模式,客户端可以在运行时选择
不同的支付策略,而不必修改客户端代码 */
// 例如ElementUI中的表单验证
//支付策略接口
class PaymentStrategy{
pay(amount){
//策略接口
}
}
//具体支付策略 - 支付宝
class AlipayStrategy extends PaymentStrategy{
pay(amount){
console.log(`Paid ${amount} using Alipay`);
}
}
//具体支付策略 - 微信支付
class WeChatStrategy extends PaymentStrategy{
pay(amount){
console.log(`Paid ${amount} using WeChat`);
}
}
//上下文类,负责接收并执行具体的支付策略
class PaymentContext{
constructor(strategy){
this.strategy = strategy
}
//设置支付策略
setPaymentStrategy(strategy){
this.strategy = strategy
}
//执行支付策略
executePayment(amount){
this.strategy.pay(amount)
}
}
//使用策略模式
const paymentContext = new PaymentContext(new AlipayStrategy());
paymentContext.executePayment(1000)
//切换策略模式
paymentContext.setPaymentStrategy(new WeChatStrategy());
paymentContext.executePayment(800)
/* 命令模式将请求封装成一个对象,从而允许不同的请求参数化客户端队列,请求可进行排队、请求可被取消
以及支持可撤销的操作 */
//命令接口
class Command{
execute(){
//命令接口,具体命令类需要实现该方法
}
}
//具体命令类 - 打开电视
class TurnOnTVcommand extends Command{
constructor(tv){
super()
this.tv = tv
}
execute(){
this.tv.turnOn();
}
}
//具体命令类 - 关闭电视
class TurnOffCommand extends Command{
constructor(tv){
super()
this.tv = tv
}
execute(){
this.turnOff();
}
}
//接收者类 - 电视
class TV{
turnOn(){
console.log('TV is turned on');
}
turnOff(){
console.log('TV is turned off');
}
}
//调用者类 - 遥控器
class RemoteControl{
constructor(){
this.command = null;
}
setCommand(command){
this.command = command
}
pressButton(){
this.command.execute()
}
}
//使用命令模式
const TV = new TV();
const turnOnCommand = new TurnOnTVcommand();
const turnOnTVcommand = new TurnOffCommand();
const remoteControl = new RemoteControl();
//配置遥控器按钮
remoteControl.setCommand(turnOnCommand);
remoteControl.pressButton();
// 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露该对象的内部表示
//自定义迭代器对象
class ArrayIterator{
constructor(array){
this.array = array
this.index = 0
}
hasNext(){
return this.index < this.array.length
}
next(){
return this.hasNext()? this.array[this.index ++] : null
}
}
//使用迭代器模拟遍历数组
const array = [1,2,3,4,5,6]
const iterator = new ArrayIterator(arr);
while(iterator.hasNext()){
console.log(iterator.next());//1 2 3 4 5 6
}
//调节器模式(中介者模式)定义了一个对象,该对象封装了一组对象间的交互方式 中介者使对象之间不能直接相互通信
//而是通过中介者对象进行通信,从而降低了对象之间的耦合度
//聊天室类
class ChatMediator{
constructor(){
this.users = []
}
addUser(user){
this.users.push(user)
}
sendMessage(message,sender){
this.users.forEach((user)=>{
if(user !== sender){
user.receiveMessage(message)
}
})
}
}
//用户类
class User{
constructor(name,mediator){
this.name = name
this.mediator = mediator
}
sendMessage(message){
console.log(`${this.name} sending message :${message}`);
this.mediator.sendMessage(message,this)
}
receiveMessage(message){
console.log(`${this.name} receive message: ${message}` );
}
}
//使用中介者模式
const mediator = new ChatMediator();
const user1 = new User('user 1',mediator)
const user2 = new User('user 2',mediator)
const user3 = new User('user 3',mediator)
mediator.addUser(user1)
mediator.addUser(user2)
mediator.addUser(user3)
user1.sendMessage('Hello everyOne')
user2.sendMessage('I am ADong')
//发布订阅模式 其实是一种对象间一对多的依赖关系,
//当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
//(如微信公众号一样有无数个订阅者,有一个发布者,当发布者发布文章的时候,订阅者都可以收到发布的文章。)
//例如vue2中的EventBus , vue3已经放弃
class Event{
constructor(){
//创建一个对象存储方法
this.eventList = {};
}
//绑定方法
on(name,fn){
if(typeof fn !== 'function') return
let eventList = this.eventList;
if(!eventList[name]) eventList[name] = [];
eventList[name].push(fn)
}
//触发事件
emit(name,...res){
const eventList = this.eventList[name];
if(!eventList || eventList.length === 0) return ;
eventList.forEach(fn => {
fn(...res)
})
}
//解绑事件
remove(name,fn){
if(typeof fn !== 'function') return ;
let eventList = this.eventList[name];
if(!eventList || eventList.length === 0) return ;
eventList = eventList.filters( f => f !== fn)
}
}
//使用发布订阅模式
function fn1(args){
console.log(args);
}
function fn2(args){
console.log(args);
}
const e = new Event();
e.on('test1',fn1);
e.on('test2',fn2);
e.emit('test1',111);//111
e.emit('test2',2222);//222