- 工厂模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>01-工厂模式</title> </head> <body> <div> <h2>原理</h2> <span>工厂模式通过使用工厂方法来创建对象,而不是直接使用new关键字。工厂方法根据输入参数的不同,决定创建哪个具体的对象实例,并将其返回。</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要创建多个相似的对象时</li> <li>当对象创建过程复杂或需要隐藏创建逻辑时</li> <li>当希望通过一个公共的接口来创建对象时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>将对象的创建与使用代码分离,客户端只需关注接口而不需要关心具体的对象创建过程</li> <li>可以通过工厂方法来创建不同类型的对象,提供灵活性和可扩展性</li> </ul> </div> <script> // 定义一个产品类 class Product { constructor(name) { this.name = name; } display() { console.log(`Product: ${this.name}`); } } // 定义工厂类 class Factory { createProduct(name) { return new Product(name); } } // 使用工厂创建对象 const factory = new Factory(); const product1 = factory.createProduct('Product 1'); const product2 = factory.createProduct('Product 2'); product1.display(); product2.display(); </script> </body> </html>
- 单例模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>02-单例模式</title> </head> <body> <div> <h2>原理</h2> <span>单例模式确保一个类只有一个实例,并提供全局访问点以获取该实例。它通过私有化构造函数,限制外部直接创建对象,并体用一个静态方法来获取或创建唯一的实例</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要一个全局对象来协调系统中的操作时</li> <li>当需要频繁访问同一个对象实例时</li> <li>当需要限制一个类只能有一个实例时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>提供了对唯一实例的全局访问,方便共享对象</li> <li>避免了重复创建实例的开销,节省了内存和资源</li> </ul> </div> <script> class Singleton { static instance = null; constructor () { if(Singleton.instance){ return Singleton.instance; } Singleton.instance = this; } } // 获取实例 const instance1 = new Singleton(); const instance2 = new Singleton(); console.log(instance1 === instance2); </script> </body> </html>
- 观察者模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>03-观察者模式</title> </head> <body> <div> <h2>原理:</h2> <span>观察者模式定义了对象之间一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖者(观察者)都会被通知更新</span> </div> <div> <h2>使用场景</h2> <ul> <li>当一个对象的变化需要通知其它对象,以便它们可以做出相应的响应时。</li> <li>当对象之间的耦合度需要降低,使得它们之间可以独立的交互时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>实现了对象之间的松耦合,被观察者和观察者可以独立的演化和变化</li> <li>可以轻松添加或移除观察者,以实现动态的发布-订阅机制</li> </ul> </div> <script> class Subject { constructor(){ this.observers = []; } addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notifyObservers() { this.observers.forEach(observer => observer.update()); } } class Observer { constructor(name) { this.name = name; } update () { console.log(`Observer ${this.name} has been notified.`); } } // 创建主题和观察者 const subject = new Subject(); const observer1 = new Observer('1'); const observer2 = new Observer('2'); // 注册观察者 subject.addObserver(observer1); subject.addObserver(observer2); // 通知观察者 subject.notifyObservers(); </script> </body> </html>
- 发布订阅模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>04-发布订阅模式</title> </head> <body> <div> <h2>原理</h2> <span>发布-订阅模式类似于观察者模式,但是发布者(或称为主题)不会直接通知特定的订阅者,而是通过消息代理(或称为事件总线)来分发和传递消息。订阅者可以根据自身的需求订阅感兴趣的消息</span> </div> <div> <h2>使用场景</h2> <ul> <li>当一个对象的状态变化需要通知多个订阅者时</li> <li>当需要将发布者和订阅者解耦,使他们可以独立的演化时</li> <li>当希望在系统中引入中介层以提供更灵活的消息传递机制时</li> </ul> </div> <div> <h2>有点</h2> <ul> <li>解耦了发布者和订阅者,使他们可以独立的交互</li> <li>提供了更灵活的消息传递机制,可以实现更复杂的事件处理逻辑</li> </ul> </div> <script> /** 原理:**/ class EventBus { constructor() { this.subscribers = {}; } subscribe(eventName, callback) { if(!this.subscribers[eventName]) { this.subscribers[eventName] = []; } this.subscribers[eventName].push(callback); } unsubscribe(eventName, callback){ if(this.subscribers[eventName]){ this.subscribers[eventName] = this.subscribers[eventName].filter((cb) => cb!== callback); } } publish(eventName, data) { if(this.subscribers[eventName]){ this.subscribers[eventName].forEach(callback => callback(data)); } } } // 创建事件总线 const eventBus = new EventBus(); // 订阅事件 const callback1 = (data) => console.log(`Subscriber 1 received: ${data}`); const callback2 = (data) => console.log(`Subscriber 2 received: ${data}`); eventBus.subscribe('event1', callback1); eventBus.subscribe('event2', callback2); // 发布事件 eventBus.publish('event1', 'Hello subscribers 1!'); eventBus.publish('event2', 'Hello subscribers 2!'); </script> </body> </html>
- 原型模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>05-原型模式</title> </head> <body> <div> <h2>原理</h2> <span>原型模式通过克隆现有对象来创建新对象,而不是依赖显式的实例化过程。每一个对象都可以作为另一个对象的原型,新对象会继承原型对象的属性和方法</span> </div> <div> <h2>使用场景</h2> <ul> <li>当创建对象的过程比较昂贵或复杂时,而且新对象的创建与现有对象的状态无关时</li> <li>当希望通过修改原型对象来影响所有克隆对象时</li> <li>当需要避免使用new关键字直接实例化对象时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>避免了创建对象的昂贵或复杂过程,提高了性能和效率</li> <li>可以通过修改原型对象来影响所有克隆对象,实现了对象状态的批量修改</li> </ul> </div> <script> class Prototype { constructor(name) { this.name = name; } clone () { return Object.create(Object.getPrototypeOf(this)); } } // 创建原型对象 const prototype = new Prototype('Prototype'); // 克隆对象 const clone1 = prototype.clone(); const clone2 = prototype.clone(); console.log(clone1.name); console.log(clone2.name); </script> </body> </html>
- 适配器模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>06-适配器模式</title> </head> <body> <div> <h2>原理</h2> <span>适配器模式将一个类的接口转换成另一个接口,以满足客户端的需求。它通过创建一个适配器类来实现接口转换,并在适配器类中调用被适配类的方法。</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要将一个已有类的接口转换成另一个接口时</li> <li>当希望通过一个统一的接口来使用多个不兼容的类时</li> <li>当需要在不影响现有代码的情况下,对已有类的方法进行扩展或修改时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>可以将已有类与新代码进行无缝衔接,使它们能够协同工作</li> <li>可以实现对象之间的接口转换,提供了灵活性和可扩展性</li> </ul> </div> <script> class Adaptee { specificRequest(){ return 'Specific request'; } } class Adapter { constructor (adaptee) { this.adaptee = adaptee; } request () { return this.adaptee.specificRequest(); } } // 使用适配器 const adaptee = new Adaptee(); const adapter = new Adapter(adaptee); console.log(adapter.request()); </script> </body> </html>
- 装饰者模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>07-装饰者模式</title> </head> <body> <div> <h2>原理</h2> <span>装饰者模式动态的给对象添加新的行为或功能,同时不改变其原始类结构。它通过创建一个装饰器类来包装原始对象,并在装饰器类中添加额外的行为</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要在不改变现有对象结构的情况下,动态地给对下个你添加新的行为时</li> <li>当希望通过透明的方式为对象添加功能,而不影响其使用方式和客户端代码时</li> <li>当不适合使用子类来扩展对象功能时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>可以透明的扩展对象的功能,而不会影响客户端代码</li> <li>允许通装饰器类组合和嵌套多个装饰器,实现复杂的功能组合</li> </ul> </div> <script> class Component { operation () { return `Component operation`; } } class Decorator { constructor(component) { this.component = component; } operation () { return `${this.component.operation()} + Decorator operation`; } } // 使用装饰者 const component = new Component(); const decorator = new Decorator(component); console.log(decorator.operation()); </script> </body> </html>
- 策略模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>08-策略模式</title> </head> <body> <div> <h2>原理</h2> <span>策略模式定义了一系列算法,将他们封装成独立的可互换的策略对象,并使得客户端可以在运行时动态的选择使用不同的策略。客户端通过与策略对下个你进行交互来实现不同的行为</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要在多个算法或行为之间进行动态选择时</li> <li>当希望将算法的实现与使用它的客户端代码分离,以便它们可以独立的演化和修改时</li> <li>当不希望使用大量的条件语句来处理不同的情况时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>实现了算法的封装和多态性,可以根据需要灵活的切换算法</li> <li>将算法的实现与使用它的客户端代码分离,使得他们可以独立演化和修改</li> </ul> </div> <script> class Strategy { execute() { // 策略执行的具体操作 } } class ConcreteStrategy1 extends Strategy { execute() { console.log('Strategy 1'); } } class ConcreteStrategy2 extends Strategy { execute () { console.log('Strategy 2'); } } // 使用策略 const strategy1 = new ConcreteStrategy1(); const strategy2 = new ConcreteStrategy2(); strategy1.execute(); strategy2.execute(); </script> </body> </html>
- 模块模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>09-模块模式</title> </head> <body> <div> <h2>原理</h2> <span>模块模式使用函数作用域和闭包来封装和组织代码,实现模块化和私有性。它通过返回一个包含公共方法和属性的对象,类来实现对外部的封装</span> </div> <div> <h2>使用场景</h2> <ul> <li>当希望将相关的方法和属性封装在一个单独的对象中时</li> <li>当希望限制对方法和属性的访问,并保持私有性时</li> <li>当需要实现模块化,避免全局命名冲突和污染时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>将相关的方法和属性封装在一个单独的对象中,提供了组织和管理代码的方式</li> <li>通过闭包实现了私有性,可以隐藏内部的实现细节,防止外部访问和修改</li> </ul> </div> <script> const module = (function () { let privateVariable = 'Private'; function privateMethod() { console.log('Private method'); } return { publicVariable: 'Public', publicMethod: function () { console.log('Public method'); } } })(); console.log(module.publicVariable); module.publicMethod(); </script> </body> </html>
- 代理模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>10-代理模式</title> </head> <body> <div> <h2>原理</h2> <span>代理模式为一个对象提供一个代理或占位符,并控制对其的访问。代理对象可以在访问被代理对象之前或之后添加额外的逻辑,如延迟加载、权限控制、缓存等</span> </div> <div> <h2>使用场景</h2> <ul> <li>当需要在访问对象之前或之后执行额外的操作时</li> <li>当希望通过代理控制对对象的访问权限时</li> <li>当需要延迟加载对象或实现缓存等功能时</li> </ul> </div> <div> <h2>优点</h2> <ul> <li>可以在访问对象之前或之后执行额外的操作,如延迟加载、权限控制、缓存等</li> <li>提供了对真实对象的访问控制,可以限制对对象的直接访问</li> </ul> </div> <script> class RealSubject { request() { console.log('Real subject request'); } } class Proxy { constructor(realSubject){ this.realSubject = realSubject; } request() { // 在调用真实对象方法之前或之后执行额外操作 console.log('Proxy request'); this.realSubject.request(); } } // 使用代理 const realSubject = new RealSubject(); const proxy = new Proxy(realSubject); proxy.request(); </script> </body> </html>
- 迭代器模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>11-迭代器模式</title> </head> <body> <div> <h2>原理</h2> <span>迭代器模式提供了一种访问集合对象元素的方式,而无需暴露集合的内部结构。它将迭代逻辑封装在迭代器对象中,客户端通过迭代器来遍历集合</span> </div> <div> <h2>使用场景</h2> <ul> <li> 当集合对象的内部结构可能经常变化时,使用迭代器可以减少对客户端代码的影响 </li> <li> 当需要对集合对下个你进行不同类型的遍历时,迭代器提供了统一的接口,使得遍历逻辑更加灵活和可扩展 </li> <li> 当需要在遍历过程中对集合元素进行筛选、过滤或转换时,可以通过迭代器来实现 </li> </ul> </div> <div> <h2>优点</h2> <ul> <li>将遍历集合的责任从客户端代码中抽离出来,简化了客户端代码</li> <li>隐藏了集合的内部结构,提供了更好的封装性和安全性</li> <li>支持不同类型的集合,提供了统一的迭代接口</li> </ul> </div> <script> // 定义集合对象 class Collection { constructor () { this.items = []; } addItem(item) { this.items.push(item); } getIterator(){ return new Iterator(this.items); } } // 定义迭代器对象 class Iterator { constructor (collection) { this.collection = collection; this.index = 0; } hasNext(){ return this.index < this.collection.length; } next () { return this.collection[this.index++]; } } // 使用迭代器遍历集合 const collection = new Collection(); collection.addItem('Item 1'); collection.addItem('Item 2'); collection.addItem('Item 3'); const iterator = collection.getIterator(); while (iterator.hasNext()) { console.log(iterator.next()); } </script> </body> </html>
- 状态模式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>12-状态模式</title> </head> <body> <div> <h2>原理</h2> <span>状态模式允许对象在内部状态发生改变时改变其行为,看起来就像是对象类发生了改变。它将每个状态封装在一个独立的类中,并允许对象在不同状态之间切换。</span> </div> <div> <h2>使用场景</h2> <ul> <li> 当一个对象的行为取决于其内部状态,并在不同状态下具有不同行为时,可以使用状态模式来管理状态转换和行为。 </li> <li> 当需要在运行时根据条件动态的改变对象的行为时,状态模式提供了一种优雅的方式来实现 </li> <li> 当对象有大量的条件语句,而且随着状态的增加会变得更加复杂时,可以使用状态模式来简化代码结构 </li> </ul> </div> <div> <h2>优点</h2> <ul> <li> 将对象的状态和行为封装在独立的类中,提高了代码的可读性和可维护性 </li> <li> 避免了使用大量的条件语句来处理不同的状态,简化了代码结构 </li> <li> 新增或修改状态变得更加容易,不会对其他状态产生影响 </li> </ul> </div> <script> // 定义状态接口 class State { handle (context) { // 默认实现 } } // 定义具体状态类 class ConcreteStateA extends State { handle(content) { console.log('State A'); context.setState(new ConcreteStateB()); } } class ConcreteStateB extends State { handle(context) { console.log('State B'); context.setState(new ConcreteStateA()); } } // 定义上下文类 class Context { constructor(){ this.state = new ConcreteStateA(); } setState(state){ this.state = state; } request() { this.state.handle(this); } } // 使用状态模式 const context = new Context(); context.request(); context.request(); context.request(); </script> </body> </html>
js 常用12种设计模式
于 2023-07-08 15:16:32 首次发布