轻松掌握设计模式-创建型模式

文/晨风不可依米 (2025.06.25)

程序设计模式-创建型模式

  • 隐藏对象创建过程的逻辑。
  • 非直接使用new操作初始化对象。
  • 具有代码复用性高、对象扩展性灵活等特点。

    .

单例模式

  • 单例模式:是指在创建对象过程中仅保存一个实例对象;再次创建对象,即直接使用该对象引用。
  • 模式优缺点
    • 优点:只有一个实例对象,节省内存空间、提升访问速度等。
    • 缺点:违背单一职责,无法构建多实例对象,需重构来解决。
  • 适用场景:配置类对象,资源类对象、系统类对象,全局单一对象。

饿汉式单例实现

  • 特点:无论是否使用单例对象,类对象加载时创建。
class Singleton {
  
  // 在类加载时,初始化单例对象
  private static instance: Singleton = new Singleton();
  
  public static getInstance: Singleton {
    return this.instance
  }

  // 禁止使用 new 来创建对象
  private constructor () {}
}

懒汉式单例实现

  • 特点:在首次调用时初始化单例对象。
class Singleton {
  
  // 在类加载时,初始化单例对象
  private static instance: Singleton | null = null;
  
  public static getInstance: Singleton {
    // 首次使用时动态创建
    if (!this.instance) this.instance = new Singleton();

    return this.instance;
  }

  // 禁止使用 new 来创建对象
  private constructor () {}
}

工厂模式

  • 工厂模式:是指将对象创建过程与对象使用过程分离,通过工厂类封装对象的创建逻辑,并返回创建对象。
  • 模式优缺点
    • 优点:创建过程与使用过程分离,拓展与维护性好。
    • 缺点:类对象众多,且关系复杂。
  • 适用场景:条件式创建同质对象实例,或者组合多种非同质对象实例来构成完整服务功能对象。

简单工厂模式

  • 定义产品接口声明,并实现具体产品类的封装过程。
  • 定义工厂类,根据条件(产品类型)返回指定具体产品实例对象。

// 定义产品接口声明
interface Phone {
  getPhoneID (): string

  initBrowser(): void;
} 


// 封装具体产品类对象
class IPhone6 implements Phone {
  getPhoneID (): string {
    return Math.random().toString().slice(2);
  }
  initBrowser () {
    console.log('初始化浏览器')
  }
}
class IPhone8 implements Phone {
  getPhoneID (): string {
    return Math.random().toString().slice(2);
  }
  initBrowser () {
    console.log('初始化浏览器')
  }
}

// 定义工厂类,提供条件返回具体产品实例对象
class IPhoneFactory {
  createPhone (type: string): Phone {
    if (type === 'iphone6') {
      return new IPhone6();
    } else if (type === 'iphonne8') {
      return new IPhone8();
    } else {
      throw new Error(`工厂类不存在 ${type} 类型手机,无法创建`);
    }
  }
}


工厂方法模式

  • 定义抽象产品类、抽象工厂类,规范类对象的方法接口,并交由具体类来实现抽象方法。
  • 定义具体产品类、具体工厂类,实现具体类对象的封装过程,以及实现抽象方法功能逻辑。
  • 特点:具体工厂类创建同质单一对象实例,强调创建同一工厂类型的对象(比如苹果手机,有i6、i9)。
// 定义抽象产品类
abstract class Phone {
  // 公共方法
  public getPhoneID (): string {
    if (!this.phoneID) return null;
    return this.phoneID;
  }
  // 抽象方法
  abstract usePhone(): void;
  abstract useSMS(): void;
}

// 实现产品类;如苹果手机
class IPhone extends Phone {
  // 实现抽象方法具体逻辑
  public usePhone(): void {
    console.log('使用苹果手机电话功能')
  }
  public usePhone(): void {
    console.log('使用苹果手机短讯功能')
  }
}

// 实现产品类;如安卓手机
class Android extends Phone {
  // 实现抽象方法具体逻辑
  public usePhone(): void {
    console.log('使用安卓手机电话功能')
  }
  public usePhone(): void {
    console.log('使用安卓手机短讯功能')
  }
}

