概述
面向对象的核心就是类和对象,在正式进入工厂模式之前,我们不妨先来认识下三大类设计模式。
- 创建型:简单工厂模式、工厂方法、抽象工厂模式、建造者模式、单例模式
- 结构型:适配器模式、桥接模式、装饰模式、外观模式、享元模式、代理模式
- 行为型:命令模式、中介者模式、观察者模式、状态模式、策略模式
而这三大类设计模式也分别针对三类问题:
- 创建型:如何创建对象
- 结构型:如何将零散的类和对象组合成为更强大的结构
- 行为型:类与对象之间的行为分配
一、「创建型」设计模式
建议通过 3W 模型来学习设计模式:
- What: 是什么?
- Why:为什么?
- How:怎么做?
对应起来则是:
1.「创建型」设计模式是什么?
创建型设计模式包含工厂模式、建造者模式、单例模式、原型模式
2.为什么使用「创建型」设计模式
- 只使用 new 来直接创建对象并不妥,尤其是针对于复杂应用时
- 同样是创建对象,理应有更”优雅“的创建方式
- 当创建对象时,「创建型」设计模式就会给予你灵感
3.如何使用「创建型」设计模式
- 掌握并熟练运用工厂模式
- 熟悉并熟练运用建造者模式
- 熟悉并熟练运用单例模式
- 熟悉并熟练运用原型模式
想要熟练掌握并运用好「创建型」设计模式,离不开对每个设计模式的掌握,那么本篇将会通过一个简化版的图形标注器功能来和大家一起探索 TypeScript 中工厂模式的实践。
二、简单工厂模式
图形标注器是一个比较复杂的组件,一般来说会包含椭圆画笔、矩形画笔和多边形画笔,这三种画笔分别对应三种图形的绘制。
不妨假设这三种画笔分别对应三个类
// 用来继承的抽象画笔父类
abstract class Pencil {
abstract draw();
}
// 椭圆
class EllipsePencil extends Pencil {
draw() {
// ...
}
}
// 矩形
class RectanglePencil extends Pencil {
draw() {
// ...
}
}
// 多边形
class PolygonPencil extends Pencil {
draw() {
// ...
}
}
创建对象时,我们依据通过传递参数的形式来创建不同的对象
class SimpleFactory {
createPencil(type: string) {
if( type === 'rectangle' ) {
return new RectanglePencil();
} else if ( type === 'ellipse' ) {
return new EllipsePencil();
} else if ( type === 'polygon' ) {
return new PolygonPencil();
}
}
}
在客户端中调用简单工厂
// 使用了简单工厂的客户端:
const factory = new SimpleFactory();
const pencil = factory.createPencil('rectangle');
如果我们不使用简单工厂模式,而是在客户端中直接调用对应的类,大概长这个样子:
// 未使用简单工厂的客户端:
// 当需要矩形画笔时
const rectanglePencil = new RectanglePencil();
// 当需要椭圆画笔时
const ellipsePencil = new EllipsePencil();
// 当需要多边形画笔时
const polygonPencil = new PolygonPencil();
经过对比,我们不难发现简单工厂的一些特点:
1.简单工厂必须包含必要的判断逻辑
在 SimpleFactory 的 createPencil() 方法中,通过传入不同的类型来返回具体需要创建的对象。
2.客户端无需知道需要创建的具体类,只需要知道传入的参数就可以了
对于客户端来说,根本无需关心具体是由哪个画笔类创建的对象,只需要关心自己传入什么参数可以拿到这些对象就可以了。
3.新增的配置也无需修改客户端的代码
如果需要新增直线画笔 LinePencil 类,根本无需对客户端代码做修改,只需要对简单工厂内部做修改就可以了。
三、工厂方法模式
但是简单工厂模式暴露出一个问题,如果我们不断的新增一些画笔类型,那么每次都要在简单工厂内部新增判断条件。有没有什么方法不需要改变已有代码,而是可以更好的扩展它呢?
我们可以创建多个工厂,每个工厂负责一种对象的创建,而核心的工厂类只用于继承而
abstract class Factory {
abstract createPencil();
}
class RectangleFactory extends Factory {
createPencil() {
return new RectanglePencil();
}
}
class EllipseFactory extends Factory {
createPencil() {
return new EllipsePencil()
}
}
class PolygonFactory extends Factory {
createPencil() {
return new PolygonPencil();
}
}
在客户端代码中,我们如果想要创建多边形画笔,只需要这样做:
const factory: Factory = PolygonFactory();
const pencil = factory.createPencil();
如果我们想要额外新增一个直线画笔,那么只需要新增对应的工厂和直线画笔类就可以了
class LinePencil extends Pencil {
draw() {
// ...
}
}
class LineFactory extends Factory {
createPencil() {
return new LinePencil();
}
}
在客户端中创建时,修改具体的创建工厂就可以了
const factory: Factory = LineFactory(); // 修改为创建直线画笔的工厂
const pencil = factory.createPencil();
对比简单工厂模式,我们使用多态的方式消除了 if else 这类代码,新增不同的画笔工厂也不需要修改已有的工厂代码,而是直接添加新的工厂就可以了。
四、抽象工厂模式
一个工厂往往不会生产一种产品,一个矩形画笔可能是画矩形框,也有可能画矩形遮罩,这也就意味着父类 Factory 除了包含 createPencil() 方法以外,还会包含 createMask() 方法。
针对创建遮罩功能,我们定义一些新的类
abstract class Mask {
abstract draw();
}
class RectangleMask extends Mask {
draw() {
// ...
}
}
class EllipseMask extends Mask {
draw() {
// ...
}
}
class PolygonMask extends Mask {
draw() {
// ...
}
}
我们再更新下 Factory 父类
abstract class Factory {
abstract createPencil();
abstract createMask();
}
子类也要添加相应的方法
class RectangleFactory extends Factory {
createPencil() {
return new RectanglePencil();
}
createMask() {
return new RectangleMask();
}
}
class EllipseFactory extends Factory {
createPencil() {
return new EllipsePencil()
}
createMask() {
return new EllipseMask();
}
}
class PolygonFactory extends Factory {
createPencil() {
return new PolygonPencil();
}
createMask() {
return new PolygonMask();
}
}
如果客户端中需要创建遮罩,调用对应工厂的方法就可以了
const factory: Factory = new RectangleFactory();
const mask = factory.createMask(); // 创建遮罩
一般什么时候会用到抽象工厂呢?
- 如果想要创建的对象关联关系小,但是却具有相同的约束关系,那么就可以使用抽象工厂。
- 系统中包含多个产品,但是一次只会用到一个产品,例如在本例中客户端不会既画矩形又画椭圆。
- 系统只提供一个产品类的库,所有的产品会以同样的接口出现,从而客户端不依赖于具体实现。
最后
以上就是狂野项链为你收集整理的设计一个矩形类rectangle_TypeScript 设计模式与重构技巧 · 工厂模式的全部内容,希望文章能够帮你解决设计一个矩形类rectangle_TypeScript 设计模式与重构技巧 · 工厂模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复