创建型:工厂模式-工厂方法、抽象工厂

创建,工厂,模式,方法,抽象 · 浏览次数 : 311

小编点评

工厂方法模式与抽象工厂模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂结构可以负责多个不同产品等级结构中的产品对象的创建 。 抽象工厂模式与工厂方法模式相对于,工厂方法模式是针对一个产品系列的,而抽象工厂模式则需要面对多个产品等级结构,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。 定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。 工厂方法与抽象工厂抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂结构可以负责多个不同产品等级结构中的产品对象的创建 。

正文

简单工厂问题

简单工厂中我们通过参数来返回不同的产品对象,如果管理的对象过多,这个工厂函数会比较庞大,且当我们需要增加一个新的产品时,需要修改这个工厂方法,违反开闭原则(对拓展开放,对修改关闭)。

为了解决简单工厂模式的问题,出现了工厂方法模式。

解决简单工厂思路

简单工厂类图关系类似如下:

如上图当我们需要增加一个产品时,我们需要修改create 方法增加相关判断的逻辑,这不符合开闭原则。

假如一个工厂只负责他自己的产品,那么新增产品也只是新增一个工厂以及对应的产品,那么简单工厂的问题是不是也解决了。

总结:将对象的创建与实例化延迟到子类,这样的工厂设计就符合“开闭原则”了,扩展时不必去修改原来的代码

工厂方法模式

如上图当我们增加一个产品时,只需要增加一个工厂(实现抽象类),然后在各自的工厂返回自己需要的产品即可;

工厂方法由4个要素组成:

  1. 抽象工厂 AbstractFactory: 这个是工厂方法模式的核心,定义用来生产对应产品的方法,是具体工厂必须实现的接口或者必须继承的父类,通常使用中它由抽象类或者接口来实现。
  2. 具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码。
  3. 抽象产品 AbstractProduct:把产品共有的特征抽象,通常使用中它由抽象类或者接口来实现。
  4. 具体产品 Product:具体工厂所创建的产品(对象)。

 

如果只是接触了js,可能对抽象不太了解 ,其实抽象只是一种思考的问题的方式。

抽象的定义是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程

简单的理解其实就是共有的特征、特性,比如我们要规范人这个对象具有的特点,就用一个接口或者抽象类声明一些共有的属性、方法,具体的子类在实现这个接口或者抽象类,这样子类也有这些属性、方法。

这样做的好处就是约束子类,保证子类都有这些属性、方法,不会存在乱七八糟的对象,这也符合我们大脑工作方式。

ts模拟工厂方法模式

  工厂方法是将实际创建对象的工作推迟到子类中,这样核心类就变成了抽象类。但是在JavaScript中很难像传统面向对象那样去实现创建抽象类。所以在JavaScript中我们只需要参考它的核心思想即可。我们可以将工厂方法看作是一个实例化对象的工厂类。虽然ES6也没有实现abstract,但是我们可以使用new.target来模拟出抽象类。new.target指向直接被new执行的构造函数,我们对new.target进行判断,如果指向了该类则抛出错误来使得该类成为抽象类。

ts 扩展了js,所以这里我用ts 来模拟

/*
工厂方法是简单工厂的优化版本,在之前把生成具体产品的实例逻辑都写在了工厂方法中,
导致增加一个产品,这个工厂方法需要修改。
所以工厂方法主要是把这一部分功能独立出来了,一个工厂负责一个产品
工厂方法核心结构有四个角色
  1、抽象工厂
  2、具体工厂
  3、抽象产品
  4、具体产品
因为js不支持没有抽象类这里用ts 代替,只要符合核心思想即可
*/
// 抽象工厂
abstract class CardFactor{
  abstract getCardInstance(name:string, time:string):Card
}
// 抽象产品
abstract class Card {
  carName: string;
  time: string;
  abstract getCarDesc():void
}

// 具体产品-BydCar
class BydCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}
// 具体产品-JeepCar
class JeepCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}
// 具体产品-BenzCar
class BenzCar extends Card {
  carName: string
  time: string
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}

