JavaScript设计模式详解

JavaScript设计模式是解决软件设计中常见问题的可重复使用的解决方案。本博客将深入探讨JavaScript设计模式的各个方面,包括设计模式的类别、创建型、结构型、行为型、并发型和架构型设计模式。

设计模式概述

什么是设计模式?

设计模式是一种在软件设计中解决常见问题的可重用解决方案。它们是经过验证的、通用的设计思想,提供了一种解决软件设计中反复出现问题的方法。设计模式不是可直接转化成代码的具体算法,而是关于如何解决某一类问题的指导性方案。

设计模式的好处包括提高代码的可重用性、可维护性、可扩展性,同时也有助于降低代码的复杂性。

设计模式的分类

设计模式可以分为不同的类别,主要包括:

1. Proto-patterns(原型模式)和 Anti-patterns(反模式):  这些是在设计模式被广泛接受之前的阶段。Proto-patterns 是被开发者社区认可并广泛使用的设计模式,而 Anti-patterns 代表不良实践。

2. 创建型设计模式(Creational Design Patterns):  处理对象的创建机制,优化对象的创建过程。包括工厂方法、抽象工厂、建造者、原型和单例等。

3. 结构型设计模式(Structural Design Patterns):  处理对象之间的关系,确保系统的一部分变化时,整个系统不需要随之改变。包括适配器、桥接、组合、装饰者、外观、享元和代理等。

4. 行为型设计模式(Behavioral Design Patterns):  识别、实施和改进系统中不同对象之间的通信。确保系统的不同部分具有同步的信息。包括责任链、命令、迭代器、中介者、备忘录、观察者、状态、策略和访问者等。

5. 并发型设计模式(Concurrency Design Patterns):  处理多线程编程范例,包括活动对象、核反应和调度程序等。

6. 架构型设计模式(Architectural Design Patterns):  用于架构目的的设计模式,包括MVC(模型-视图-控制器)、MVP(模型-视图-表示器)和MVVM(模型-视图-视图模型)等。

原型模式和反模式

原型模式是什么?

Proto-patterns(原型模式)是指那些在设计模式被广泛接受之前的阶段,由开发者个体提出并在实践中得到验证的设计思想。当一个开发者在解决某一问题时,可能会想到一个独特的解决方案,这个解决方案并没有被广泛认可和文档化,但开发者自身认为它具有可重用性,并认为开发者社区会从中受益。这个阶段被称为 Proto-pattern,意味着这是一个潜在的设计模式,但尚未被完全确认和纳入标准。

如文章中所述,一个 Proto-pattern 在变成一个正式的设计模式之前,需要经历一定的测试阶段,由各种开发者和场景验证,以确保该模式在实践中是有用的、并能够提供正确的结果。通常,将一个 Proto-pattern 转变为完全成熟的模式需要大量的工作和文档化。

如何辨别设计模式?

辨别设计模式的方法通常包括以下几个方面:

1. 问题的复发性:  设计模式是为解决在软件设计中反复出现的问题而提出的,因此首先需要观察问题是否是一种常见的、具有一般性的问题。

2. 通用性:  设计模式通常是一种通用的解决方案,而不是特定于某个特定应用的解决方案。如果一个解决方案在多个上下文中都适用,可能是一个设计模式。

3. 可重用性:  设计模式应该是可重用的,可以在不同的情境中应用。如果解决方案只在特定情境下有用,可能更适合被称为特定应用的最佳实践,而不是设计模式。

4. 文档和社区认可:  成熟的设计模式通常有相应的文档和社区认可。它们被广泛讨论、使用,并有相关的资料可以供开发者学习和参考。

反模式的概念和例子

反模式是指在软件设计和开发中,被认为是不良实践或导致问题的常见做法。这些是反面教材,指导开发者在设计和编码时应该避免的模式。使用 Anti-pattern 可能导致代码不可维护、难以理解、性能低下等问题。

1. 修改 Object 类原型(Modifying Object Class Prototype):  在 JavaScript 中修改 Object 类的原型,影响了所有继承自 Object 的对象,可能导致不可预测的行为和潜在的冲突。

Object.prototype.newMethod = function() {
   // 新增的方法
};

   

2. 在不拥有的对象上进行修改(Modifying Objects You Don’t Own):  修改第三方库或框架中的对象,可能导致兼容性问题和难以维护的代码。

// 在第三方库的对象上添加新方法
thirdPartyLibrary.someObject.newMethod = function() {
   // 新增的方法
};

