diff --git a/docs/design-patterns/creational/abstract-factory.md b/docs/design-patterns/creational/abstract-factory.md index 252603d65..a8193dc0c 100644 --- a/docs/design-patterns/creational/abstract-factory.md +++ b/docs/design-patterns/creational/abstract-factory.md @@ -6,7 +6,111 @@ group: title: 创建型 order: 2 title: 抽象工厂模式 -order: 5 +order: 2 --- # 抽象工厂模式 + +抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。抽象工厂模式是工厂方法模式的进一步扩展,它将一组相关的工厂封装在一个接口中,使客户端代码可以与具体工厂的实现分离。 + +关键组成部分: + +1. 抽象工厂(Abstract Factory): 定义了一组创建相关对象的方法,每个方法对应一个具体工厂。 +2. 具体工厂(Concrete Factory): 实现了抽象工厂的接口,负责创建一组相关的产品。 +3. 抽象产品(Abstract Product): 定义了一组相关产品的接口。 +4. 具体产品(Concrete Product): 实现了抽象产品的接口,是由具体工厂创建的对象。 + +抽象工厂模式的关键思想在于将一组相关的产品的创建封装在一个工厂中,使得客户端代码可以通过工厂接口来创建产品,而不需要直接关心具体产品的实现。 + +以下是一个简单的抽象工厂模式的例子,假设我们有两种风格的按钮和文本框:Windows 风格和 Mac 风格。 + +```typescript +// 抽象产品 - 按钮 +class Button { + click() {} +} + +// 具体产品 - Windows 风格按钮 +class WindowsButton extends Button { + click() { + console.log("Windows button clicked"); + } +} + +// 具体产品 - Mac 风格按钮 +class MacButton extends Button { + click() { + console.log("Mac button clicked"); + } +} + +// 抽象产品 - 文本框 +class TextBox { + input() {} +} + +// 具体产品 - Windows 风格文本框 +class WindowsTextBox extends TextBox { + input() { + console.log("Windows text box input"); + } +} + +// 具体产品 - Mac 风格文本框 +class MacTextBox extends TextBox { + input() { + console.log("Mac text box input"); + } +} + +// 抽象工厂 +class UIFactory { + createButton() {} + createTextBox() {} +} + +// 具体工厂 - Windows 风格工厂 +class WindowsUIFactory extends UIFactory { + createButton() { + return new WindowsButton(); + } + + createTextBox() { + return new WindowsTextBox(); + } +} + +// 具体工厂 - Mac 风格工厂 +class MacUIFactory extends UIFactory { + createButton() { + return new MacButton(); + } + + createTextBox() { + return new MacTextBox(); + } +} + +``` + +使用抽象工厂模式,客户端代码可以通过抽象工厂接口来创建按钮和文本框,而不需要直接关心具体产品的实现。例如: + +```typescript +// 客户端代码 +function createUI(factory) { + const button = factory.createButton(); + const textBox = factory.createTextBox(); + + return { button, textBox }; +} + +const windowsUI = createUI(new WindowsUIFactory()); +windowsUI.button.click(); // 输出:Windows button clicked +windowsUI.textBox.input(); // 输出:Windows text box input + +const macUI = createUI(new MacUIFactory()); +macUI.button.click(); // 输出:Mac button clicked +macUI.textBox.input(); // 输出:Mac text box input +``` + +通过使用抽象工厂模式,我们可以轻松切换不同风格的 UI,而不需要修改客户端代码。这使得系统更加灵活,并易于扩展和维护。 \ No newline at end of file diff --git a/docs/design-patterns/creational/builder.md b/docs/design-patterns/creational/builder.md deleted file mode 100644 index 9b477725a..000000000 --- a/docs/design-patterns/creational/builder.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -nav: - title: 设计模式 - order: 10 -group: - title: 创建型 - order: 2 -title: 创造者模式 -order: 6 ---- - -# 创造者模式 diff --git a/docs/design-patterns/creational/factory-method.md b/docs/design-patterns/creational/factory-method.md index e79bc09c7..e00be70b6 100644 --- a/docs/design-patterns/creational/factory-method.md +++ b/docs/design-patterns/creational/factory-method.md @@ -6,9 +6,78 @@ group: title: 创建型 order: 2 title: 工厂方法模式 -order: 4 +order: 1 --- # 工厂方法模式 -工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。 +工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但是由子类决定实例化哪个类。这样,工厂方法模式将类的实例化推迟到子类。 + +以下是一个简单的 JavaScript 示例,演示了工厂方法模式: + +假设我们有一个计算器应用程序,需要支持不同的操作,例如加法和减法。我们可以使用工厂方法模式来实现不同操作的创建。 + +```typescript +// 抽象产品 - 操作 +class Operation { + getResult() {} +} + +// 具体产品 - 加法操作 +class AdditionOperation extends Operation { + constructor(number1, number2) { + super(); + this.number1 = number1; + this.number2 = number2; + } + + getResult() { + return this.number1 + this.number2; + } +} + +// 具体产品 - 减法操作 +class SubtractionOperation extends Operation { + constructor(number1, number2) { + super(); + this.number1 = number1; + this.number2 = number2; + } + + getResult() { + return this.number1 - this.number2; + } +} + +// 抽象创建者 - 操作工厂 +class OperationFactory { + createOperation() {} +} + +// 具体创建者 - 加法操作工厂 +class AdditionOperationFactory extends OperationFactory { + createOperation(number1, number2) { + return new AdditionOperation(number1, number2); + } +} + +// 具体创建者 - 减法操作工厂 +class SubtractionOperationFactory extends OperationFactory { + createOperation(number1, number2) { + return new SubtractionOperation(number1, number2); + } +} + +// 客户端代码 +function calculate(factory, number1, number2) { + const operation = factory.createOperation(number1, number2); + const result = operation.getResult(); + console.log(`Result: ${result}`); +} + +const additionFactory = new AdditionOperationFactory(); +calculate(additionFactory, 5, 3); // 输出:Result: 8 + +const subtractionFactory = new SubtractionOperationFactory(); +calculate(subtractionFactory, 5, 3); // 输出:Result: 2 +``` \ No newline at end of file diff --git a/docs/design-patterns/creational/prototype.md b/docs/design-patterns/creational/prototype.md index 38db9a826..2d21c07e4 100644 --- a/docs/design-patterns/creational/prototype.md +++ b/docs/design-patterns/creational/prototype.md @@ -6,7 +6,66 @@ group: title: 创建型 order: 2 title: 原型模式 -order: 3 +order: 4 --- # 原型模式 + +原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而无需显式地使用构造函数。原型模式通常用于创建复杂的对象,其中的构造过程相对昂贵或者复杂,而新对象的创建可以通过复制现有对象的状态来更高效地实现。 + +关键组成部分: + +1. 原型接口(Prototype Interface): 定义了克隆方法的接口,具体的原型类将实现这个接口。 +2. 具体原型类(Concrete Prototype): 实现了原型接口,负责实现克隆方法,以便通过复制自身来创建新对象。 +3. 客户端(Client): 使用原型模式的代码,通过克隆来创建新对象。 + +下面是一个简单的 JavaScript 实现原型模式的例子: + +```typescript +// 原型接口 +class Animal { + clone() {} + makeSound() {} +} + +// 具体原型类 - 狗 +class Dog extends Animal { + clone() { + return Object.create(this); // 通过原型链复制自身 + } + + makeSound() { + console.log("Woof!"); + } +} + +// 具体原型类 - 猫 +class Cat extends Animal { + clone() { + return Object.create(this); // 通过原型链复制自身 + } + + makeSound() { + console.log("Meow!"); + } +} + +// 客户端代码 +const originalDog = new Dog(); +const clonedDog = originalDog.clone(); +console.log(originalDog === clonedDog); // 输出:false,虽然内容相同但是不是同一个实例 + +originalDog.makeSound(); // 输出:Woof! +clonedDog.makeSound(); // 输出:Woof! + +const originalCat = new Cat(); +const clonedCat = originalCat.clone(); +console.log(originalCat === clonedCat); // 输出:false + +originalCat.makeSound(); // 输出:Meow! +clonedCat.makeSound(); // 输出:Meow! +``` + +在这个例子中,`Dog` 和 `Cat` 类都实现了 `Animal` 接口的 `clone` 方法,通过调用 `Object.create(this)` 来创建一个新对象,该对象继承自当前对象。客户端代码可以通过调用 `clone` 方法来创建新的狗和猫实例。 + +原型模式的优势在于通过复制现有对象来创建新对象,避免了昂贵的构造过程。这对于那些创建过程复杂或者需要大量资源的对象来说是非常有用的。 \ No newline at end of file diff --git a/docs/design-patterns/creational/singleton.md b/docs/design-patterns/creational/singleton.md index 1a2a527bf..5c40e7b56 100644 --- a/docs/design-patterns/creational/singleton.md +++ b/docs/design-patterns/creational/singleton.md @@ -6,148 +6,54 @@ group: title: 创建型 order: 2 title: 单例模式 -order: 2 +order: 5 --- # 单例模式 -**单例模式(Singleton)** 指保证一个类仅有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。 +单例模式(Singleton Pattern) 是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点以获取该实例。 -在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单例。 +单例模式通常在以下情况下使用: -单例模式在现实生活中的应用也非常广泛,例如公司 CEO、部门经理等都属于单例模型。 +1. 一个全局对象负责协调系统的操作。 +2. 一个共享的资源,例如配置信息,需要在系统中的多个部分之间共享。 -## 特点 +单例模式的关键特点包括: -单例模式有三个特点: +1. 私有构造函数(Private Constructor): 单例类通常会将其构造函数设为私有,以防止直接通过 new 关键字创建多个实例。 +2. 静态方法或属性提供访问点: 单例类通常提供一个静态方法或属性,用于获取该类的唯一实例。 +3. 延迟实例化(Lazy Instantiation): 实例的创建通常是延迟的,即在第一次请求实例时才进行创建。 -1. 单例类只有一个实例对象 -2. 该单例对象必须由单例类自行创建 -3. 单例类对外提供一个访问该单例的全局访问点 +下面是一个简单的 JavaScript 实现单例模式的示例: -优点: +```typescript +class Singleton { + // 私有变量,用于存储唯一实例 + static instance = null; -1. 可避免对共享资源的多重占用 -2. 可保证内存中只有一个实例,减少内存的开销 -3. 可设置全局访问点,优化和共享资源的访问 - -缺点: - -1. 扩展性差:单例模式一般没有接口,扩展困难。如果要扩展,则修改原来的代码,违背开闭原则 -2. 职责过重:单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则 - -## 模式结构 - -## 代码示例 - -全局作用域中的全局变量不是单例模式,全局变量会存在很大的隐患,随着项目的体积和功能日益增大,很容易出现命名冲突、作用域内变量污染和变量覆盖等问题,给开发人员带来很多苦恼。 - -所以要减少全局变量使用,即使用全局变量也要将污染降到最低。 - -单例模式通常有两种实现形式:懒汉式单例和饿汉式单例子。 - -### 饿汉式单例 - -该模式的特点是类一旦加载就创建一个单例,保证在调用 `getInstance` 方法之前单例已经存在了。 - -```ts -class HungrySingleton { - public name: string; - public type: number; - - private static instance: HungrySingleton = new HungrySingleton(); - - // 将 constructor 设为私有属性,防止 new 调用 - private constructor() {} - - public static getInstance(): HungrySingleton { - return HungrySingleton.instance; - } -} - -const personA = HungrySingleton.getInstance(); -const personB = HugnrySingleton.getInstance(); - -console.log(personA === personB); -// true -``` - -### 懒汉模式 - -1. 实例被需要时才去创建,如果单例已经创建,将无法创建新的单例,返回原先的单例。 -2. 如果某个单例使用的次数少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建 - -```ts -class LazySingleton { - public name: string; - public age: number; - private static instance: LazySingleton; + // 私有构造函数 + constructor() { + if (!Singleton.instance) { + // 如果实例不存在,则创建实例 + Singleton.instance = this; + } - public construcotr(name: string, age: number) { - this.name = name; - this.age = age; + // 返回唯一实例 + return Singleton.instance; } - public static getInstance(name: string, age: number): LazySingleton { - if (LazySingleton.instance === null) { - LazySingleton.instance = new LazySingleton(name, age); - } - - return this.instance; + // 公共方法 + showMessage() { + console.log("Hello, I am a Singleton!"); } } -const personA = LazySingleton.getInstance('Dave', 20); -const personB = LazySingleton.getInstance('Mary', 24); +// 使用单例模式 +const singleton1 = new Singleton(); +singleton1.showMessage(); // 输出:Hello, I am a Singleton! -console.log(personA, personB); -// LazySingleton{ name: "Dave", age: 20 } LazySingleton{ name: "Dave", age: 20 } +const singleton2 = new Singleton(); +console.log(singleton1 === singleton2); // 输出:true,因为它们是同一个实例 ``` -### 命名空间 - -命名空间可以减少全局变量的数量,可以使用对象字面量将这一类的变量作为它的属性进行访问。 - -```js -var Singleton = { - fun1: function () { - console.log('fun1'); - }, - fun2: function () { - console.log('fun2'); - }, -}; -``` - -### 使用闭包封装私有变量 - -使用 IIFI 立即执行函数表达式,让 JavaScript 编译器不在认为这是一个函数声明,而是 **立即执行函数**,将私有变量保存在它的闭包环境中,暴露可以访问私有变量的接口。类似创建一个块级作用域,和其他作用域的变量隔离。 - -```js -const Singleton = (function () { - let instance; - - function createInstance() { - var object = new Object('I am the instance'); - return object; - } - - return { - getInstance: function () { - if (!instance) { - instance = createInstance(); - } - return instance; - }, - }; -})(); - -function run() { - const instance1 = Singleton.getInstance(); - const instance2 = Singleton.getInstance(); - - console.log('Same instance? ' + (instance1 === instance2)); -} - -run(); -``` +在这个例子中,通过构造函数的私有性和静态属性来确保只有一个实例,并通过 `showMessage` 方法来验证单例的存在。使用单例模式可以确保在整个应用程序中只有一个实例,避免了不必要的资源浪费和复杂性。 \ No newline at end of file