创造性设计模式 => 工厂模式 => 工厂方法模式上车
工厂模式的定义: 工厂模式定义创造对象的接口, 但是让子类去真正的实例化, 也就是工厂方法将类的实例化延迟到子类
光看文字可能其实没什么感觉, 那笔者来举个栗子
相信飞机大战这个游戏大家都有玩过, 里面会有很多中不同的飞机, 每个飞机的能力都不太一样但是他们也有相似的地方, 拿到前端中来说如果要我们写一个飞机大战, 我们如何来创建这些飞机呢?
// 如果是新手的话, 应该是这样创建
var smallPlane = {
color: 'red',
size: 500,
power: 0.5,
blood: 100,
touch: function() {
this.blood -= 50;
if(this.blood == 0) {
console.log('game over');
}
}
}
var bigPlane = {
color: 'blue',
size: 700,
power: 0.7,
blood: 150,
touch: function() {
this.blood -= 50;
if(this.blood == 0) {
console.log('game over');
}
}
}
// 新手可能会无限的去重复复制飞机的对象, 那么假设有几十个飞机的话 那要copy几十个, 不用讲都能明白这种方法肯定有问题
// 可能又会有朋友说到构造函数, 没错 构造函数确实是大多数人会用的方法了
function Plane(color, size, power, blood) {
this.color = color;
this.size = size;
this.power = power;
this.blood = blood;
this.touch = function() {
this.blood -= 50;
if(this.blood == 0) {
console.log('game over');
}
}
}
var smallPlane = new Plane('red', 500, 0.5, 100);
var bigPlane = new Plane('blue', 700, 0.7, 150);
// 这样的操作也确实解决了我们重复代码过多的问题, 但是现在我有一个需求, 大飞机有一个获得特殊技能的方法,getSkill, 调用这个方法可以直接将血量提升百分之五十, 但是小飞机没有这个方法, 我们应该怎么实现呢? 在Plane原型上写吗? 那样小飞机上也会获得这个方法
// 笔者来写一份代码来迎合一下工厂模式的思想
function PlaneFactory(type) {
let _Plane = null;
let _planeTypes = {
'smallPlane': () => _Plane = SmallPlane,
'bigPlane': () => _Plane = BigPlane
}
_planeTypes[type]();
_Plane.prototype.touch = () => {
this.blood -= 50;
}
return new _Plane();
}
function SmallPlane() {
this.width = 100;
this.height = 100;
this.name = 'smallPlane',
this.blood = 100;
this.touch = function () {
this.blood -= 100;
if (this.blood === 0) {
console.log('die');
}
}
}
BigPlane.prototype.attackSkill = function () {
console.log('特殊技能');
}
function BigPlane() {
this.width = 150;
this.height = 150;
this.name = 'smallPlane',
this.blood = 100;
}
我们来对比一下笔者写的简单的迎合工厂模式思想的代码和普通代码的区别
- 工厂类中集中了所有对象的创建, 便于对象创建的统一管理
- 对象的使用者仅仅是使用产品, 实现了单一职责原则
- 便于扩展, 如果是新增了一种业务, 只需要增加相关的业务对象类和工厂类中的生产业务对象的方法, 不需要修改其他的地方
- 也确实违反了开闭原则
所以简单工厂模式是存在缺陷的, 于是我们引进工厂方法模式**
工厂方法模式: 不再有唯一的工厂类去创建产品, 而是将不同的产品交付给对应的工厂子类去实现, 每个产品由负责生产的子工厂来创造, 如果添加新的产品, 需要做的就是添加新的子工厂和产品, 而不需要修改其他的工厂代码。
工厂方法模式组成
- 抽象工厂类: 负责定义创建产品的公共接口
- 产品子工厂: 继承抽象工厂类, 实现抽象工厂类提供的接口
- 每一种产品有各自的产品类
概念也说的差不多了, 废话少说直接刚代码
function PlaneFactory() {
this.touch = function () {
this.blood -= 50;
if (this.blood === 0) {
console.log('die');
}
}
}
// 创造飞机工厂
PlaneFactory.create = function (type) {
if (PlaneFactory.prototype[type] == undefined) {
throw new Error('没有该种类的飞机');
}
if (PlaneFactory.prototype[type].prototype.__proto__ != PlaneFactory.prototype) {
PlaneFactory.prototype[type].prototype = new PlaneFactory();
}
let arg = [].slice.call(arguments, 1);
console.log(arg);
const newPlane = new PlaneFactory.prototype[type](...arg);
return newPlane;
}
// 真正定义子工厂
PlaneFactory.prototype.SmallPlane = function (x, y) {
this.width = 100;
this.height = 100;
this.x = x;
this.y = y;
this.blood = 100;
}
PlaneFactory.prototype.BigPlane = function (x, y) {
this.width = 200;
this.height = 200;
this.x = x;
this.y = y;
this.blood = 200;
this.attackSkill = function () {
console.log('特殊技能');
}
}
let newPlane = PlaneFactory.create('SmallPlane', 10, 20);
console.log(newPlane);
工厂方法模式会比工厂模式代码复杂一些, 引入了抽象层, 还有子工厂, 这会增加代码的难度和复杂度, 但是相比于简单工厂模式, 代码的维护性和扩展性大大提高, 由于把原型暴露出来, 所以扩展时我们势必只需要在原型上添加一个新的方法就够了, 不需要修改到抽象工厂和其他子工厂, 更加符合面向对象的开发和开闭原则
来源:CSDN
作者:付金权
链接:https://blog.csdn.net/weixin_44238796/article/details/104258940