设计模式---工厂模式

工厂模式包括简单工厂,工厂方法,抽象工厂,这里分别介绍前后端工厂模式以及示例

(前端)工厂模式

简单工厂

简单工厂模式又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象类的实例,主要用来创建同一类对象
简单工厂在调用return new的时候使用
比如说,在实际的项目中,我们常常需要根据用户的权限来渲染不同的页面,高级权限的用户所拥有的页面有些是无法被低级权限的用户所查看,所以我们可以在不同权限等级用户的构造函数中,保存该用户能够看到的页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let UserFactory = function (role) { 
function SuperAdmin() {
this.name = "超级管理员",
this.viewPage = ['首页', '用户管理', '订单管理', '应用管理', '权限管理']
}
function Admin() {
this.name = "管理员",
this.viewPage = ['首页', '订单管理', '应用管理']
}
function NormalUser() {
this.name = '普通用户',
this.viewPage = ['首页', '订单管理']
}
switch (role) {
case 'superAdmin':
return new SuperAdmin();
break;
case 'admin':
return new Admin();
break;
case 'user':
return new NormalUser();
break;
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user');
}
}
//调用
let superAdmin = UserFactory('superAdmin');
let admin = UserFactory('admin')
let normalUser = UserFactory('user')

总结:在上面的例子中,UserFactory就是一个简单工厂,在该函数中有3个构造函数分别对应不同的权限的用户,当我们调用工厂函数时,只需要传递superAdmin, admin, user这三个可选参数中的一个获取对应的实例对象

优点:

简单工厂的优点在于,你只需要一个正确的参数,就可以获取到你所需要的对象,而无需知道其创建的具体细节;

缺点:

在函数内包含了所有对象的创建逻辑(构造函数)和判断逻辑的代码,每增加新的构造函数还需要修改判断逻辑代码,我们的对象不是上面的3个而是30个或更多时,这个函数会成为一个庞大的超级函数,便得难以维护,简单工厂只能作用于创建的对象数量较少,对象的创建逻辑不复杂时使用;

工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//安全模式创建的工厂方法函数 
let UserFactory = function(role) {
if(this instanceof UserFactory) {
var s = new this[role]();
return s;
} else {
return new UserFactory(role);
}
}
//工厂方法函数的原型中设置所有对象的构造函数
UserFactory.prototype = {
SuperAdmin: function() {
this.name = "超级管理员",
this.viewPage = ['首页', '用户管理', '订单管理', '应用管理', '权限管理']
},
Admin: function() {
this.name = "管理员",
this.viewPage = ['首页', '订单管理', '应用管理']
},
NormalUser: function() {
this.name = '普通用户',
this.viewPage = ['首页', '订单管理']
}
}
//调用
let superAdmin = UserFactory('SuperAdmin');
let admin = UserFactory('Admin')
let normalUser = UserFactory('NormalUser')

总结:在简单工厂中,如果我们新增加一个用户类型,需要修改两个地方的代码,一个是增加新的用户构造函数,一个是在逻辑判断中增加对新的用户的判断,而在抽象工厂方法中,我们只需要在UserFactory.prototype中添加就可以啦。

(后端)工厂模式

(1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern)。

(2)工厂方法(Factory Method)模式,又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式;

(3)抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。

为什么要用工厂模式

(1) 解耦 :把对象的创建和使用的过程分开

(2)降低代码重复: 如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。

(3) 降低维护成本 :由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建某个对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。

适用场景

(1)需要创建的对象较少。

(2)客户端不关心对象的创建过程。

简单工厂

@Override是什么注解

@Override 的作bai用是:如果想重写父类的方du法,比如toString()方法的话zhi,在方法前面加上@Override 系统dao可以帮你检查方法的正确性。

(1)创建Shape接口

1
2
3
public interface Shape {
void draw();
}

(2)创建实现该接口的具体图形类

圆形

1
2
3
4
5
6
7
8
9
public class Circle implements Shape {
public Circle() {
System.out.println("Circle");
}
@Override
public void draw() {
System.out.println("Draw Circle");
}
}

长方形

1
2
3
4
5
6
7
8
9
public class Rectangle implements Shape {
public Rectangle() {
System.out.println("Rectangle");
}
@Override
public void draw() {
System.out.println("Draw Rectangle");
}
}

正方形