// 具体的工厂-BydCarFactory
class BydCarFactory extends CardFactor {
  getCardInstance (name, time) {
    return new BydCar(name, time)
  }
}
// 具体的工厂-JeepCarFactory
class JeepCarFactory extends CardFactor{
  getCardInstance (name, time) {
    return new JeepCar(name, time)
  }
}
// 具体的工厂-BenzCarFactory
class BenzCarFactory extends CardFactor{
  getCardInstance (name, time) {
    return new BenzCar(name, time)
  }
}
// test 直接使用具体的工厂
const bydCar = new BydCarFactory().getCardInstance('byd 汽车', '2022-08-20')
const jeepCar = new JeepCarFactory().getCardInstance('jeep 汽车', '2022-08-21')
const benzCar = new BenzCarFactory().getCardInstance('benz 汽车', '2022-08-22')


bydCar.runCarName()
bydCar.getCarDesc()

jeepCar.runCarName()
jeepCar.getCarDesc()

benzCar.runCarName()
benzCar.getCarDesc()

 如果我们现在需要增加一种车型,那我们只需增加对应的工厂,跟产品类即可,我们对原有的工厂不会造成任何影响 所谓的“对拓展开放,对修改封闭”就这么圆满实现了。

工厂方法缺陷

  在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体工厂对应一个具体产品,但有时候我们需要一个工厂能够提供多个产品对象,而不是单一的对象,这个时候我们就需要使用抽象工厂模式。

  上面代码中我们的比亚迪工厂只是生产一种产品,现实是一个工厂大概率是要生产很多种不同的产品,如比亚迪有汉dmi、dmp、唐suv等车型。这种一个工厂需要多种产品的时候,按照工厂方法的思路,我们需要写很多个这种工厂类,这也非常繁琐。

抽象工厂模式

  我们需要的是一个工厂可以生产多种不同的产品对象,按照设计模式的思路把变化的抽出来封装。变的是一个工厂可以支持多个产品对象,不变的依旧是在工厂中拿到产品对象。按照工厂方法的思路,只需要在抽象工厂中增加创建对应的产品即可,以之前汽车的例子把工厂方法改成抽象工厂,只要把抽象工厂中增加对应的获取产品,修改之后现在比亚迪工厂支持默认车型,汉车型,suv车型;

/*
抽象工厂:一个工厂可以生产多种不同的产品,它思路跟工厂方法基本一致。
抽象工厂核心结构有四个角色
  1、抽象工厂
  2、具体工厂
  3、抽象产品
  4、具体产品
因为js不支持没有抽象类这里用ts 代替,只要符合核心思想即可
*/
// 抽象工厂
abstract class CardFactor{
  // 默认的车型
  abstract getCardInstance(name:string, time:string):Card
  // 汉车型
  abstract getCardHanDmiInstance(name:string, time:string):Card
  // suv 车型
  abstract getCardSuvInstance(name:string, time:string):Card
}
// 抽象产品,同理:这里也可以把产品进一步抽象,如汉的抽象产品,suv的抽象产品,这里不在调整
abstract class Card {
  carName: string;
  time: string;
  abstract getCarDesc():void
}

// 具体产品-BydCar
class BydCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}