// 定义抽象工厂类
abstract class PhoneFactory {
  abstract createPhone(): Phone
}

// 实现具体工厂类,如苹果手机工厂
class IPhoneFactory extends PhoneFactory {
  public createPhone(): Phone {
    return new IPhone();
  }
}
// 实现具体工厂类,如安卓手机工厂
class AndroidFactory extends PhoneFactory {
  public createPhone(): Phone {
    return new Android();
  }
}

// 应用场景
const AndroidFactoryInstance = new AndroidFactory();
const AndroidPhone = AndroidFactoryInstance.createPhone();
AndroidPhone.usePhone();


抽象工厂模式

  • 定义抽象产品类、抽象工厂类,规范类对象的方法接口,并交由具体类来实现抽象方法。
  • 定义具体产品类、具体工厂类,实现具体类对象的封装过程,以及实现抽象方法功能逻辑。
  • 特点:具体工厂类创建非同质单一对象实例,强调创建多个不同类型的产品类来组合构建完整功能的产品(如套餐菜单,饮料有咖啡、雪碧)。
// 定义抽象饮料类
abstract class Drink {
   abstract getDrinkInfo(): string;
}
// 实现具体饮料类(咖啡)
class Coffee extends Drink {
  public getDrinkInfo() {
    console.log('这是一杯咖啡');
  }
}
// 实现具体饮料类(雪碧)
class Sprite extends Drink {
  public getDrinkInfo() {
    console.log('这是一杯雪碧');
  }
}

// 定义抽象面包类
abstract class Bread {
  abstract getBreadInfo(): string;
}
// 定义具体面包类(法棍)
class Baguette extends Bread {
  public getBreadInfo() {
    console.log('这是一条法棍');
  }
}
// 定义具体面包类(肉包子)
class MeatBun extends Bread {
  public getBreadInfo() {
    console.log('这是一个肉包子');
  }
}

// 定义抽象面条类
abstract class Noodles {
  abstract getNoodlesInfo(): string;
}
// 实现具体面条类(意大利面)
class Pasta extends Noodles {
  public getNoodlesInfo() {
    console.log('这是一碗意大利面');
  }
}
// 实现具体面条类(河粉)
class RiceNoodles extends Noodles {
  public getNoodlesInfo() {
    console.log('这是一碗河粉');
  }
}

// 定义抽象工厂类
abstract class MenuFactory {
  abstract createDrink(): Drink;
  abstract createBread(): Bread;
  abstract createNoodles(): Noodles;
}

// 实现具体工厂类(中国套餐)
class ChinaMenuFactory extends MenuFactory {
  public createDrink(): Drink {
    return new Sprite();
  }
  public createBread(): Bread {
    return new MeatBun();
  }
  public createNoodles(): Noodles {
    return new RiceNoodles();
  }
}

// 实现具体工厂类(外国套餐)
class ForeignMenuFactory extends MenuFactory {
  public createDrink(): Drink {
    return new Coffee();
  }
  public createBread(): Bread {
    return new Baguette();
  }
  public createNoodles(): Noodles {
    return new Pasta();
  }
}


// 查看套餐信息
function getMenuProductInfo (factory: MenuFactory) [
  const drink = chinaMenu.createDrink();
  const bread = chinaMenu.createBread();
  const noodles = chinaMenu.createNoodles()

  drink.getDrinkInfo()
  bread.getBreadInfo()
  noodles.getNoodlesInfo()
}

// 点选中国套餐
const chinaMenu = new ChinaMenuFactory();
getMenuProductInfo(chinaMenu);


建造者(生成器)模式

  • 建造者模式:通过选择多变的部件类,并按相对稳定的构建流程顺序完成复杂对象的创建。
  • 模式优缺点
    • 优点:类对象构建过程分离,并隐藏构建过程,且灵活控制。
    • 缺点:类与对象多,且关系复杂。部件类选择方式较少时,代码量较大。
  • 适用场景:产品类中存在部件选择或复杂对象构建流程控制等创建场景。

