设计模式之-工厂模式

1.工厂模式同样是属于创建型模式的一种。

2.定义:在创建对象的时候,不会对客户端暴露具体的创建逻辑,通过工厂所提供的一个统一的接口来得到对象。

3.在工厂模式里面,主要涉及到两个概念(角色):

3.1工厂:该角色负责创建具体的对象,对外部隐藏了具体的创建逻辑

3.2产品:通过调用工厂给客户端提供的接口,所得到的对象

4.整个工厂模式有三种变体:

简单工厂模式

工厂方法模式

抽象工厂模式

5.先写一个简单的工厂模式吧

javascript 复制代码
// 定义产品接口
interface IProduct {
    use():void;
}
class ProductA implements IProduct{
    use(): void {
        console.log("ProductA is used");
    }
    
}
class ProductB implements IProduct{
    use(): void {
        console.log("ProductB is used");
    }
    
}
class SimpleFactory {
    static createProduct(type:string){
        switch(type){
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
                throw new Error("No such product");
        }
    }
}
// 得到具体的产品
// 不需要引入具体的产品类
// 而是通过工厂类来创建具体的产品
const pA = SimpleFactory.createProduct('A');
const pB = SimpleFactory.createProduct('B');

pA.use();
pB.use();

下面是一个贪吃蛇案例的伪代码

javascript 复制代码
// 例如下面的代码是贪吃蛇游戏中的简单工厂模式的一个demo:
class SquareFactory {
    Floor(x,y,color){
        const floor = new Floor(x,y,squareWidth,squareWidth); // 实例化Floor对象
        this.init(floor,color,colliderType.move); // 设置该DOM元素的CSS信息
        return floor; // 返回该对象
    }
    Wall(x,y,color){
        const wall = new this.Wall(x,y,squareWidth,squareWidth); // 实例化 Wall 对象
        this.init(wall,color,collideType.die); // 设置该 DOM 元素的 CSS 信息
        return wall; // 返回该对象
    }
    SnakeHead(x,y,color){
        const snakeHead = new this.SnakeHead(x,y,squareWidth,squareWidth); // 实例化 SnakeHead 对象
        this.init(snakeHead, color, collideType.die); // 设置该 DOM 元素的 CSS 信息
        // 由于蛇头是单例模式,只会有一个蛇头,所以我们需要更新蛇头的 x、y 坐标,而不是新创建一个
        snakeHead.update(x,y);
        return snakeHead; // 返回该对象
    }
    SnakeBody(x,y,color){
        const snakeBody = new SnakeBody(x, y, squareWidth, squareWidth); // 实例化 SnakeBody 对象
        this.init(snakeBody, color, collideType.die); // 设置该 DOM 元素的 CSS 信息
        return snakeBody; // 返回该对象
    }
    Food(x, y, color) {
        const food = new Food(x, y, squareWidth, squareWidth); // 实例化 Food 对象
        this.init(food, color, collideType.eat); // 设置该 DOM 元素的 CSS 信息

        // 由于食物是单例模式,只会有一个食物,所以我们需要更新食物的 x、y 坐标,而不是新创建一个
        food.update(x, y);

        return food; // 返回该对象
    }
    init(square,color,action){
        square.viewContent.style.position = 'absolute';
        square.viewContent.style.width = square.width+'px';
        square.viewContent.style.height = square.height + "px";
        square.viewContent.style.background = color;
         /*
            让 x 代表列,y 代表行
            left = 列(x)*宽度;
            top = 行(y)*高度; 
         */
        square.viewContent.style.left = square.x * squareWidth + "px";
        square.viewContent.style.top = square.y * squareWidth + "px";
         square.collide = action;  //给方块身上打上标签
    }
    static create(type,x,y,color){
         // 预警处理,如果传递过来的 type 类型不存在,抛出一个错误
        if (!SquareFactory.prototype[type]) {
            throw new Error('no this type');
        }
        // 创建一个工厂实例,然后调用工厂对应的流水线方法
        return new SquareFactory()[type](x,y,color);
    }
}

