前言:
设计模式就像是能针对特定问题的大招或者组合技,在解决特定问题上能有非常好的效果
所以设计模式都是为了方便开发、后续拓展来使用的
但如果不考虑实际应用,直接就上设计模式的话,会增加不必要的代码复杂度,反而影响开发、阅读和后续维护
下面记录下来几种比较常用的设计模式,以供以后需要的时候可以直接拿来用:
工厂模式(Factory Pattern)
工厂模式创造了一个专门用来生成对象的工厂类,当需要特定对象时,由工厂类来决定具体实例化哪一对象
工厂模式分为3种:
1:简单工厂模式(单一工厂类生产多种对象)
2:工厂模式(n个工厂生成n个对象)
3:抽象工厂模式
工厂模式介绍和简单工厂模式实现:
https://www.jianshu.com/p/72567cc1d63f
解决了什么问题:
当创建对象变得很复杂,或者创建对象需要涉及多个其它对象并且需要在多个地方创建实例时,需要用到工厂模式来进一步封装
实现代码的解耦,方便后续修改
建造者模式(Builder Pattern)
在创建对象时,将赋予其属性的方式包装起来,链式的赋予属性,最后创建对象
// 省略 getter 和 setter 方法
public class Computer {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Computer(String cpu, String screen, String memory, String mainboard) {
this.cpu = cpu;
this.screen = screen;
this.memory = memory;
this.mainboard = mainboard;
}
}
public class NewComputer {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public NewComputer() {
throw new RuntimeException(“can’t init”);
}
private NewComputer(Builder builder) {
cpu = builder.cpu;
screen = builder.screen;
memory = builder.memory;
mainboard = builder.mainboard;
}
public static final class Builder {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Builder() {}
public Builder cpu(String val) {
cpu = val;
return this;
}
public Builder screen(String val) {
screen = val;
return this;
}
public Builder memory(String val) {
memory = val;
return this;
}
public Builder mainboard(String val) {
mainboard = val;
return this;
}
public NewComputer build() {
return new NewComputer(this);}
}
}
public class Click {
public static void main(String[] args) {
// 非 Builder 模式
Computer computer = new Computer(“cpu”, “screen”, “memory”, “mainboard”);
// Builder 模式
NewComputer newComputer = new NewComputer.Builder()
.cpu(“cpu”)
.screen(“screen”)
.memory(“memory”)
.mainboard(“mainboard”)
.build();
}
}
解决了什么问题:
能解决当创建对象的参数比较多,而且需要一次创建一个完整的对象
在这种情况下使用建造者模式能更清晰的看到具体参数
并且能很方便的创建有多个默认参数的完整对象
但当类属性变多时,会增加代码复杂度
装饰器模式(Decorator Pattern)
就像一件装备,装上能增加类或者函数的功能,例如打印log、检测登录等
下面是我一实际应用,使用python flask
装饰器代码:
def check_user_cookie(re):
"""装饰器,用cookie来检查用户登录"""
def decorator(func):
@functools.wraps(func)
def wrapper(*arg, **kw):
db.session.remove() # 清理flask_sqlalchemy缓存,不清理的话,会导致新加入的数据不能查询出来
cookie = re.cookies.get(app.config['COOKIE_NAME'])
agree = cookie2user(app.config['COOKIE_NAME'], cookie, re.remote_addr)
if not agree:
return render_template('user/login.html')
return func(*arg, **kw)
return wrapper
return decorator
应用代码:
@mod.route('/<table>/delete/<int:item_id>')
@check_user_cookie(request)
def config_delete(table, item_id):
"""删除数据"""
delete_item = tables[table].query.filter_by(ID=item_id).first()
if delete_item:
try:
db.session.delete(delete_item)
db.session.commit()
flash('删除成功!')
except Exception as e:
flash('删除失败,错误信息:%s' % e, category='error')
return redirect(url_for('configtool.config_tool', table=table))
解决了什么问题:
我曾有一次在权限管理功能上的实际应用,场景如下:
某些函数需要审核符合特定的权限才可以使用,所以我写了2个装饰器,一个是普通用户,一个是管理员
某些函数需要验证普通用户权限,某些需要管理员权限
我使用装饰器的话,就可以不在每个函数上面写 if 语句,
这样在使用的时候只需要一行代码,不但阅读清晰
而且在需要修改审核权限逻辑的时候,就不用一个个改了
单例模式(Singleton Pattern)
单例模式指在调用类对象的时候,使用同一个实例
注意在需要的时候考虑多线程的问题(多进程不共享实例)
解决了什么问题:
有一次我一个需要用到情感分析的项目,每次运行程序的时候
都需要根据语料(可能需要更新)训练一个情感模型
这时候我就需要多个线程同时使用这个模型,而不是每次使用都再训练一次,
这时候就需要用到单例模式