抽象工厂模式
首发于:2022-03-22
基本概念
抽象工厂(Abstract Factory):通过对类的工厂抽象使其业务用于对产品类簇的创建,而不是负责创建某一类产品的实例。关键在于使用抽象类制定了实例的结构,调用者直接面向实例的结构编程,从实例的具体实现中解耦。
现实生活中的例子
还是上次那个饭店的例子,当然饭店可以有很多个,也不一定非要去这一家,而每一家饭店又都有自己的特色菜,饭店有菜,有汤,还有面食等各种这样的食物,菜都可以吃,汤都可以喝,面都可以嗦。
上面的场景都属于抽象工厂的场景,食物可以被抽象,饭店也可以被抽象。
应用场景
如果一组实例都有相同的结构,那么就可以使用抽象工厂模式。
优缺点
优点:
- 抽象产品类将产品的结构抽象出来,访问者不需要知道产品的具体实现,只需要面向产品的结构编程即可,从产品的具体实现中解耦;
缺点:
- 扩展新类簇的产品类比较困难,因为需要创建新的抽象产品类,并且还要修改工厂类,违反开闭原则;
- 带来了系统复杂度,增加了新的类,和新的继承关系;
实现
抽象工厂创建饭店
因为 js 没有抽象类,所以用 ts 来实现。
ts
abstract class Restaurant {
name: string = '';
menu: Record<string, Dish> = {};
order(name: string) {
if (this.menu[name]) {
return this.menu[name];
}
console.log('没这个菜了');
return null;
}
addMenu(name: string, food: Food) {
this.menu[name] = food;
}
}
abstract class Food {
name: string = '';
eatMethod: string = 'eat';
eat() {
console.log(`${this.eatMethod} ${this.name}`);
}
}
class Dish extends Food {
constructor() {
super();
this.name = '小炒黄牛肉';
}
}
class Soup extends Food {
constructor() {
super();
this.eatMethod = 'drink';
this.name = '紫菜蛋花汤';
}
}
class Noodle extends Food {
constructor() {
super();
this.eatMethod = 'suck';
this.name = '阳春面';
}
}
class Restaurant1 extends Restaurant{
constructor(name: string) {
super();
this.name = name;
}
}
class Restaurant2 extends Restaurant{
constructor(name: string) {
super();
this.name = '高级饭店' + name;
}
}
const r1 = new Restaurant1('r1');
console.log(r1.name);
r1.addMenu('yangchunmian', new Noodle());
r1.addMenu('xiaochaohuangniurou', new Dish());
r1.addMenu('zicaidanhuatang', new Soup());
r1.order('yangchunmian')?.eat();
r1.order('xiaochaohuangniurou')?.eat();
r1.order('yuxiangrousi')?.eat();
const r2 = new Restaurant2('r2');
console.log(r2.name);
r2.addMenu('yangchunmian', new Noodle());
r2.addMenu('xiaochaohuangniurou', new Dish());
r2.addMenu('zicaidanhuatang', new Soup());
r2.order('yangchunmian')?.eat();
r2.order('xiaochaohuangniurou')?.eat();
r2.order('zicaidanhuatang')?.eat();