// 应用
const newFloor = SquareFactory.create('Floor', snake.tail.x, snake.tail.y, 'grey'); 
const newBody = SquareFactory.create('SnakeBody', snake.head.x, snake.head.y, 'green');
const snakeHead = SquareFactory.create('SnakeHead', 3, 1, 'deeppink');
const food = SquareFactory.create('Food', x, y, 'red');
const wall = SquareFactory.create("Wall", x, y, "black");

简单工厂模式所存在的问题:

工厂类的职责过重,每一次需要新增一个类型的产品的时候,都需要修改工厂类内部的逻辑,不符合设计原则里面的开放-封闭原则。

6.工厂方法模式

标准的工厂方法模式,其核心就是一个产品对应一个工厂,而不是将创建不同类型的产品的逻辑放入到一个方法里面。

假设有产品 A,B,C,那么在标准的工厂方法模式里面,就有对应的工厂 A,B,C,假设现在需要新增一个产品 D,我们只需要新增一个对应的工厂 D 即可,原来的工厂是不受任何影响的。

typescript 复制代码
interface ILogger{
    log(message:string):void;
}
class FileLogger implements ILogger {
    log(message:string):void {
        console.log('FileLogger ----'+message);
    }
}
class DatabaseLogger implements ILogger {
    log(message:string):void {
        console.log('DatabaseLogger ----'+message);
    }
}
class RemoteLogger implements ILogger{
  log(message:string):void{
    console.log('RemoteLogger----'+message)
  }
}

//Factory
interface IFactory {
    createLogger():ILogger;
}

class FileLoggerFactory implements IFactory {
    createLogger(): ILogger {
        return new FileLogger();
    }
    
}

class DatabaseLoggerFactory implements IFactory {
    createLogger(): ILogger {
       return new DatabaseLogger();
    }
    
}
class RemoteLoggerFactory implements IFactory{
  createLogger(): ILogger {
      return new RemoteLogger();
  }
}

// 使用
const fileFactory = new FileLoggerFactory();
const logger = fileFactory.createLogger();
logger.log('hello--syt--woshi file-logger');
const dataBaseFactory = new DatabaseLoggerFactory();
const logger2 = dataBaseFactory.createLogger();
logger2.log('hello-zcy-')

6.1标准的工厂模式存在的问题:

每增加一个产品,就需要增加一个工厂,当我们的产品的数量很多的时候,就会使得工厂的数量也成倍的增加。

7.抽象工厂模式就是解决上述问题的

在抽象工厂模式中,会有一个产品族的概念,一个产品族(一个系列)会对应一组产品,之后一个工厂在生产的时候,是生产这一组产品,而非单个的某个产品。

7.1场景:

例如,假设我们有一个家具店,产品包括椅子、沙发、咖啡桌等。这些产品可以根据风格(现代、维多利亚、装饰艺术等)来分类。现代风格的椅子、沙发和咖啡桌可以构成一个产品族,维多利亚风格的椅子、沙发和咖啡桌构成另一个产品族。

7.2 如果按照前面所介绍的工厂方法模式,那么这里家具的种类和风格的种类一组合,就会有 9 个工厂,这个在设计上面肯定是不太合理的。

7.3 在这里,当客户想要订购一套现代风的家具的时候,直接通过现代风家具工厂就能够得到该风格的一整套家具,而非某一个单独的家具。

  1. 抽象产品或者产品接口:对不同的产品进行约束
  2. 具体的产品:具体的产品会继承抽象类或者实现对应的抽象接口。
  3. 抽象工厂或者工厂接口:对不同的工厂进行约束。
  4. 具体的工厂:具体的工厂可以继承抽象工厂或者实现工厂接口
  5. 客户端通过某一个具体的工厂,来生产一系列的对象

demo1

typescript 复制代码
// 抽象产品类
abstract class Chair {
    abstract sitOn():string;
}
abstract class Sofa{
    abstract lieOn():string;
}
abstract class CoffeeTable {
    abstract putOn(thing:string):string;
}

// 具体产品
// 现代风
class ModernChair extends Chair {
    sitOn():string {
        return "现代风椅子 - 坐在上面"
    }
}
class ModernSofa extends Sofa {
    lieOn(): string {
        return "现代风沙发 - 躺在上面"
    }
}
class ModernCoffeeTable extends CoffeeTable{
    putOn(thing:string):string {
        return `现代风咖啡桌 - 放上${thing}`
    }
}