// 具体产品-BydHanCar
class BydHanCar extends Card {
  name = '中大型轿车汉'
  desc = '这是来自比亚迪的汉'
  constructor () {
    super()
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}
// 具体产品-BydSuvCar
class BydSuvCar extends Card {
  name = 'suv'
  desc = '这是来自比亚迪的suv'
  constructor () {
    super()
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生产于:${this.time}`)
  }
}
// 具体的工厂-BydCarFactory
class BydCarFactory extends CardFactor {
  // 生产默认的byd 车型
  getCardInstance (name, time) {
    return new BydCar(name, time)
  }
  // 生产byd汉车型
  getCardHanDmiInstance () {
    return new BydHanCar()
  }
  // 生产byd suv车型
  getCardSuvInstance () {
    return new BydSuvCar()
  }
}

// test 直接使用具体的工厂
const bydCarFactory = new BydCarFactory()
// 现在这个工厂具备生产三种车的产品了
const bydCar = bydCarFactory.getCardInstance('默认车型', '2023-3-7');
const hanCar = bydCarFactory.getCardHanDmiInstance();
const suvCar = bydCarFactory.getCardSuvInstance();

 抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。

 抽象工厂模式同工厂方法模式一样,也是由4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。

  1. AbstractFactory:抽象工厂
  2. ConcreteFactory:具体工厂
  3. AbstractProduct:抽象产品
  4. Product:具体产品

这种管理多个产品结构的抽象类,就是抽象工厂模式,让一个工厂具备管理多个产品结构。

抽象工厂模式相对于工厂方法模式来说,工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。

定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

工厂方法与抽象工厂

抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂结构可以负责多个不同产品等级结构中的产品对象的创建 。

(1)工厂方法只有一个抽象产品类和一个抽象工厂类,可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例

(2)抽象工厂模式拥有多个抽象产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,时每个具体工厂类可以创建多个具体产品类的实例

小结

  1. 工厂方法是一个工厂只生产一种产品,类似极端情况下的抽象工厂模式(即只生产一种产品的抽象工厂模式)
  2. 抽象工厂是一个工厂可以生产多种同类的产品(产品族)

与创建型:工厂模式-工厂方法、抽象工厂相似的内容:

创建型:工厂模式-工厂方法、抽象工厂

简单工厂问题 简单工厂中我们通过参数来返回不同的产品对象,如果管理的对象过多,这个工厂函数会比较庞大,且当我们需要增加一个新的产品时,需要修改这个工厂方法,违反开闭原则(对拓展开放,对修改关闭)。 为了解决简单工厂模式的问题,出现了工厂方法模式。 解决简单工厂思路 简单工厂类图关系类似如下: 如上图

设计模式学习(三):工厂模式

设计模式学习(三):工厂模式 作者:Grey 原文地址: 博客园:设计模式学习(三):工厂模式 CSDN:设计模式学习(三):工厂模式 工厂模式 工厂模式是创建型模式,工厂模式分为:简单工厂,工厂方法和抽象工厂三种类型。 简单工厂 这个模式很简单,比如我们需要制造不同类型的鼠标,我们只需要创建一个鼠

软件设计模式系列之二———抽象工厂模式

抽象工厂模式是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的方式,而无需指定它们的具体类。该模式以一组抽象接口为核心,包括抽象工厂接口和一组抽象产品接口,每个具体工厂类负责创建特定产品家族,保证这些产品之间的兼容性。客户端代码通过与抽象工厂和抽象产品接口交互,可以轻松地切换不同工厂来创建不同系列的产品。

简易的工厂设计模式

工厂设计模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需暴露对象的创建逻辑。在工厂模式中,我们定义一个接口或抽象类,该接口或抽象类用于创建对象,但让子类决定要实例化的类。工厂方法模式使类的实例化延迟到其子类。 下面是一个完整的C#实现案例: 首先,我们定义一个接口,用于创建对象: p

软件设计模式系列之三———工厂方法模式

工厂方法模式是一种常见的设计模式,属于创建型设计模式之一,它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化,将具体对象的实例化延迟到子类中完成,以便在不同情况下可以创建不同类型的对象,而客户端代码不需要知道实际创建的对象类型。

万字详解常用设计模式

本文是博主在工作中对常用设计模式的使用经验总结归纳而来分享给大家。 设计模式一共有23种,本文讲解涉及如下: 责任链模式 模板方法模式 发布订阅模式 策略模式 三大分类 业界一般将设计模式分为三大类: 创建型模式:对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。有五种创建型模

创建型:工厂模式-简单工厂

定义 之所以叫简单工厂是因为真的非常简单,只要一个工厂(函数)就可以了,如果把被创建的对象称为产品,把创建产品的对象或者方法称为工厂,那么只需要传入不同的参数,就可以返回不同的产品(实例),这种模式就叫简单工厂模式。 简单工厂-餐馆点菜 工厂模式其实就是将创建对象的过程单独封装在一个工厂中。 它很像

设计模式之工厂模式

工厂模式是一种创建型设计模式,它提供了一个用于创建对象的接口,但允许子类决定实例化哪个类。工厂方法让一个类的实例化延迟到其子类。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在软件开发中,对象的创建和使用是常见的操作。然而,对象的创建过程常常会涉及到复杂的逻辑和多变的需求。为了

【23种设计模式】工厂方法模式(二)

## 前言 在讲述之工厂方法模式前,我们来先了解简单工厂模式,简单工厂模式是最简单的设计模式之一,它虽然不属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。下面我们来先了解下简单工厂模式,然后针对它的缺点来引出工厂方法模式。 ## 简单工厂模式定义 **简单工厂模式

设计模式之工厂模式

工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用 new 关键字,而是通过调用工厂方法来创建对象。工厂方法是一种在子类中定义的方法,该方法负责实例化对象。工厂方法可以返回不同的对象类型,因此工厂模式可以创建一组相关或不相关的对象。这样就可以将对象的创