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模板加载数据逐步演化到前后端分离的异步数据 ...
随机推荐
- hdu5438 Ponds
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submissi ...
- 1006 How many?
Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 36 Accepted: 2 Description 有一天,小Q给了小J ...
- Kubernets二进制安装(10)之部署主控节点部署调度器服务kube-scheduler
Kubernetes Scheduler是一个策略丰富.拓扑感知.工作负载特定的功能,调度器显著影响可用性.性能和容量.调度器需要考虑个人和集体的资源要求.服务质量要求.硬件/软件/政策约束.亲和力和 ...
- SQL优化汇总
今天面某家公司,然后问我SQL优化,感觉有点忘了,今天特此总结一下: 总结得是分两方面:索引优化和查询优化: 一. 索引优化: 1. 独立的列 在进行查询时,索引列不能是表达式的一部分,也不能是函数的 ...
- C# TextBlock
TextBlock 适合长文本多行显示,Label可以看成是一个简短的单行的TextBlock,只是Label可以显示图片,TextBlock只能显示纯文本 默认的文本不会分行显示,超出窗体宽度的字符 ...
- HLOD System
1.1 HLOD System简介 首先,HLOD System主要的目标是为了减少Draw Call.然后,进行更多的Batch批处理,从而大大提高渲染性能,减少面数和纹理,这样我们相应地节省了内存 ...
- 网站资源被盗链的:预防方法 VS 网站资源防盗链的:破解技巧
1 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问! 1 资源被盗链:(简明定义) 下载者不是从你的网站直接下载资源,而是通过其他盗链网站提供的你的下载资源链接进行下载你的服务 ...
- Creative Commons : CC (知识共享署名 授权许可)
1 https://creativecommons.org/ Keep the internet creative, free and open. Creative Commons help ...
- HTTP2.0 的学习笔记
1 1 1 HTTP2.0 1 11 1 1 1 1 1 1 超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,也被称为HTTP ove ...
- Beacon API
Beacon API User Tracking https://caniuse.com/#feat=beacon Question & Solution Beacon API 不会延缓网页卸 ...