相关文章和工具
带你深入理解抽象,及抽象在软件设计中的运用
相关研究:https://www.tutorialspoint.com/object_oriented_analysis_design/ooad_dynamic_modeling.htm
ZenUml源码:https://github.com/ZenUml
提问环节
1.动态体现在哪里?
提问者:
我最大的问题是不理解如何去“动态”的,我稍微收窄下提问,铺垫下场景,我觉得今天分享的案例,最终的效果就是通过一个parent calculator,然后往里面传了N个child calculator。我认为它唯一可能存在动态的场景,就是去提供这个child calculator,请问是这样理解吗?
回答者:
回到我们刚分享的为什么需要动态建模那一个部分,我觉得至少有三个部分能体现这个动态:如何构建,如何注入,如何执行。
也就是说为什么我觉得动态建模重要,我是觉得静态建模里边真的没有体现这些概念。关于动态建模,我是针对静态建模讲的,我们这个行业里面很多东西,其实你都可以从不同的角度去看,而且他也有相通的地方,例如其他的关于建模的方法论,它也会牵扯到动态建模,因此方法论中也会存在类似的概念。
提问者:
这个动态就意味着修改结构上的一些事情,从而实现不用改动细节,然后去改变它的行为吗?
回答者:
我们看这张图来理解,各种讲面向对象的书,里边基本上都是这些词:类,方法,属性,类和类的关系,类的职责。我们很少看到动态模型的这些概念:对象,状态,交互,对象关系,业务逻辑。
我们先找到我们共同的地方,比如说你打开设计模式这本书。他会跟你讲。我要有一个策略类,它有几个子类。然后这个策略类是作为一个字段,被这个上下文这个类使用,策略模式是讲这么一个东西,你同意吗?
提问者:
同意。
回答者:
其实对于动态建模,我也是有出发点的,你看我翻译的这本面向模式的软件架构这本书,它的第五卷的名字叫模式语言(pattern language)。他要解决一个什么问题呢?作者说,我们已经有这么多设计模式了。这些设计模式我们把它称为词语。我们要写的程序是一篇文章,这篇文章的最基本的单位,如果要表达一个意思的话,它至少要有一句话。
我们自然语言里面的一句话有主语、谓语、宾语。这23个设计模式里边,哪些是处于主语的位置,哪些是处于谓语的位置,哪些是处于宾语的位置,并且通过怎么样的组合能讲一个故事呢?
我举一个最简单的面向对象模式语言的例子,我首先要把一个对象创建起来,这个对象,我们可以用最简单的创建型的设计模式——单例模式来创建出来,接着我要用策略模式来装配他的行为,然后用选择器来匹配一个策略(选择器这个模式不在什么不在23个设计模式里面,但是它也算一种设计模式),然后进行执行,这样就构成了一句话。
但是这句话在对象设计模式第五卷(模式语言)出现之前,这个领域里面其实没有把模式语言这个概念抽象出来,动态建模其实跟模式语言是很接近的,面向模式的软件架构第五卷,这本书是我思考这个问题,进入一个比较系统化的时期,我在读和翻译这本书的时候,我就意识到,面向对象分析里边缺少的就是这部分。
我不知道,是否回答了你的问题。
提问者:
那比如说一句话:我吃了一个苹果,请问该如何用动态建模来理解。
回答者:
苹果就像策略模式。你告诉我说我有个苹果,这个苹果你给我描述的再漂亮,我也不会吃它。我也不知道我是要吃它,还是我要把它籽儿拿出来种一下,还是把它切成片儿看一下里边的细胞结构。你需要把它放到一个上下文里面去,说清楚你要把这个苹果怎么样用起来,是把它吃掉还是来种树?这个时候你就要考虑动态模型。如果你不考虑动态模型的话,就无法解答静态模型遗漏的那三个问题。
我十几年前看设计模式这本书的时候,我也是看的如痴如醉。但是回到项目上,我就是不会用,比如说大家耳熟能详的MVC,C是在哪个地方创建的?是C创建M,还是C创建V,M和V是什么关系?通过这个例子你会发现,MVC的这么多的书,都没有明确的跟你讲,谁创建谁这件事情。
这个时候,你就需要一个模式语言去来讲,当然一个故事有N多种讲法,你可能C创建M,也可能M创建C,但是这种创建的过程和选择,就体现了动态这两个字。
提问者:
如果不说苹果之类的太抽象的东西。就是说这个创建这一块,如果说我用这种类似于spring framework(一个完整的IOC container )的框架来创建东西,那创建的这个步骤是不是就已经解决了。
回答者:
这是个很好的问题,这就是你认识到了原来创建这件事情还是发生了,只不过是给你隐藏起来了。作为一个菜鸟或者说新手这样理解这个问题是可以的,因为创建这件事情太难了,正确的选择一个正确的时间去创建一个对象太难了,工具或者框架的出现,就是为了解决这个问题的,框架直接把对象创建好了,程序员直接从里面取出来用就行了。
但是,作为一个有经验的程序员,你必须要理解他是怎么创建的,因为被隐藏虽然有好处,但是你也要知道被隐藏也是有风险的,如果你工作过五年或者十年以上的话,你一定会遇到过一个问题:“我丢,为什么把这个东西隐藏了?我需要办法把它修改了!”。所以,并不是说创建对象的问题不存在了,它是仍然存在的,而且它是非常重要的一件事情,我认为是需要我们来理解这个过程的。
再进一步讲,就是注入的问题,那我是不是全部的对象都需要自动注入,以spring 为例,是不是全部对象都可以用这种方式创建?
如果你真的把所有对象都用这种方式注入,很有可能你的代码就会变成一坨shit。当一个类里面有几十个依赖的情况,其实你就要想了,我真的需要这些东西吗?我真的需要用这种方法去注入它吗?还是说我可以有更好的方法去管理这个注入呢?
如果你去看重构那本书的话,它的作者非常倾向于不要用这样的方法,而是用constructor 去管理注入。尤其是对于小的业务的类,不要去用那种service 的方式去去注入。
说完注入,那接下来就是执行,你怎么样去执行呢?你去看一下我们刚才的案例,执行到底是并行的,还是用一个数组做for each 的去执行呢?这些都是执行的细节。你会发现在静态建模里边,是不会有人讲这个事情的,只有重构这样的书才会讲。
最后,你如果觉得动态没有办法理解的话,可以把它替换成【运行时】。
提问者:
那就对了,我想起来自己使用go时,需要考虑运行时注入对象的一系列问题了,我知道你说的是什么了。
2.案例建模是通过一系列重构讲原有设计(各种if-else)变为的设计模式吗?
提问者:
老师,我进来的比较晚,我进来的时候,你已经在讲那个就是那个案例了,虽然你俩聊了很多,但是我还是没太听懂动态建模这个概念。
你讲案例写的这个过程,给我的感觉就是一个重构的过程。把原有的代码设计,重构成了一个更抽象的一个设计,抽象之后,发现这个更像是一个设计模式(而不是先知道有一个设计模式然后再往上套),这种就是您指的动态吗?
回答者:
这个还不是。这个是个结果,我个人认为建模一定是个过程。而且我比较推崇的一个词叫驱动,就是driven,就是你看到很多DD(BDD,DDD,FDD)之类的。
如果你告诉我一个结果的话,这个通常是大师型的人物才能做的。就是看一眼就知道这个应该是什么样子的,但是对于凡人来说,我们要有一个驱动,相当于说是你告诉我1和1,然后我能算出2来就不错了。
驱动是什么?这个驱动的过程就像你说的,就是在我们这个里面,其实就是一个重构,发现重复进行重构。
动态并不是说我建模的这个过程是动态的,而是说我关注的点是什么?你看我在这个过程中关注的点都不是类,属性,方法,类和类的关系,类的职责等。我关注的都是这个对象。这个对象是什么状态的?当然这里面我们也考虑到了一些对象之间的交互,对象之间的关系,对象的逻辑。比如说我是顺序的调用,还是for each,这个对象是什么时候创建出来的,什么时候初始化的,是怎么装配的,是怎么结构的,是怎么销毁的。这个是这个动态的来源。
我刚才讲了,就是说如果你觉得动态比较难理解,你可以把它想成运行时。但是为什么我们这个名字不叫运行时呢?是为了跟这个静态对比,这个是dynamic 翻译过后的意思。翻译的过程中我觉得有一点点损失,回到你的问题上,什么样是动态,就是我们关心的是运行时发生的事情和状态。
如果咬文嚼字一点,不是说建模的过程是动态的,而是说建模的驱动力是动态的,建模的驱动力是来自于这些动态的概念(对象,状态,交互,对象关系,业务逻辑),而不是来自于这些静态的概念(类,方法,属性,类和类的关系,类的职责)。
你如果用这样的驱动力去建模的时候,慢慢的就会发现一些好处,可能得到一个更好的设计。我是希望我觉得对于我们这样平凡的程序员来说,需要一些驱动力,来帮助我们做出更好的设计来。
3.动态建模除了时序图这种方式有没有更好的办法?
提问者:
动态建模的目的需要表达静态模型隐藏的一些逻辑,这种交互逻辑,我可以用其他的模型去展现吗?而不是用这种时序图的形式。因为我认为时序图的形式,这种方法级别的模型粒度太细了。
回答者:
实际我工作了这么多年,坦白说,我没有找到其他更好的方法。没有一个其他的图,能把这个描述的平衡做的这么好,这个平衡是指什么呢?就是既不描述太多的细节而又不缺失细节,并且你又可以随时灵活调整(比如说我不关心这一个条件,那我就把它去掉)。
对于模型粒度的问题,其实你可以在非常高的粒度上做这件建模,比如说我有一个图书馆系统。我有一个第三方的系统,叫Payment,我要检查用户有没有罚款,如果有的话,就不能借给你书,这个Payment 到底对应着一个接口还是一个类都可以。此外,假设还有一个外部系统Splunk,我们可以通过notice调用,那Splunk其实也不对应一个类,而对应的是一个系统,这个系统到底是通过in process 的调用还是http的rest 调用,都是允许的。
所以,这就是我为什么说,它是平衡的最好的一个工具,它相当于横轴铺开,纵轴铺开,是最容易理解的一种展现方式。