我想学会设计模式之抽象工厂模式| 8月更文挑战

243 阅读3分钟

抽象工厂模式

抽象工厂模式就是:围绕一个超级工厂类,创建其他工厂类;再围绕工厂类,创建实体类。相较于传统的工厂模式,它多出了一个超级工厂类

什么是抽象工厂模式?

抽象工厂模式就是:围绕一个超级工厂类,创建其他工厂类;再围绕工厂类,创建实体类。

相较于传统的工厂模式,它多出了一个超级工厂类

它的优缺点与工厂模式类似,这里不再冗赘它的优缺点,下面直接谈一下实现吧。

如何实现抽象工厂模式?

为了让目标更清晰,就实现下面的示意图:

img

准备实体类

按照之前的做法,这里我们实现几个实体类:Cat 和 Dog 一组、Male 和 Female 一组。

class Dog {
    run() {
        console.log("狗");
    }
}
class Cat {
    run() {
        console.log("猫");
    }
}
class Male {
    run() {
        console.log("男性");
    }
}
class Female {
    run() {
        console.log("女性");
    }
}

准备工厂类

假设 Cat 和 Dog,属于 Animal 工厂的产品;Male 和 Female 属于 Person 工厂的产品。所以需要实现 2 个工厂类:Animal 和 Person。

由于工厂类上面还有个超级工厂,为了方便工厂类生产实体,工厂类应该提供生产实体的方法接口。

为了更好的约束工厂类的实现,先实现一个抽象工厂类:

class AbstractFactory {
    getPerson() {
        throw new Error("子类请实现接口");
    }
    getAnimal() {
        throw new Error("子类请实现接口");
    }
}

接下来,Animal 和 Dog 实现抽象工厂类(AbstractFactory):

class PersonFactory extends AbstractFactory {
    getPerson(person) {
        person = person.toLocaleLowerCase();
        switch (person) {
            case "male":
                return new Male();
            case "female":
                return new Female();
            default:
                break;
        }
    }
    getAnimal() {
        return null;
    }
}
class AnimalFactory extends AbstractFactory {
    getPerson() {
        return null;
    }
    getAnimal(animal) {
        animal = animal.toLocaleLowerCase();
        switch (animal) {
            case "cat":
                return new Cat();
            case "dog":
                return new Dog();
            default:
                break;
        }
    }
}

实现“超级工厂”

超级工厂的实现没什么困难,如下所示:

class Factory {
    constructor(choice) {
        choice = choice.toLocaleLowerCase();
        switch (choice) {
            case "person":
                return new PersonFactory();
            case "animal":
                return new AnimalFactory();
            default:
                break;
        }
    }
}

分析小结

优点

  1. 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
  2. 易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
  3. 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中

缺点

  1. 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
  2. 如果要增加一个项目表Project,那么就需要增加三个类,IProject,MySQLProject,OracleProject,还需要改动IFactory,MySQLFactory,OracleFactory才可以完全实现。这样是很糟糕的。编程是门艺术,这样大批量的改动,显然是非常丑陋的做法。

如何改善?

可以使用简单工厂来改进抽象工厂。去除IFactory、MySQLFactory、OracleFactory三个工厂类,用一个DataAcces类代替,用一个简单工厂模式来实现。具体实现代码省略,有兴趣的小伙伴可以自己实现。

使用场景

  1. QQ 换皮肤,一整套一起换。
  2. 生成不同操作系统的程序。

特点

  • 产品族难扩展
  • 产品等级易扩展。