3. 过度使用全局变量(Overusing Global Variables):  过度使用全局变量会增加代码的耦合度,降低模块化和可维护性。

 // 过度使用全局变量
 var globalVariable = 'some value';

 function exampleFunction() {
     console.log(globalVariable);
 }

设计模式分类详解

设计模式是在软件设计中为解决特定问题而提出的一套经过验证的通用解决方案。这些模式有助于在设计阶段采用经验丰富的最佳实践,提高代码的可维护性、可扩展性和重用性。下面详细介绍几种常见的设计模式分类及其具体模式。

Creational Design Patterns(创建型设计模式)

这些模式关注对象的创建机制,旨在解决对象的实例化过程中可能引起的问题。

1. Factory Method(工厂方法):  定义一个用于创建对象的接口,由子类决定实例化哪个类。它使一个类的实例化延迟到其子类。

2. Abstract Factory(抽象工厂):  提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定它们的具体类。

3. Builder(建造者):  将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

4. Prototype(原型):  通过复制现有对象来创建新对象,而不是从头开始创建。适用于对象创建的成本较高的情况。

5. Singleton(单例):  确保一个类只有一个实例,并提供全局访问点。

Structural Design Patterns(结构型设计模式)

这些模式关注对象的组合,帮助定义不同对象之间的关系。

1. Adapter(适配器):  将一个接口转换成另一个客户希望的接口,使得原本不兼容的类可以一起工作。

2. Bridge(桥接):  将抽象部分与它的实现部分分离,以便两者可以独立地变化。

3. Composite(组合):  将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端统一对待单个对象和组合对象。

4. Decorator(装饰器):  动态地给一个对象添加一些额外的职责,同时保持原有对象的结构。

5. Facade(外观):  为子系统中的一组接口提供一个一致的界面,使得子系统更容易使用。

6. Flyweight(享元):  通过共享已经存在的相似对象来最小化内存使用或计算开销。

7. Proxy(代理):  为其他对象提供一种代理以控制对这个对象的访问。

Behavioral Design Patterns(行为型设计模式)

这些模式关注对象之间的通信,定义了它们之间的算法和责任。

1. Chain of Responsibility(责任链):  通过传递请求沿链来处理请求,直到有一个对象处理它。

2. Command(命令):  将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。

3. Iterator(迭代器):  提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部表示。

4. Mediator(中介者):  用一个中介对象来封装一系列的对象交互,使得对象之间松散耦合。

5. Memento(备忘录):  在不暴露对象内部表示的情况下,捕获并且保存对象的内部状态,以后可以恢复到这个状态。

6. Observer(观察者):  定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知并被自动更新。

7. State(状态):  允许对象在其内部状态改变时改变其行为,对象看起来似乎修改了它的类。

8. Strategy(策略):  定义一系列算法,将它们封装起来,并且使它们可以互相替换。

9. Visitor(访问者):  表示一个作用于某对象结构中的各元素的操作。可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

Concurrency Design Patterns(并发设计模式)

这些模式关注多线程和并发编程中的问题和解决方案。

1. Active Object(主动对象):  将每个请求封装成对象,然后由一个专门的线程调度这些对象。

2. Nuclear Reaction(核反应):  通过将任务划分成可并行执行的小任务,以提高计算效率。

3. Scheduler(调度器):  控制并发执行的任务顺序,使得程序能够以期望的方式运行。

Architectural Design Patterns(架构设计模式)

这些模式关注整个软件架构的组织和结构。

1. MVC(Model-View-Controller):  将应用程序分为三个组件:模型(应用程序数据和业务逻辑)、视图(用户界面元素)和控制器(处理用户输入和管理视图与模型之间的交互)。

2. MVP(Model-View-Presenter):  类似于MVC,但是Presenter处理用户输入并更新视图,同时负责更新模型。

3. MVVM(Model-View-ViewModel):  将视图和模型分离,使用一个中介层(ViewModel)来处理用户输入并更新模型,然后通知视图进行更新。

设计模式示例

以下是每个设计模式的具体示例:

1. Constructor Pattern(构造函数模式): 

function Person(name, age) {
    this.name = name;
    this.age = age;
}

// Usage
const person1 = new Person('John', 25);
const person2 = new Person('Jane', 30);

2. Module Pattern(模块模式): 

const CounterModule = (function () {
    let count = 0;

    function increment() {
        count++;
    }

    function decrement() {
        count--;
    }

    function getCount() {
        return count;
    }

    return {
        increment,
        decrement,
        getCount
    };
})();

// Usage
CounterModule.increment();
console.log(CounterModule.getCount()); // Output: 1

3. Revealing Module Pattern(揭示模块模式): 