// 维多利亚风格家具
class VictorianChair extends Chair {
    sitOn():string {
        return "维多利亚风椅子 - 坐在上面"
    }
}
class VictorianSofa extends Sofa {
    lieOn():string{
        return "维多利亚风沙发 - 躺在上面"
    }
}
class VictorianCoffeeTable extends CoffeeTable {
    putOn(thing:string):string {
        return `维多利亚风咖啡桌 - 放上${thing}`
    }
}
// 定义抽象工厂
abstract class AbstractFactory {
    abstract createChair():Chair;
    abstract createSofa():Sofa;
    abstract createCoffeeTable():CoffeeTable;
}

class ModernFactory extends AbstractFactory {
    createChair():Chair {
        return new ModernChair();
    }
    createSofa():Sofa{
        return new ModernSofa();
    }
    createCoffeeTable():CoffeeTable {
        return new ModernCoffeeTable();
    }
}

class VictorianFactory extends AbstractFactory {
    createChair(): Chair {
        return new VictorianChair();
    }
    createSofa(): Sofa {
        return new VictorianSofa();
    }
    createCoffeeTable(): CoffeeTable {
        return new VictorianCoffeeTable();
    }
    
}

// 商店
class Store {
    private factory:AbstractFactory;
    constructor(fac:AbstractFactory){
        this.factory=fac;
    }
    public orderFurniture():string{
        // 生产对应风格的一套家具
        const chair = this.factory.createChair();
        const sofa = this.factory.createSofa();
        const coffeeTable = this.factory.createCoffeeTable();
        return `${chair.sitOn()} ${sofa.lieOn()} ${coffeeTable.putOn("coffee3")}` 
    }
}
// 现在客户想要一套维多利亚风格的家具
const vFactory = new VictorianFactory();
const store = new Store(vFactory);
console.log(store.orderFurniture());

const mFactory = new ModernFactory();
const store2 = new Store(mFactory);
console.log(store2.orderFurniture());

demo2

typescript 复制代码
// 抽象工厂
class UIComponentFactory{
    createButton(){}
    createInput(){}
}
// 具体工厂
// 负责生产 Material 分割的组件
class MaterialUIComponentFactory extends UIComponentFactory {
    createButton(){
        return new MaterialButton();
    }
    createInput(){
        return new MaterialInput();
    }
} 
// 具体工厂
// 负责生产 AntDesign 风格的组件
class AntDesignUIComponentFactory extends UIComponentFactory {
    createButton(){
        return new AntDesignButton();
    }
    createInput(){
        return new AntDesignInput();
    }
}
// 抽象产品
abstract class Button {}
abstract class Input {}
//具体产品
class MaterialButton extends Button {}
class MaterialInput extends Input {}

class AntDesignButton extends Button {}
class AntDesignInput extends Input {}

// 使用
// 通过materialFactory 就可以生产一套 material 风格的组件
const materialFactory = new MaterialUIComponentFactory();
const materialButton = materialFactory.createButton();
const materialInput = materialFactory.createInput();

非原创,来源渡一谢杰老师的课程,简单记录下

相关推荐
weibkreuz2 小时前
React的基本使用@2
前端·javascript·react.js
于是我说2 小时前
前端JavaScript 项目中 获取当前页面滚动位置
开发语言·前端·javascript
小肖爱笑不爱笑2 小时前
JavaScript
java·javascript·json·web
凯小默2 小时前
02.内存管理和内存泄漏
javascript
来杯三花豆奶2 小时前
Vue 2.0 Mixins 详解:从原理到实践的深度解析
前端·javascript·vue.js
San30.3 小时前
深度驱动:React Hooks 核心之 `useState` 与 `useEffect` 实战详解
前端·javascript·react.js
柒.梧.3 小时前
HTML入门指南:30分钟掌握网页基础
前端·javascript·html
syt_10134 小时前
设计模式之-装饰器模式
设计模式·装饰器模式
智算菩萨4 小时前
实战:高级中文自然语言处理系统的Python设计与实现
前端·javascript·easyui