这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
工厂模式
下面我们学习一些面向对象编程中,一些常用的设计模式,如何在 TS 中实现?
一个设计模式,是能够解决一个问题。我们学设计模式,最重要的是,知道这种设计模式发源于哪;为什么要这么设计;它能够解决什么问题?
那我们先来学习一个最简单的设计模式:工厂模式。
先来看下这个例子:
// 橘子罐头
class CannedOrange {}
// 苹果罐头
class CannedApple {}
// 吃一个罐头
function eatCan(c: CannedApple | CannedOrange) {
}
let o = new CannedOrange();
eatCan(o);
复制代码
我们有几个罐头:橘子罐头、苹果罐头,然后还有一个吃一个罐头的方法,它的输入是其中某一种罐头,接下来,我们创建了一个橘子罐头,然后把它吃了。
从上面这个例子,大家可以看出有什么可以改进的地方吗?
类型定义,比较麻烦,使用到了联合类型,以后每增加一种罐头,都需要再添加一个类型,代码耦合比较高,有没有什么优化方法呢?
我们可以定义一个抽象罐头,所有的罐头都得继承这个抽象罐头。
// 抽象罐头
abstract class Can {}
// 橘子罐头
class CannedOrange extends Can {}
// 苹果罐头
class CannedApple extends Can {}
// 吃一个罐头
function eatCan(c: Can) {
}
let o = new CannedOrange();
eatCan(o);
复制代码
那下面还有什么优化的地方呢?
我们注意到这里我们定义了一个橘子罐头,是直接使用 new 创建出来的,这里的话,就需要我们知道创建的罐头的类的名字是什么,假如这个文件比较大,或者类分布在其他地方,我们在new 的时候,就不知道有哪些罐头可以被创建。
扫描二维码关注公众号,回复:
13294540 查看本文章
这个时候,就可以使用工厂模式,将罐头的创建,放到这个工厂里面,我们来看下这个工厂类,这样的话,就可以实现简单的罐头工厂。
// 抽象罐头
abstract class Can {}
// 橘子罐头
class CannedOrange extends Can {}
// 苹果罐头
class CannedApple extends Can {}
type CanTypes = 'orange' | 'apple';
class CanFactory {
static createCan(CanType: CanTypes) {
if (CanType === 'apple') {
return new CannedApple();
} else if(CanType === 'orange') {
return new CannedOrange();
}
}
}
// 吃一个罐头
function eatCan(c: Can) {
}
let p = CanFactory.createCan('apple');
eatCan(p);
复制代码
下面我们来试一下创建一个罐头,在调用的时候,只要打一个引号,就会提示有哪几种罐头可以创建。这样就解决了之前无法预知罐头名称的问题了。
习题:理解工厂模式,并计算生产编号
class Animal {
private name: string;
private static id = 0;
// 工厂模式车间
constructor(name: string) {
this.name = name;
Animal.id++;
}
getAnimalInfo() {
return `我是火星工厂生产的 ${this.name},生产编号为 ${Animal.id}`;
}
}
new Animal('panda').getAnimalInfo(); // 生产编号为 ?
new Animal('panda').getAnimalInfo(); // 生产编号为 ?
复制代码
答案:1 2
解析:
工厂模式常用的实例化对象模式,用于批量生产对象。
题目使用了工厂模式。大家可以仔细看看哦。解决本题的思路是类的静态属性,所有的实例共享类的静态属性。所有编号分别为 1
,2
。