js 常用12种设计模式

  1. 工厂模式
    <!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>
  2. 单例模式
    <!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>

  3. 观察者模式
    <!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>

  4. 发布订阅模式
    <!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>

  5. 原型模式
    <!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>

  6. 适配器模式
    <!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>

  7. 装饰者模式
    <!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>

  8. 策略模式
    <!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>

  9. 模块模式
    <!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>

  10. 代理模式
    <!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>

  11. 迭代器模式
    <!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>

  12. 状态模式
    <!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>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值