0
点赞
收藏
分享

微信扫一扫

软考架构-论文练手草稿(设计模式-正文)

本文结合笔者的实际工作经验,主要论述软件设计模式在该项目中的具体应用。该项目是前后端分离,在各模块的后端代码中我们大量使用了decorator装饰器模式,如认证、权限、日志等,可以动态地对某个对象增加新功能;在监控模块的告警功能上,我们使用了strategy策略模式,这样可灵活地使用用户指定的方式发告警信息,如钉钉|短信|电话语音等;在连接数据库方面我们使用了pool对象池模式,可避免频繁创建TCP连接浪费服务器资源。通过使用这些设计模式,提高了软件的设计质量和开发效率,最终项目顺利上线,获得用户一致好评。


由于传统的结构化的软件设计方法不符合面向对象的设计原则,无法很好地实现高内聚低耦合的要求,模块之间过于紧密,给软件扩展和维护带来很多困难,这种情况下设计模式的出现和广泛应用给问题的解决提供了一种有效的方法,通过利用设计模式,可帮助开发者利用已有的设计方法,设计出结构合理、易于复用和可维护的软件,当用户需求发生改变时,可通过修改少量代码或不修改原有代码即可满足新的需求,增强了系统的可修改性和稳定性,降低系统开发成本。一般一个设计模式具有模式名称、适应场景、解决方案、效果这4个方面的基本要素,设计模式依据其目的可分为创建型、结构型、行为型三种类型。创建型模式,主要负责对象的创建工作,程序在确定需要创建对象时,可获得更大的灵活性,常用的创建型模式有:singleton单例、abstract factory抽象工厂、prototype原型、builder构建器、factory method、pool对象池等;结构型模式,负责处理类或对象之间的关系,用于构建结构更为复杂庞大的系统,常用的结构型设计模式有facade|bridge|composite|flyweight|proxy|adapter|decorator等,行为型模式,主要任务是对类或对象如何交互及类和对象分配具体职责进行描述,常用的行为型模式有:observer|template method|iterator|stragegy|chain of reposibility|command|interpreter|visitor|mediator|memento|state等。这些设计方法是经过反复使用的成熟的方法,对优化软件结构、提高软件质量具有重要的指导意义。


decorator,属结构型,可动态地给一个对象添加一些额外的职责,它提供了用子类扩展功能的一个灵活替代,比派生一个子类更加灵活;是AOP面向切面编程思想的体现,在需要的类或方法上切下,前后的切入点可加入增强的功能,让调用者和被调用者解耦;这是一种不修改原来的业务代码,给程序动态添加功能的技术。我们在各模块的后端代码大量使用了decorator模式,如认证、权限、日志(、及py内置的@property类属性@classmethod类方法)等,以认证为例用@login_required装饰函数视图对象或用@method_decorator(login_required)装饰类对象,实现仅允许已登录用户可访问某页面数据,login_required函数里的代码逻辑就是验证用户是否登录,而其它所有业务函数应把与验证用户是否登录这个功能剥离干净;用@csrf_exempt实现展示前端调用后端接口时免除csrf校验。以函数装饰器为例主要用了嵌套函数、柯里化和闭包的思想,具体实现是,外部函数把被包装函数作为参数传进来,内部函数通过闭包把被包装函数作为对象调用,调用前后可以加上新的逻辑,然后内部函数返回执行后的被包装函数的结果,外部函数返回内部函数的引用。使用这种设计模式我们发现,使代码更简洁,每个函数各自只需完成自己的逻辑部分即可,利用py的@这种特有语法使得增强功能实现更容易。类装饰器则用了__call__()魔术方法。


strategy,属行为型,定义一系列算法,把它们一个个封装起来,并且使它们之间可互相替换,从而让算法可独立于使用它的用户而变化。在监控模块的告警功能上,我们监控的各软件的前端界面上可由用户配置接收告警信息的方式,例如默认钉钉另有短信、微信、电话语音,定时任务在监控到有异常且满足发告警的情况下,后端代码会获取到用户配置的信息,根据配置信息调用指定的策略发送告警信息,具体实现是,先抽象出基类class AlarmSender,子类扩展基类class DingSender(AlarmSender)、class SMSSender(AlarmSender)等,并在子类中定义具体实现def send(self, info),假设当前有RabbitMQ告警且用户配置的是默认钉钉方式,则在发告警时的代码为先实例化mq_ins = MQInfo(info='告警内容', way=[DingSender]),way为具体的发告警的方式,再调用mq_ins.way.send(info)完成发送告警。使用这种模式我们发现,发告警的方式(即算法)可自由切换,将发告警的类名作为参数传入即可,这也是依赖抽象类设计接口的好处之一,还减少代码冗余,扩展性好,移植方便,使用灵活。


pool对象池模式,属创建型,在github的python-patterns中将此模式单列出来,而一些书籍将此模式归为singleton,原理上相通,即将单例引申为仅能创建指定数目的实例。预设或维护一组相同类型的实例,常用于数据库连接池、线程池、进程池等,连接池主要负责分配、管理和释放连接,它允许应用程序重复使用连接池中空闲的连接,而不是重新建立一个,这项技术能明显提高对数据库操作的性能。我们以数据库连接池为例,应用程序连接数据库时,一个请求就会和后端DB进行一次TCP连接,TCP连接代价是高昂的,连接时要3次握手断开时4次挥手,当前端请求很多时,后台数据库服务器承受不了大量的连接,用连接池就可解决这种频繁创建连接的场景,我们经研究发现,既要控制数据库的连接数,又要保证线程安全,同时要保证web的并发,最终的解决方案是DB连接池,我们使用pymysql+DBUtils模块实现,DBUtils有2种模式,DBUtils.PooledDB这种模式在连接池中创建一批连接供所有线程共享使用,而DBUtils.PersistentDB这种模式需要自己控制线程数量,经分析我们采用PooledDB更方便管理,使用POOL = PooledDB(creator=pymysql, maxconnections=10, mincached=2, maxcached=5, host='', port='', user='', password='', database='', charset='utf8'),createor指定链接DB的模块,maxconnections连接池允许最大连接数等主要参数,conn = POOL.connection()接着用with conn.cursor() as cur进行上下文管理使用。经过在项目中使用,DB连接池能统一管理连接,可在保证应用的并发,同时又不会给DB server很大压力,能明显提高对DB的操作性能。


举报

相关推荐

0 条评论