python工业互联网应用实战7—业务层
本章我们演示代码是如何“进化”的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的“禅”——简单设计、快速发布、获得反馈、快速开发的迭代循环过程,如何保证迭代过程持续交互合格的代码,代码重构和单元测试是非常重要的手段。单元测试用来保证重构的代码先满足原来的测试逻辑,代码结构优化满足新的业务需求扩展,然后开发增加新的功能、新的单元测试,每一轮迭代发布新的功能,获取用户反馈…
上一章功能完成的时候,你发现当前的admin.py已经较早期复杂了,里面包含了较多的功能逻辑代码。文件里有django admin设置需要增加的代码,也有业务逻辑“下达”、“任务分解”的业务功能代码。现场是时候重构和优化我们的代码结构了。把把业务相关的代码纳入到业务层(Biz)层去实现,然后确保功能不变,将来你会发现这一抽象和功能内聚极大的提高了代码的重用性和可扩展性。
1.1. 增加TaskBiz.py类
我们通过IDE环境增加对应的Task Model业务类文件TaskBiz.py,并把Task相关的业务逻辑封装到TaskBiz类下面。
TaskBiz类代码如下(代码会说话):
from .models import Task,Job class TaskBiz(object):
"""description of class""" def task_start(self,obj):
""" 任务变更状态到 运行中 """
success=False
if obj.State==Task.STATE_PROCESSED:
obj.State=Task.STATE_RUNNING
try:
obj.save()
success = True
except Exception:
success = False
return success def task_decompose(self,request,obj):
success=True
try:
job1=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":1,"Source":obj.Source,"Target":'102',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job1.save()
job2=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":2,"Source":None,"Target":'1',"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job2.save()
job3=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":3,"Source":"102","Target":'104',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job3.save()
job4=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":4,"Source":'104',"Target":'103',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job4.save()
job5=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":5,"Source":'1',"Target":'5',"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job5.save()
job6=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":6,"Source":'504',"Target":'503',"Executor":"AGV05","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job6.save()
job7=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":7,"Source":'5',"Target":None,"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job7.save()
job8=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":8,"Source":'503',"Target":'05-01-01',"Executor":"AGV05","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,})
job8.save()
#子任务分解完成,并提交数据库
#更新任务的状态到“处理完成”
obj.State=Task.STATE_PROCESSED
obj.save()
except Exception:
success = False return success
同时,我们修改admin.py的task_decompose和task_start调用方式。
from .TaskBiz import TaskBiz
#Task模型的管理器
class TaskAdmin(admin.ModelAdmin): ... @atomic
def task_start_action(self, request, queryset):
for obj in queryset:
biz= TaskBiz()
result=biz.task_start(obj)
if result:
self.message_user(request, str(obj.TaskNum) + " 下达成功.")
else:
self.message_user(request, str(obj.TaskNum) + " 下达失败.") task_start_action.short_description = '下达所选的' + ' 任务' @atomic
def task_decompose_action(self, request, queryset):
for obj in queryset:
#只处理状态等于未处理的任务
if obj.State==Task.STATE_NEW:
#result=self.task_decompose(request,obj)
biz=TaskBiz()
result=biz.task_decompose(request,obj)
if result:
self.message_user(request, str(obj.TaskNum) + " 处理成功.")
else:
self.message_user(request, str(obj.TaskNum) + " 处理成功.") task_decompose_action.short_description = '处理所选的' + ' 任务'
这样admin.py文件只专注于django admin相关设置和事件触发的转调用,不再包含Task业务相关的代码,TaskBiz类则内聚了所有于Task业务业务操作的功能代码,这样通过代码结构性调整,实现了面向对象里的“高内聚”原则,业务代码就不用全部散落参杂在admin.py文件里,尤其随着业务的推进admin.py文件只会越来越复杂。业务层的抽象让admin.py变得简单易读,更利于功能得扩展和维护。
1.2. 持续TaskBiz重构
为了让TaskBiz更专注于业务本身,你发现现在的task_decompose_action方法使用了界面段传过来的request参数,把参数修改成传user对象,同时修改admin.py调用的参数传入。
from .models import Task,Job class TaskBiz(object):
"""description of class""" def task_start(self,obj):
success=False
if obj.State==Task.STATE_PROCESSED:
obj.State=Task.STATE_RUNNING
try:
obj.save()
success = True
except Exception:
success = False
return success def task_decompose(self,obj,user):
success=True
try:
job1=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":1,"Source":obj.Source,"Target":'102',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job1.save()
job2=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":2,"Source":None,"Target":'1',"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job2.save()
job3=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":3,"Source":"102","Target":'104',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job3.save()
job4=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":4,"Source":'104',"Target":'103',"Executor":"AGV01","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job4.save()
job5=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":5,"Source":'1',"Target":'5',"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job5.save()
job6=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":6,"Source":'504',"Target":'503',"Executor":"AGV05","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job6.save()
job7=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":7,"Source":'5',"Target":None,"Executor":"ELEVATOR","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job7.save()
job8=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":8,"Source":'503',"Target":'05-01-01',"Executor":"AGV05","State":Job.STATE_NEW,\
"Priority":obj.Priority,"Barcode":obj.Barcode,"User":user,})
job8.save()
#子任务分解完成,并提交数据库
#更新任务的状态到“处理完成”
obj.State=Task.STATE_PROCESSED
obj.save()
except Exception:
success = False return success
到这里我们得到了一个小步迭代的新版本代码,让TaskBiz更专注于Task业务本身,作为业务层更关注业务对象本身。最后,我们也需要重构一下admin.py里task_start_view的函数代码,已确保调用重构后的task_start函数。
from .TaskBiz import TaskBiz
#Task模型的管理器
class TaskAdmin(admin.ModelAdmin): ... @atomic
def task_start_view(self, request, *args, **kwargs): obj = get_object_or_404(Task, pk=kwargs['pk'])
#self.task_start(obj)
biz= TaskBiz()
biz.task_start(obj)
#raise Exception('模拟抛出异常!')
#重新刷新列表界面
co_path = request.path.split('/')
new_path=co_path[0:4]
new_path='/'.join(new_path)
request.path = new_path
return redirect(new_path)
这样本章节的抽象出一个业务Biz层的逻辑分层就做完了,这里看似简单的实现代码在实战中,往往不容易做这样的抽象,尤其糟糕项目后期做这样的抽象基本上可能已是举步维艰了,唯一能做的就是“将就”,点上三柱香祈祷新加入的代码不要影响原来的功能(熊猫烧香是有群众基础的)。笔者早些年的编码经历里,这样的例子比比皆是。让你的作品(代码)有生命,他们能在功能演化过程中不走进死胡同么。从简设计、迭代、重构和单元测试,敏捷编程的核心原则,让笔者看到代码一片“光明”。
1.3. 小结
本章节我们演示了如何对业务逻辑层进行抽象,通过面向对象内聚的原则,构建一个专注于Task的业务操作的TaskBiz类(层),从而实现把分散在admin.py的业务逻辑封装到对象类里,实现面向过程编码逻辑到面向对象逻辑的抽象。未来的章节中我们会逐步体会到这个抽象带来的扩展和维护优势。下一章节我们通过增加单元测试来进一步阐明如何进行代码重构。
python工业互联网应用实战7—业务层的更多相关文章
- python工业互联网应用实战3—模型层构建
本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...
- python工业互联网应用实战2—从需求开始
前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...
- python工业互联网应用实战1—SQL与ORM
从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题. ...
- python工业互联网应用实战18—前后端分离模式之jquery vs vue
前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...
- python工业互联网应用实战3—Django Admin列表
Django Admin笔者使用下来可以说是Django框架的开发利器,业务model构建完成后,我们就能快速的构建一个增删查改的后台管理框架.对于大量的企业管理业务开发来说,可以快速的构建一个可发布 ...
- python工业互联网应用实战11—客户端UI
这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...
- PYTHON工业互联网应用实战12—客户端操作
本章节我们将实现与admin里类似的列操作"下达"功能,演示客户端是如何实现操作功能,同时,演示也会强调一点,何时合并你的功能代码,避免相同功能使用不同的代码段来实现,在企业开发中 ...
- python工业互联网应用实战13—基于selenium的功能测试
本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...
- python工业互联网应用实战15-前后端分离模式1
我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...
随机推荐
- HDU 3336——Count the string
It is well known that AekdyCoin is good at string problems as well as number theory problems. When g ...
- 【转】Kubernetes scheduler学习笔记
简介 Kubernetes是一个强大的编排工具,可以用来很方便的管理许多台机器,为了使机器的资源利用率提高,同时也尽可能的把压力分摊到各个机器上,这个职责就是由scheduler来完成的. Kuber ...
- MySQL 多实例及其主从复制
目录 Mysql 实例 Mysql 多实例 创建多实例目录 编辑配置文件 初始化多实例数据目录 授权目录 启动多实例 连接多实例并验证 Mysql 多实例设置密码 设置密码后连接 Mysql 多实例主 ...
- SSH 密钥认证
目录 SSH协议概述 SSH 和 Telnet 的区别 SSH 相关命令 SSH 验证方式 基于密钥的安全认证 SSH 优化 expect 脚本免交互登录 sshpass 免交互登录 SSH协议概述 ...
- CentOS7系统时间和硬件时间不同步问题
CentOS7系统中有两个时间:系统时间 和 硬件时间 我们常用命令 date 会输出系统时间,用 date 命令修改的也是系统时间 硬件时间是写入到 BIOS 中的时间,用 hwclock -r 命 ...
- Keepalived+LVS实现LNMP网站的高可用部署
Keepalived+LVS实现LNMP网站的高可用部署 项目需求 当我们访问某个网站的时候可以在浏览器中输入IP或者域名链接到Web Server进行访问,如果这个Web Server挂了, ...
- 局部变量 static new 结构体指针
struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; 有一个函数利用LisNode ...
- C++含有无符号类型的表达式的计算
unsigned u=10; int i=-42; cout<<i+i<<endl; cout<<u+i<<endl; 在第二个输出表达式中,相加前首先 ...
- sdut2878 环形依赖的DP(高斯消元,剪枝后的模板
这题的状态是循环依赖的有环.. 之前一道概率DP,类似有环..但是它是可以消掉的 比如dp[i]=0.3*dp[i+1]+0.2*dp[i+2]+0.5*dp[i]; 完全可以变成,0.5*dp[i] ...
- Windows中VS code无法查看C++ STL容器的值 - 解决方法
Windows中VS code debug时无法查看C++ STL容器内容 首先,你很可能用的是x64版本的Windows. 我发现一个有效的解决方法,但在x64版本的Windows上安装MinGW时 ...