延续上一篇文章的例子,我们除了想要训练出 baseball player 之外,也希望他能够同时拥有一些装备,像是合适的棒球衣以及棒球鞋。
所以这里我们在 BaseballPlayer
当中加上 clothes 和 shoes 属性。同时为了举例,分别提供了一些细节
class BaseballPlayer {
private name: string
private clothes = {
details: 'baseball clothes'
}
private shoes = {
details: 'baseball clothes'
}
constructor(name: string){
this.name = name
}
showEquipments(): void {
console.log(`${this.name} has ${this.clothes.details} and ${this.shoes.details}`)
}
}
实际执行结果如下
const jeter = new BaseballPlayer2('jeter')
jeter.showEquipments() // jeter has baseball clothes and baseball shoes
这时 tennis player 同样也需要一套适合的运动衣和运动鞋,所以我们就可以复制上面的做法得到结果。
但这时候就会思考,好像每个运动选手都需要运动衣与运动鞋,我们可以怎麽「集中管理」运动装备的生产,并依据不同运动员的需求,给予不同的实际产品呢?
步骤 1:先让我们把运动衣和运动鞋给抽象出来
abstract class Clothes {
abstract details: string;
}
abstract class Shoes {
abstract details: string;
}
步骤 2:建立专属於 baseball player 专属的运动衣和运动鞋类别
class BaseballClothes extends Clothes {
constructor(){
super()
}
details = 'baseball clothes'
}
class BaseballShoes extends Shoes {
constructor(){
super()
}
details = 'baseball shoes'
}
步骤 3:建立完「产品范本」之後,让我们开始建立工厂。首先同样先把我们想要的工厂的样子抽象出来。在这个 EquipmentFactory
当中,我希望他具备生产运动衣和运动鞋的方法
abstract class EquipmentFactory {
abstract produceClothes(): Clothes;
abstract produceShoes(): Shoes;
}
步骤 4:建立专门生产 baseball player 装备的工厂 BaseballEquipmentFactory
并放入实作产品的方法。
class BaseballEquipmentFactory extends EquipmentFactory {
constructor(){
super()
}
produceClothes(): Clothes {
return new BaseballClothes()
}
produceShoes(): Shoes {
return new BaseballShoes()
}
}
步骤 5:最後,使用者可已透过 BaseballEquipmentFactory
,来生产出我们期待中的产品
class BaseballPlayer {
private name: string
private baseballEquipmentFactory = new BaseballEquipmentFactory()
private clothes = this.baseballEquipmentFactory.produceClothes()
private shoes = this.baseballEquipmentFactory.produceShoes()
constructor(name: string){
this.name = name
}
showEquipments(): void {
console.log(`${this.name} has ${this.clothes.details} and ${this.shoes.details}`)
}
}
得到同样的结果
const jeter = new BaseballPlayer('jeter')
jeter.showEquipments() // jeter has baseball clothes and baseball shoes
这里整理一下我们刚刚做的事情:
当然,我们也可以为网球选手做同样的事情:
class TennisClothes extends Clothes {
constructor(){
super()
}
details = 'tennis clothes'
}
class TennisShoes extends Shoes {
constructor(){
super()
}
details = 'tennis shoes'
}
class TennisEquipmentFactory extends EquipmentFactory {
constructor(){
super()
}
produceClothes(): Clothes {
return new TennisClothes()
}
produceShoes(): Shoes {
return new TennisShoes()
}
}
class TennisPlayer {
tennisEquipmentFactory = new TennisEquipmentFactory()
private name: string
private clothes = this.tennisEquipmentFactory.produceClothes()
private shoes = this.tennisEquipmentFactory.produceShoes()
constructor(name: string){
this.name = name
}
showEquipments(): void {
console.log(`${this.name} has ${this.clothes.details} and ${this.shoes.details}`)
}
}
得到结果
const federer = new TennisPlayer('federer')
federer.showEquipments() // federer has tennis clothes and tennis shoes
上面这样的模式,就是抽象工厂模式。这里要注意的是,不是用 abstract 宣告工厂类别就是抽象工厂。
抽象工厂的重点在於,能够帮助我们快速建立一系列的产品,譬如棒球衣和棒球鞋、网球衣和网球鞋。虽然这这些产品之前可能没有关系(衣服和鞋子),不过我们可以透过抽象工厂,将它们组合在一起
抽象工厂模式的优点在於,能够让使用者只要透过一个工厂,就能够得到系列产品。另一方面,当我们定义好系列产品的样子之後,就可以扩张成不同系列,譬如从原本的棒球系列,拓展的篮球系列、足球系列等等。
但是缺点在於,如果我们要拓展系列本身,譬如从原本的「衣服 + 鞋子」,变成「衣服 + 鞋子 + 帽子」,那麽就会牵一发动全身,所有不同系列(棒球、网球、篮球 ... 等)的实作工厂都要同时变动。
如果系列本身只有一个产品,譬如我只做衣服产品(棒球衣、网球衣、足球衣),那麽其实就跟原本的工厂模式一样,就不需要使用到抽象工厂模式。
另一方面,如果只有一种系列要做,譬如我只想做棒球系列(棒球衣、棒球鞋、棒球帽),那麽甚至我们可以直接使用简单工厂,让使用者传入参数(订单),然後直接产出他们需要的产品即可。不需要考虑到任何扩张的情境。
<<: Angular 深入浅出三十天:表单与测试 Day19 - 与 Cypress 的初次见面(下)
>>: Day19 - 写出更有品质的程序码,信 eslint 得永生
. 根据NIST术语表,安全功能是指系统级别的“系统或系统元素提供的功能” 。 . 独立安全审核的...
如果想要将从 line 上蒐集到的资料或数据呈现在自己的网页上,我们可以使用 flask 建立好网页...
#16. Quiz App 所谓Quiz App就是提供给用户答题的小应用,包含数个选择题,选完一个...
作天已经教大家列表的基础用法,今天要来教大家稍微金皆一点的,然後预告一下过几天可能就会进入到运用还有...
1.JS是什麽? Java Script 是一种运行在客户端的脚本语言 (script就是脚本的意思...