1
2
3
4
5
6
7
8
9
10
public class Square implements Shape {
public Square() {
System.out.println("Square");
}

@Override
public void draw() {
System.out.println("Draw Square");
}
}

(3)创建工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ShapeFactory {

// 使用 getShape 方法获取形状类型的对象
public static Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}

(4)测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {

public static void main(String[] args) {

// 获取 Circle 的对象,并调用它的 draw 方法
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();

// 获取 Rectangle 的对象,并调用它的 draw 方法
Shape rectangle = ShapeFactory.getShape("RECTANGLE");
rectangle.draw();

// 获取 Square 的对象,并调用它的 draw 方法
Shape square = ShapeFactory.getShape("SQUARE");
square.draw();
}
}

输出结果:

1
2
3
4
5
6
Circle
Draw Circle
Rectangle
Draw Rectangle
Square
Draw Square

这样的实现有个问题,如果我们新增产品类的话,就需要修改工厂类中的getShape()方法,这很明显不符合 开放-封闭原则 。

工厂方法

上面简单工厂例子中的图形接口以及相关图像实现类不变。我们只需要增加一个工厂接口以及实现这个接口的工厂类即可。

(1)增加一个工厂接口:

1
2
3
public interface Factory {
public Shape getShape();
}

(2)增加相关工厂类:

圆形工厂类

1
2
3
4
5
6
7
8
9
public class CircleFactory implements Factory {

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Circle();
}

}

长方形工厂类

1
2
3
4
5
6
7
8
9
public class RectangleFactory implements Factory{

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Rectangle();
}

}

圆形工厂类

1
2
3
4
5
6
7
8
9
public class SquareFactory implements Factory{

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Square();
}

}

(3)测试:

1
2
3
4
5
6
7
8
9
public class Test {

public static void main(String[] args) {
Factory circlefactory = new CircleFactory();
Shape circle = circlefactory.getShape();
circle.draw();
}

}

输出结果:

1
2
Circle
Draw Circle

适用场景

一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏
将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

抽象工厂

适用场景

和工厂方法一样客户端不需要知道它所创建的对象的类。
需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)
场景:
不知道大家玩过穿越火线或者吃鸡这类游戏了吗,游戏中存在各种枪。我们假设现在存在AK、M4A1两类枪,每一种枪对应一种子弹。我们现在这样考虑生产AK的工厂可以顺便生产AK使用的子弹,生产M4A1的工厂可以顺便生产M4A1使用的子弹。(AK工厂生产AK系列产品包括子弹啊,AK枪的类型啊这些,M4A1工厂同理)

抽象工厂模式实例

(1)创建相关接口:

1
2
3
public interface Gun {
public void shooting();
}

子弹

1
2
3
public interface Bullet {
public void load();
}

(2)创建接口对应实现类:

AK类

1
2
3
4
5
6
7
8
9
public class AK implements Gun{

@Override
public void shooting() {
System.out.println("shooting with AK");

}

}

M4A1类

1
2
3
4
5
6
7
8
9
public class M4A1 implements Gun {

@Override
public void shooting() {
System.out.println("shooting with M4A1");

}

}

AK子弹类

1
2
3
4
5
6
7
8
public class AK_Bullet implements Bullet {

@Override
public void load() {
System.out.println("Load bullets with AK");
}

}

M4A1子弹类

1
2
3
4
5
6
7
8
9
public class M4A1
_Bullet implements Bullet {

@Override
public void load() {
System.out.println("Load bullets with M4A1");
}

}

(3)创建工厂接口

1
2
3
4
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}

(4)创建具体工厂

生产AK和AK子弹的工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AK_Factory implements Factory{

@Override
public Gun produceGun() {
return new AK();
}

@Override
public Bullet produceBullet() {
return new AK_Bullet();
}

}

生产M4A1和M4A1子弹的工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
public class M4A1_Factory implements Factory{

@Override
public Gun produceGun() {
return new M4A1();
}

@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}

}

(5)测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {

public static void main(String[] args) {

Factory factory;
Gun gun;
Bullet bullet;

factory =new AK_Factory();
bullet=factory.produceBullet();
bullet.load();
gun=factory.produceGun();
gun.shooting();

}

}

输出结果:

1
2
Load bullets with AK
shooting with AK

参考文章: https://developer.51cto.com/art/201904/594382.htm
https://www.imooc.com/article/31360

-------------本文结束感谢您的阅读-------------