经典案例

  • 定义部件类,以供产品类选择所需的部件。
  • 定义产品类,提供部件替换的方法(set**)。
  • 定义建造者类接口声明,规范约束创建部件类的方法(build**)。
  • 定义具体建造者类,实现部件类的选择逻辑,以及访问产品类对象的方法。
  • 定义指导类,不关心构建内容,只关心构建顺序和方式。
// 部件类类型声明
interface ProductOpt {
  name: string
  price: number
}

// 定义部件类(饮料)
class Drink {
  public name: string;
  public price: number;
  constructor (opt: ProductOpt) {
    this.price = opt.price;
    this.name = opt.name;
  }
}
// 定义部件类(面包)
class Bread {
  public name: string;
  public price: number;
  constructor (opt: ProductOpt) {
    this.price = opt.price;
    this.name = opt.name;
  }
}
// 定义部件类(面食)
class Noodles {
  public name: string;
  public price: number;
  constructor (opt: ProductOpt) {
    this.price = opt.price;
    this.name = opt.name;
  }
}


// 定义产品类
class Menu {
  private drink: Drink;
  private bread: Bread;
  private noodles: Noodles;

  public setDrink(drink: Drink): void {
    this.drink = drink;
  }
  public setBread(bread: Bread): void {
    this.bread = bread;
  }
  public setNoodles(noodles: Noodles): void {
    this.noodles = noodles;
  }
  
  public getInfo() {
    return {
      drink: this.drink ?? null,
      bread: this.bread ?? null,
      noodles: this.noodles ?? null 
    }
  }
}


// 定义建造者类接口声明
interface MenuBuilder {
  buildDrink(): void;
  buildBread(): void;
  buildNoodles(): void;
  getMenu(): Menu; 
}

// 定义具体建造者类(套餐A: 咖啡、法棍、意大利面)
class MenuABuilder implements MenuBuilder {
  private menu : Menu;
  constructor() {
    this.menu = new Menu();
  }
  
  buildDrink(): void {
    const drink = new Drimk({ name: '咖啡', price: 10 });
    this.menu.setDrink(drink);
  }
  buildBread(): void {
    const bread = new Bread({ name: '法棍', price: 5 });
    this.menu.setBread(bread);
  }
  buildNoodles(): void {
    const noodles = new Noodles({ name: '意大利面', price: 25 });
    this.menu.setNoodles(noodles);
  }
  getMenu(): Menu {
    return this.menu;
  }
}

// 定义具体建造者类(套餐B: 雪碧、肉包、河粉)
class MenuBBuilder implements MenuBuilder {
  private menu : Menu;
  constructor() {
    this.menu = new Menu();
  }
  
  buildDrink(): void {
    const drink = new Drimk({ name: '雪碧', price:3 });
    this.menu.setDrink(drink);
  }
  buildBread(): void {
    const bread = new Bread({ name: '肉包', price: 2 });
    this.menu.setBread(bread);
  }
  buildNoodles(): void {
    const noodles = new Noodles({ name: '河粉', price: 15 });
    this.menu.setNoodles(noodles);
  }
  getMenu(): Menu {
    return this.menu;
  }
}

// 定义指导类(下单流程以及费用统计)
class MenuDirector {
  private builder: MenuBuilder
  constructor (builder: MenuBuilder) {
    this.builder = builder;
  }

  // 下单流程
  public submitOrder () {
    this.builder.buildDrink();
    this.builder.buildBread();
    this.builder.buildNoodles();
  }
  
  // 费用统计
  public computedFee() {
    const { drink, bread, noodles } = this.getMenuInfo();
    return [drink, bread, noodles].reduce((sum, product => sum + product.price, 0);
  }
  
  // 获取套餐信息
  public getMenuInfo () {
     const menu = this.builder.getMenu();
     return menu.getInfo();
  }
}


// 选择套餐A
const menuA = new MenuABuilder();
const orderA = new MenuDirector(menuA);
orderA.submitOrder();
console.log(orderA.comptedFee())


原型模式

