工厂方法和抽象工厂
一般来说我们都会用 new 操作符直接创建对象,这本身没什么问题,但是当我们的系统存在很多的具体类,实例化哪个取决于运行时的一些条件。比如根据类型创建不同的产品
if (a) {
return new ProductA()
} else if (b) {
return new ProductB()
} else if (xxx) {
//.......if more concrete class
}
如果系统内新增一个具体类的时候,我们就需要更改代码,这样的代码显然不具备伸缩性和可维护性,违反了编程中很重要的开闭原则:对扩展开放但是对修改封闭
客户代码耦合具体类型
如何解决这个问题,很容易的我们想到将对象的创建过程单独出来,比如有个 createProduct 方法,专职创建我们需要的对象,这是最简单的工厂模式的体现,但是依旧解决不了创建者耦合具体类的问题。
依赖倒置原则提醒我们创建对象的时候要避免依赖具体类型,而是依赖抽象,我们可以在超类里声明一个抽象的创建方法,返回的是关于创建对象的抽象,然后各个子类去实现这个创建方法,子类当然知道自己需要实例化哪个类型,而客户代码并不依赖具体类型,而是依赖抽象(向上转型),当我们扩展新的具体类,并不需要更改客户的代码,完成了客户代码与具体类的解耦
代码示例:
/**
* A factory method handles object creation and encapsulates it in a subclass.
* This decouples the client code in the superclass from the object creation code in the subclass.
* excerpt From: Eric Freeman. “Head First Design Patterns.” Apple Books.
*/
abstract class PizzaStore {
public orderPizza(type:string):Pizza {
const pizza = this.createPizza(type)
pizza.prepare()
pizza.cut()
return pizza
}
abstract createPizza(type:string):Pizza;
}
abstract class Pizza {
name!:string
prepare():void{
console.log(`preparing ${this.name} pizza`);
}
cut():void {
console.log('cuting into squares');
}
}
class NewYorkStyleCheesePizza extends Pizza {
name:string
constructor(){
super()
this.name = "NewYork Style Cheese Pizza 🧀🧀🧀🧀"
}
}
class NewYorkStyleVeggiePizza extends Pizza {
name:string
constructor(){
super()
this.name = "NewYork Style Veggie Pizza 🥦🥦🥦🥦"
}
}
class NewYorkPizzaStore extends PizzaStore {
createPizza(type:string):Pizza{
if(type === 'cheese'){
return new NewYorkStyleCheesePizza()
}
if(type === 'veggie'){
return new NewYorkStyleVeggiePizza()
}
return new NewYorkStyleCheesePizza()
}
}
class TokyoStyelCheesePizza extends Pizza {
name:string
constructor() {
super()
this.name = "Tokyo 🇯🇵 Style Cheese Pizza"
}
}
class TokyoPizzaStore extends PizzaStore {
createPizza(type:string):Pizza{
console.log(type);
return new TokyoStyelCheesePizza()
}
}
//client code
const newYorkPizzaStore = new NewYorkPizzaStore()
const tokyoPizzaStore = new TokyoPizzaStore()
newYorkPizzaStore.orderPizza('cheese')
newYorkPizzaStore.orderPizza('veggie')
tokyoPizzaStore.orderPizza("cheese")