创建型设计模式(下)
简单工厂模式:
1、定义:根据参数的不同返回不同类的实例
2、模式结构:
(1)工厂角色(Factory):实现创建所有实例的内部逻辑
(2)抽象产品角色(Product):所创建的所有对象的父类,负责描述所有实例所共有的公共接口
(3)具体产品角色(ConcreteProduct):创建目标,所有创建的对象都充当这个角色的某个具体类的实例
3、优点:
(1)工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,通过这种做法实现了对责任的分割
(2)客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可
(3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,
在一定程度上提高了系统的灵活性
4、缺点:
(1)工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响
(2)在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护
(3)系统扩展困难,一旦添加新产品就不得不修改工厂逻辑
5、适用场景:
(1)工厂类负责创建的对象比较少
(2)客户端只知道传入工厂类的参数,对于如何创建对象不关心
// Abstract Product interface Car { carGreet(): void; } // ConcreteProduct class Moto implements Car { carGreet(): void { console.log("Moto says hello..."); } } class Bike implements Car { carGreet(): void { console.log("Bike says hello..."); } } // Factory class Factory { createCar(carName: string): Car { if (carName === "Moto") return new Moto(); else if (carName === "Bike") return new Bike(); return null; } } let carFactory: Factory = new Factory(); carFactory.createCar("Moto").carGreet(); // Moto says hello... carFactory.createCar("Bike").carGreet(); // Bike says hello...
工厂方法模式:
1、定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中
2、模式结构:
(1)抽象产品(Product):所创建产品的父类,给出一个抽象接口或抽象类,一般由具体产品类具体实现
(2)具体产品(ConcreteProduct):抽象产品类的实现类,为实现某个具体产品的对象
(3)抽象工厂(Factory):工厂方法模式的核心(简单工厂模式无此抽象类),与应用程序无关。
是具体工厂必须实现的接口或者必须继承的父类
(4)具体工厂(ConcreteFactory):继承抽象工厂类,实现具体业务逻辑
3、优点:
(1)用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名
(2)工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部
(3)使用工厂方法模式的另一个优点是在系统中加入新产品时,
只要添加一个具体工厂和具体产品就可以了,完全符合“开闭原则”
注:开闭原则,对于扩展是开放的,对于修改是关闭
4、缺点:
(1)在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类
(2)由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,
增加了系统的抽象性和理解难度
5、适用场景:
(1)一个类不知道它所需要的对象的类
(2)一个类通过其子类来指定创建哪个对象
(3)将创建对象的任务委托给多个工厂子类中的某一个,需要时动态指定
// 抽象产品 abstract class Animal { abstract speak(): void; abstract leg(): void; } // 具体产品 class Cat extends Animal { speak(): void { console.log("miao miao miao"); } leg(): void { console.log("cat has four legs"); } } class Dog extends Animal { speak(): void { console.log("wang wang wang"); } leg(): void { console.log("dog has four legs") } } // 抽象工厂 abstract class AnimalFactor { abstract createAnimal(): Animal; } // 具体工厂 class CatFactor extends AnimalFactor { createAnimal(): Animal{ let cat: Cat = new Cat(); return cat; } } class DogFactory extends AnimalFactor { createAnimal(): Animal { let dog: Dog = new Dog(); return dog; } } let animal: AnimalFactor = new CatFactor(); animal.createAnimal().speak(); animal.createAnimal().leg(); animal = new DogFactory(); animal.createAnimal().speak();
抽象工厂模式:
1、定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类
2、模式结构:
(1)抽象工厂(AbstractFactory):声明生成抽象产品的方法
(2)具体工厂(ConcreteFactory):实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,
这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中
(3)抽象产品(AbstractProduct):为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法
(4)具体产品(Product):定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法
注:
(1)产品等级结构:即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,
3、优点:
(1)抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建
(2)当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
(3)增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”
4、缺点:
(1)在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品
(2)“开闭原则”的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)
5、适用场景:
(1)系统中有多于一个的产品族,而每次只使用其中某一产品族
(2)属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来
(3)系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
注:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的
// 抽象产品 abstract class Mouse { abstract sayHi(): void; } abstract class Keybo { abstract sayHi(): void; } // 抽象工厂 abstract class PCFactory { abstract createMouse(): Mouse; abstract createKeybo(): Keybo; } // 具体产品 class DellMouse extends Mouse { sayHi() { console.log("DellMouse say hi"); } } class HpMouse extends Mouse { sayHi() { console.log("HpMouse say hi"); } } class DellKeybo extends Keybo { sayHi() { console.log("DellKeybo say hi"); } } class HpKeybo extends Keybo { sayHi() { console.log("HpKeybo say hi"); } } // 具体工厂 class DellFactory extends PCFactory { createMouse() { return new DellMouse(); } createKeybo() { return new DellKeybo(); } } class HPFactory extends PCFactory { createMouse() { return new HpMouse(); } createKeybo() { return new HpKeybo(); } } let dell: DellFactory = new DellFactory(); let hp: HPFactory = new HPFactory(); dell.createMouse().sayHi(); // DellMouse say hi dell.createKeybo().sayHi(); // DellKeybo say hi hp.createMouse().sayHi(); // HpMouse say hi hp.createKeybo().sayHi(); // HpKeybo say hi