当前位置: 首页 > 科技观察

面向对象分析与设计的底层逻辑

时间:2023-03-22 14:03:53 科技观察

1.面向对象是人认识事物的基本方法(1)人是怎样认识事物的?在面向对象出现之前,有一种面向过程的分析方法。提出来了吗?本质原因是人们发现面向过程并不是按照人们通常认识事物的方式来分析软件,那么人们是如何认识事物的呢?Yourdon在《面向对象的分析》一书中提到,人类是根据分类学认识事物的。分类学主要包括三点:区分对象及其属性;区分整个对象及其组成部分;形成和区分不同的对象类。我们现在可以回想一下我们认识事物的过程,是不是和分类学中提到的三点类似?当我们看到一个事物时,我们可能会感知它的成分、形状以及它的归属。分类。因此,人们从物体的角度认识事物,然后给物体赋予特定的概念,如苹果、梨、汽车等概念名称。(2)分类和分层的两种思维我们面对的现实世界是非常复杂的。处理复杂事物的一个重要方法是抽象。抽象在实际应用过程中体现为两种方法:分层和分类。分类就是把不同的事物归为不同的组。就像我们经常听到的“物以类聚,人以群分”的道理一样,分类的原因有两个:一是事物之间关系的紧密,没有必要把所有的事物都耦合在一起;还有一点就是人对事物的把握是有局限性的,只能把握少量的点,比如5-7点,这些点更容易被遗忘。分层就是从不同的角度看事物。每一层都有不同的关注点。这种侧重点的不同是其自身的视角造成的。例如,我们不需要深入研究二进制电信号来理解计算机。.层次特征在软件设计中经常遇到,如计算机体系结构、TCP七层协议等。层次特征有一个特点:层次越高越具体,层次越低越抽象,层次越高level,内容越不稳定,也就是容易改变。(3)从问题域到解空间的映射我们把要解决的问题称为问题域或问题空间,而解称为解空间。上一节讲到的事物具有层次性特点,不同的人从自己的角度理解事物,所以大家的理解和沟通并不一致。如果我们看到的问题空间是肤浅的,那么基于浅层理解设计的解决方案就会不稳定,一个小的改动就可能导致下一次重新设计解决方案。我们可以将一个软件分为三层:场景、功能和实体。场景层经常变化。比如发放优惠券的场景有很多。优惠券等,这种场景的变化随着业务的调整变化非常快,所以场景层不稳定。该功能支持一组特定的场景。与场景相比,功能相对稳定。就像上面说的发券场景,本质就是给用户发券。只需要提供发放优惠券的功能即可。至于which并没有关注场景去调用它,但是功能还是基于场景的集合进行了抽象。如果场景类型发生变化,功能也会随之改变。例如,担保交易不同于预售交易。实体稳定。以保底交易和预售交易为例,它们的下单模型大致相同,只是增加了一些新的信息。所以,我们希望从问题空间到解空间,大家看到的和理解的是一样的,看到的是问题的本质而不是表象。往往场景和功能是不稳定的,而面向过程是基于功能驱动的,所以在不断变化的场景中,面临的问题更多。相对稳定的是问题空间中的实体对象,所以面向对象分析是现实需要。面向过程和面向对象是两个不同角度的分析方法:面向过程是归纳分析方法,是从外到内的过程;面向对象是一种演绎分析方法,是一个由内到外的过程。4、三连贯的软件开发会经历需求分析、总体设计、详细设计、编码、测试、上线等主要阶段。我们不希望每一块都分开。比如分析完成后,设计阶段还要做分析工作,那么就涉及到一致性问题,即需求到分析的一致性,分析到设计的一致性,设计到编码的一致性。这样做的好处是可以保证不存在信息失真,所以我们急需一种可以做到这一点的分析设计方法,面向对象的分析设计可以做到,所以整个过程都是以对象为分析目标和设计,最后对象也被编码。5、面向对象的底层逻辑说到面向对象,有人会提到封装、继承、多态等特性,但这些都不是面向对象的本质特性,比如封装、面向过程还有封装性,多态性在面向过程中也有体现,这些特性并不是面向对象特有的特性。面向对象的底层逻辑是基于真实事物的抽象映射:真实事物对应软件中的对象,我们讨论解决方案空间可以对应问题空间中的对象,两者直接一一映射,和其他分析方法一样,是问题空间到解空间的一种间接映射。2、面向对象分析与设计全景图(1)我们面临的问题是什么?从顶层来说,我们需要完成从需求到编码的工作,但是从需求到编码会经历多个阶段,比如需求分析、方案设计等,从大的层面来说,我们主要遇到三个问题:1)whattodo的问题看似简单的问题,但是在复杂的业务场景中,whattodo的理解太重要了,因为不同比如最近的一个项目中,有一个业务判断规则,只对cross计算tax-边境订单。一开始开发同学的理解是判断卖家是不是跨境卖家。但是到了测试阶段,我发现大家对这个业务规则的判断和理解是不一致的。跨境订单与卖家类型无关。真正的跨境订单税费计算场景是shipTo(收货地址)和shipFrom(收货地址)。国家地址不同。在涉及多个团队协作的大型项目中,此类问题尤为突出。而且,从业务需求到产品需求,再到技术方案,有两个转变。每一次转型都涉及到不同的角色,每个人的理解也会不同。2)当如何做的问题落实到具体的做事方式上时,人往往没有大的问题。如何去做更具体到实施阶段。程序员在逻辑严谨性上往往没有大问题,往往问题出在第一个问题上,说明方向不对,所做的工作没有用。3)方法指导的问题我们常常希望获得一种不费吹灰之力就能处理所有问题的通用方法,同时看不起低级方法。.其实从70年代到80年代以来,软件的分析设计方法并没有太大的变化,我们大学的时候也学过,但是大家并不觉得它是高级的方法。(2)从分析到设计的过程本节我们推导软件从分析到设计,从粗到精的过程,并最终实现我们接触到的UML知识。从需求提出到编码实现的过程中有两个关键问题:一是定义目标,即明确定义要做什么,相当于我们工作的方向和目标;另一个是具体怎么做,即如何实现具体的方案支持需求目标的实现。因此,我们需要一种能够帮助我们明确目标和表达具体计划的方法,而且是大家公认的常用方法。用例图可以帮助我们定义目标。用例中包含三个关键要素:用户、场景和目标。例如,下交易订单是一个用例,它的用户是买家。场景包括下单成功和下单失败两种场景。用例的目标是买家可以购买他们喜欢的产品。当确定了用例目标后,就相当于定义了目标,知道了需求需要做什么。这个过程需要和业务方反复确认。最后大家对目标的理解是一致的,方向是对的。怎么做很容易。向上。具体如何用时序图来表示。绘制时序图需要注意的一点是顶层对象层次结构必须保持一致。有的对象不能代表具体的实体对象,有的代表系统对象,即对象层次是一致的,或者大家都是一个系统,比如导购系统调用交易系统,交易系统调用支付系统,或者说每个人都是一个对象,比如商品、订单等。通过时序图可以看到一个完整功能的执行步骤,包括具体的执行细节,比如正常流程和异常流程。其实上面有问题。画时序图的时候一定要确定对象,那么这个对象是怎么来的呢?用健壮性图来分析,里面有3个关键对象:一个是边界对象,比较容易理解,比如UI界面就是边界对象;另一个是控制对象,它是控制业务流程的对象,如下单个服务可以看作是一个控制对象;实体对象是问题空间中的业务对象,例如订单。绘制稳健性图是有规则的。一般边界对象调用控制对象,控制对象生成实体对象。比如用户下单界面是边界对象,下单服务是控制对象,订单是实体对象。3.寻找对象的方法(1)对象从哪里来?如本文第一部分第三小节所述,问题空间到解空间是一对一的映射。当我们讨论解决方案空间中的对象时,它实际上映射到问题空间中。问题空间中的对象主要来自业务概念、业务规则和关键事件。大多数对象是可见的,我们可以通过了解业务来发现它们。有些对象是隐藏的,需要我们继续对业务有更深入的了解才能发现。一个好的对象模型需要经过多次迭代打磨,不可能一蹴而就。(2)发现对象的方法本节主要介绍完整的对象发现方法。主要方法分为四个步骤:1.通过健壮图找到关键实体对象;2.通过结构分析的方法找到更多的实体3.将对象组合成一个有机的对象模型;4.最后遍历用例,检查对象模型是否完整。下面用一个案例来说明发现对象的过程。案例是用户下单时,订单上显示税额。先画稳健图。这里的边界对象是订单接口。控制对象有两个,一个是订单服务,一个是税务服务。还有两个实体对象,一个是税表,一个是订单。.有了税单和订单这两个实体对象,我们可以通过结构分析的方法来分析更多的对象。对象具有结构。只要掌握了物体的结构,我们就可以基本掌握物体的大致外观。因此,我们从对象的结构入手,分析对象的内部结构和对象关联的结构。本质上,我们是从两个维度出发:一个是从自己的角度出发,看自己里面包含了哪些对象,比如主订单包含子订单;另一种是从外部角度出发,看你关联了哪些对象,比如订单关联的税单。我把这种找对象的方法称为结构分析法,因为结构本身就是表达事物本质的一种方式。例如,化学分子的结构决定化学现象。为了更好的表达对象的结构,我的一个经验就是定义好对象。可以从功能维度、价值维度、目的维度、结构维度等不同维度进行定义,这里可以从结构维度入手来定义对象。以计税表为例,我们可以给它下一个定义:计税表是将订单金额信息转化为若干标的物计税的单据模型。从这个定义中我们可以看出,税单的计算表是与订单相关的。另外就是税单包含了几个对象,我们可以画出税单的对象模型。对象模型画好后,后续再谈业务。基本上我们会围绕这个对象模型来讨论业务问题,比如商品标的物的多少应该参与计税,计税金额的计算口径是多少。到这里,大家就明白了“直接把问题空间一一映射到解空间”这句话下的商业诉求无非就是哪些订单商品需要征税,税金计算逻辑是什么,可以这个场景扣金本位折扣,另外一个场景金本位折扣不用扣。基于对象模型,和产品、测试同学讨论问题,大家看问题的角度一致,沟通和理解的成本会少很多。对象模型是一种视觉表达。我们大部分的沟通问题都是由于缺乏明确的表达造成的。这句话可以这样理解,也可以这样理解,导致大家的理解出现偏差。现在我们使用模型来交流问题。消除了许多偏差和歧义。(3)组织对象结构当我们分析一堆对象时,还是要经过一定的组织。前面说过,人对事物的认识有限,不能一下子接受太多的事物,所以可以把它分成小的域,比如商品域、订单域、税收域等,这样当一个问题聚集起来的时候,你只能查看某个子域中的对象模型。4.如何分配职责(1)职责是怎么来的面向对象最难的有两点:一是找对象;二是找对象。二是落实责任。UML将责任定义为“分类器的契约或义务”,因此责任的划分本质上是由分类器自己决定的,比如订单,它提供了订单呈现、订单创建、订单修改、订单查询的义务。责任分为两类:一类是认知责任;另一个是行为责任。认知责任包括:私有数据封装意识。对相关对象的认识。对可以导出或计算的事物的认识。行为责任包括:您自己执行的行为,包括创建对象或计算。初始化其他对象的操作。控制或协调其他对象的活动。(2)职责分配逻辑本节提到的职责分为两类。认知职责是对象自身的认知范围,即它只能根据自身的属性完成相应的职责。举个例子,如果一个master有多个Sub-order,要计算订单总金额,如何分配职责?首先,一个产品只能找到它自己的价格信息。它的认知是基于产品的价格属性。一个子订单可以有多个商品,所以只能计算子订单的金额信息。它的认知是基于item和Quantity两个属性,主订单包含所有子订单的信息,然后可以计算出总订单金额。从上面的例子可以看出,认知责任是基于对象属性的。俗话说“不在位,不求为政”,认知责任不能超出其认知范围。行为责任是特定领域的服务。有时候一个责任并不属于某个对象,比如转移,这是一个动作,不宜让其他责任承担。这种行为责任往往是一个重大的业务活动,比如订单呈现、订单创建是行为责任而不是认知责任。分配职责必须遵循“信息专家”模型,即将职责分配给具有完成职责所需信息的类,即上述的意识生成职责。(三)核实职责分工的合理性。我们期望分配的职责满足“高内聚低耦合”。如何验证?我们回头想想责任的定义:分类者的契约或义务。也就是说,职责是满足其他对象的调用。这与我们画时序图的目的是一致的。每一次调用发生,就意味着其他对象要提供一个职责,所以我们可以在时序图中看到对象之间的调用频率。如果一个对象被非常频繁地调用,则可能是该对象承担了太多责任。它拆分并分配了部分职责。因此,对象职责的分配不是一蹴而就的,需要不断的回顾和测试。分配职责是遵循一定的原则,比如创作者模式、信息专家模式、纯虚构模式等,这些原则将在下一篇文章中单独讨论。5.案例(1)案例背景下面举例说明面向过程和面向对象在分析和编写代码时的区别。计税需要判断是否符合计税规则。比如虚拟商品不征税(手机充值等),部分免税地址不计税,小B买家不计税等。因此需要提供计税过滤判断逻辑。(2)常规的面向过程实现面向过程的思想很简单。提供过滤方法依次处理以下逻辑:过滤虚拟商品计税请求、过滤免税地址计税请求、过滤小B买家计税请求。publicvoidfilter(Listrequest){//过滤虚拟商品计税请求filterVirtualItem(request);//过滤免税地址计税请求(即外岛)filterOuterIsland(request);//FiltersmallB买家计算TaxrequestfilterPurchaseType(reqeust);}(3)面向对象实现面向过程是从流程或功能的角度分析问题,而面向对象是从对象的角度分析问题.Filteringtaxcalculationrequests是一个taxcalculationfilter,用来判断taxcalculation请求是否满足taxcalculation规则,这里包含两个对象:taxcalculationfilter和taxcalculationrules,判断是否满足taxcalculation要求的责任应该在具体的计税规则处理器,比如是不是小B买房等等,我们可以画出对象模型。关键代码如下:publicabstractclassAbstractRuleHandler{/***抽象业务规则处理**@paramrequest*/publicabstractvoidhandler(TaxCalculateRequestrequest);/***在构造函数中注册*/publicAbstractRuleHandler(){TaxCaluclateFilter.register(this);}}6.总结文中提到,面向对象的底层逻辑是基于真实事物的抽象映射。重要的不是面向对象具体技术的使用,而是分析问题的思维,这个才是最难的。它最大的优点是问题空间直接映射到解空间。请注意,它是一对一的直接映射。这意味着我们在讨论解决方案时可以映射到问题空间。如果是间接映射,意味着设计方案后期会面临重新设计的可能,因为它是基于场景或功能的归纳设计,属于表面设计。真正掌握了面向对象分析设计的方法,也体会到了其中的好处,对于理解业务、程序设计、编码开发都有好处。