  • 原型模式;基于当前对象(内含自我拷贝clone方法)为模板,减少创建对象过程(构造对象、初始化属性和方法)的性能消耗,
  • 模式优缺点
    • 优点:减少创建对象过程的内存占用,复制现有副本修改。
    • 缺点:重点关注对象的结构复杂性,以便采用浅拷贝或深拷贝来克隆对象为模板。
  • 适用场景:频繁创建建对象带来巨大性能消耗(对象复杂或多级无限嵌套)。

浅拷贝原型模式

  • 简单对象结构(少数属性和方法);浅拷贝克隆对象一层属性和方法等内容,对象的引用属性或方法修改,源体与副本对象会造成一改全改。
/** 浅拷贝 */
function shallowClone<T>(input: T): T {
  if (Array.isArray(input)) {
    return input.slice() as any;
  } else if (input && typeof input === 'object') {
    return Object.assign(
      Object.create(Object.getPrototypeOf(input)),
      input
    );
  }
  return input;
}

/** 原型对象类型声明 */
interface Prototype<T> {
  /** 自我拷贝clone方法 */
  clone(): T;
}

interface HumanOption {
  name: string;
  age?: string;
}

class Human implements Prototype<Human> {
  constrctor (option) {
    const keys = Object.keys(option);
    for (const key of keys) {
      this[key] = option[key]l
    }
  }
  
  /** 自我拷贝clone方法 */
  clone(option) {
    return new Human(shallowClone(this.option))
  }
}


深拷贝原型模式

  • 复杂对象结构(庞大属性和方法);深拷贝克隆对象所有属性和方法,对象的引用属性或方法修改,源体与副本对象互不影响。

function deepClone<T>(input: T, weakMap = new WeakMap()): T {
  // 基本类型或函数
  if (input === null || typeof input !== 'object') {
    return input;
  }

  // 防止循环引用
  if (weakMap.has(input as object)) {
    return weakMap.get(input as object);
  }

  /** 各种类型对象的深拷贝处理 */
  // Date
  if (input instanceof Date) {
    return new Date(input) as any;
  }

  // RegExp
  if (input instanceof RegExp) {
    return new RegExp(input) as any;
  }

  // Map
  if (input instanceof Map) {
    const result = new Map();
    weakMap.set(input, result);
    input.forEach((v, k) => {
      result.set(deepClone(k, weakMap), deepClone(v, weakMap));
    });
    return result as any;
  }

  // Set
  if (input instanceof Set) {
    const result = new Set();
    weakMap.set(input, result);
    input.forEach((v) => {
      result.add(deepClone(v, weakMap));
    });
    return result as any;
  }

  // Array
  if (Array.isArray(input)) {
    const result: any[] = [];
    weakMap.set(input, result);
    input.forEach((item, idx) => {
      result[idx] = deepClone(item, weakMap);
    });
    return result as any;
  }

  /** 记录引用缓存 */
  const result = Object.create(Object.getPrototypeOf(input));
  weakMap.set(input, result);
  for (const key of Object.keys(input)) {
    (result as any)[key] = deepClone((input as any)[key], weakMap);
  }
  
  return result;
}

/** 原型对象类型声明 */
interface Prototype<T> {
  /** 自我拷贝clone方法 */
  clone(): T;
}

interface HumanOption {
  name: string;
  age?: string;
}

class Human implements Prototype<Human> {
  constrctor (option) {
    const keys = Object.keys(option);
    for (const key of keys) {
      this[key] = option[key]l
    }
  }
  
  /** 自我拷贝clone方法 */
  clone(option) {
    return new Human(deepClone(this.option))
  }
}


文章收获

  • 如果觉得对你有所帮助,请点下“推荐”吧!
  • 如果担心文忘记章地址,请点下“收藏”吧!
  • 如果对博主文章内容喜欢,可进行“关注”博主,更好地获悉最新文章内容。
posted @ 2025-06-25 17:25  晨风不可依米  阅读(17)  评论(0)    收藏  举报