本章我们演示代码是如何“进化”的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的“禅”——简单设计、快速发布、获得反馈、快速开发的迭代循环过程,如何保证迭代过程持续交互合格的代码,代码重构和单元测试是非常重要的手段。单元测试用来保证重构的代码先满足原来的测试逻辑,代码结构优化满足新的业务需求扩展,然后开发增加新的功能、新的单元测试,每一轮迭代发布新的功能,获取用户反馈…

  上一章功能完成的时候,你发现当前的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—业务层的更多相关文章

  1. python工业互联网应用实战3—模型层构建

    本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...

  2. python工业互联网应用实战2—从需求开始

    前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...

  3. python工业互联网应用实战1—SQL与ORM

    从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题. ...

  4. python工业互联网应用实战18—前后端分离模式之jquery vs vue

    前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...

  5. python工业互联网应用实战3—Django Admin列表

    Django Admin笔者使用下来可以说是Django框架的开发利器,业务model构建完成后,我们就能快速的构建一个增删查改的后台管理框架.对于大量的企业管理业务开发来说,可以快速的构建一个可发布 ...

  6. python工业互联网应用实战11—客户端UI

    这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...

  7. PYTHON工业互联网应用实战12—客户端操作

    本章节我们将实现与admin里类似的列操作"下达"功能,演示客户端是如何实现操作功能,同时,演示也会强调一点,何时合并你的功能代码,避免相同功能使用不同的代码段来实现,在企业开发中 ...

  8. python工业互联网应用实战13—基于selenium的功能测试

    本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...

  9. python工业互联网应用实战15-前后端分离模式1

    我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...

随机推荐

  1. hdu5135 Little Zu Chongzhi's Triangles

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others) Total Submissi ...

  2. [POJ 2585] Window Pains 拓朴排序

    题意:你现在有9个2*2的窗口在4*4的屏幕上面,由于这9这小窗口叠放顺序不固定,所以在4*4屏幕上有些窗口只会露出来一部分. 如果电脑坏了的话,那么那个屏幕上的各小窗口叠放会出现错误.你的任务就是判 ...

  3. Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final) A. Kids Seating (规律)

    题意:给你一个正整数\(n\),在\([1,4n]\)中找出\(n\)个数,使得这\(n\)个数中的任意两个数不互质且不能两两整除. 题解:这题我是找的规律,从\(4n\)开始,往前取\(n\)个偶数 ...

  4. Codeforces Round#630 div2 A~C题解

                                                                                                        ...

  5. 深入了解typeof与instanceof的使用场景及注意事项

    JavaScript中的数据类型分为两类,undefined,number,boolean,string,symbol,bigint,null[1]组成的基础类型和Object.Function.Ar ...

  6. Hexo之更换背景及透明度

    Hexo之更换背景及透明度 引入方式 首先,介绍一下引入方式,外部导入css文件,不影响内部配置. 1.创建css文件 创建一个css文件移动到\themes\butterfly\source\css ...

  7. python to exe

    使用pyinstaller 打包 文件结构如下 命令行cd 进入 project文件夹 ,然后 命令 pyinstaller -F main.py 即可打包文件为一个完整的exe.(不含DLL等)

  8. 7A - Kalevitch and Chess

    A. Kalevitch and Chess time limit per test 2 seconds memory limit per test 64 megabytes input standa ...

  9. 操作系统 part3

    1.操作系统四特性 并发:一个时间段,多个进程在宏观上同时运行 共享:系统中的资源可以被多个并发进程共同使用(互斥共享,同时共享) 虚拟:利用多道程序设计,利用时分复用(分时系统)和空分复用(虚拟内存 ...

  10. HDU 3341 Lost's revenge (AC自动机 + DP + 变进制/hash)题解

    题意:给你些分数串,给你一个主串,主串每出现一个分数串加一分,要你重新排列主串,最多几分 思路:显然这里开$40^4$去状压内存不够.但是我们自己想想会发现根本不用开那么大,因为很多状态是废状压,不是 ...