const RevealingCounterModule = (function () {
    let count = 0;

    function increment() {
        count++;
    }

    function decrement() {
        count--;
    }

    function getCount() {
        return count;
    }

    return {
        increment,
        decrement,
        getCount
    };
})();

// Usage
RevealingCounterModule.increment();
console.log(RevealingCounterModule.getCount()); // Output: 1

4. Singleton Pattern(单例模式): 

const Singleton = (function () {
    let instance;

    function createInstance() {
        // Private method to create a singleton instance
        return { message: 'This is a singleton instance.' };
    }

    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

// Usage
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // Output: true

5. Observer Pattern(观察者模式): 

class Observer {
    constructor() {
        this.observers = [];
    }

    subscribe(callback) {
        this.observers.push(callback);
    }

    unsubscribe(callback) {
        this.observers = this.observers.filter(observer => observer !== callback);
    }

    notify(data) {
        this.observers.forEach(observer => observer(data));
    }
}

// Usage
const observer = new Observer();

const callback1 = data => console.log(`Callback 1: ${data}`);
const callback2 = data => console.log(`Callback 2: ${data}`);

observer.subscribe(callback1);
observer.subscribe(callback2);

observer.notify('Data has been updated.'); 
// Output: 
// Callback 1: Data has been updated.
// Callback 2: Data has been updated.

6. Mediator Pattern(中介者模式): 

class Mediator {
    constructor() {
        this.colleagues = [];
    }

    addColleague(colleague) {
        this.colleagues.push(colleague);
    }

    mediate(originator, message) {
        this.colleagues.forEach(colleague => {
            if (colleague !== originator) {
                colleague.receive(message);
            }
        });
    }
}

class Colleague {
    constructor(mediator, name) {
        this.mediator = mediator;
        this.name = name;
        this.mediator.addColleague(this);
    }

    send(message) {
        this.mediator.mediate(this, message);
    }

    receive(message) {
        console.log(`${this.name} received: ${message}`);
    }
}

// Usage
const mediator = new Mediator();
const colleague1 = new Colleague(mediator, 'Colleague 1');
const colleague2 = new Colleague(mediator, 'Colleague 2');

colleague1.send('Hello from Colleague 1!');
// Output: Colleague 2 received: Hello from Colleague 1!

7. Prototype Pattern(原型模式): 

const Dog = {
    breed: 'Unknown',
    clone: function () {
        const clone = Object.create(this);
        clone.sound = 'Woof';
        return clone;
    }
};

// Usage
const dog1 = Dog.clone();
dog1.breed = 'Labrador';

const dog2 = Dog.clone();
dog2.breed = 'Poodle';

console.log(dog1.sound); // Output: Woof
console.log(dog1.breed); // Output: Labrador

console.log(dog2.sound); // Output: Woof
console.log(dog2.breed); // Output: Poodle

8. Command Pattern(命令模式): 

class Command {
    constructor(receiver) {
        this.receiver = receiver;
    }

    execute() {
        throw new Error('execute method must be overridden');
    }
}

class ConcreteCommand extends Command {
    execute() {
        this.receiver.action();
    }
}

class Receiver {
    action() {
        console.log('Receiver is performing an action.');
    }
}

class Invoker {
    constructor(command) {
        this.command = command;
    }

    invoke() {
        this.command.execute();
    }
}

// Usage
const receiver = new Receiver();
const command = new ConcreteCommand(receiver);
const invoker = new Invoker(command);

invoker.invoke(); // Output: Receiver is performing an action.

9. Facade Pattern(外观模式): 

class Subsystem1 {
    operation() {
        return 'Subsystem 1 operation';
    }
}

class Subsystem2 {
    operation() {
        return 'Subsystem 2 operation';
    }
}

class Facade {
    constructor(subsystem1, subsystem2) {
        this.subsystem1 = subsystem1;
        this.subsystem2 = subsystem2;
    }

    operation() {
        const result1 = this.subsystem1.operation();
        const result2 = this.subsystem2.operation();
        return `${result1}\n${result2}`;
    }
}

// Usage
const subsystem1 = new Subsystem1();
const subsystem2 = new Subsystem2();
const facade = new Facade(subsystem1, subsystem2);

console.log(facade.operation());
// Output:
// Subsystem 1 operation
// Subsystem 2 operation

原文链接:https://juejin.cn/post/7324750282859921445 作者:乔明飞

(0)
上一篇 2024年1月17日 下午5:00
下一篇 2024年1月17日 下午5:10

相关推荐

发表回复

登录后才能评论