面向对象的业务应用程序:实体,边界,交互器

分享到:
更新时间:2015-11-18 14:06:05
 

面向对象的业务应用程序:实体,边界,交互器


    持续的系列中,我将谈论实体,边界和交互器(EBI)的架构设计模式。 我第一次听到它的主题演讲视频Bob大叔关于Ruby中西部称为“失去的岁月的建筑”。 这也被描述为六边形结构或“端口和适配器”。

在此模式的系统的任何客户谈话使用模型请求对象的模型和从模型中模型响应的对象的形式接收数据。 此外,当你的模型谈到任何一种持久性的或子系统应该通过一个适配器,可以更换。 对于一个模型架构,这样,您就可以通过编写新的适配器更换任何部件的UI奥德下层和插件他们进来。
术语

要迭代的术语:

实体是代表该应用程序的系统的数据对象。 它们不包含太多的逻辑,除了是一成不变的永远不会改变(基于物理或数学规律什么的)规则。

交互件是用例的对象,它们包含在当前用例有效,并与实体工程,以完成其任务所需的业务逻辑。

边界是负责翻译模型请求/响应进入该UI或演员可以理解的格式。 他们还模型和下级之间进行调解,例如管理数据库事务。
一个例子

让我们开始在PHP代码中的一个例子。 我们将继续使用一个常见的​​例子在所有的博客文章,通常的银行帐户/汇款。 用例是从一个银行账户(源)的钱转移到另外一个(目标)。

首先,我们通过实施实体的BankAccount:

  <?php的
 类 的BankAccount
 {
     私人 $ 平衡 ;

     公共职能 __construct()
     {
         $这 - > 余额 = 新 钱 (0);
     }

     公共职能 收回 ( 钱 $ 钱 )
     {
         $这 - > 余额 = $这个 - > 平衡 - > 减 ($ 钱 );
     }

     公共职能 保证金 ( 金额 $ 钱 )
     {
         $这 - > 余额 = $这个 - > 平衡 - > 添加 ($钱 );
     }
 }

这是容易实现的退出和存款的功能。 货币对象实现此省略。

交互件处理的用例从源到目标帐户转账的:

  <?php的
 类 MoneyTransferRequest
 {
     公众 $的sourceID;
     公众 $ destinationId;
     公众 $金额 ;
 }
 类 MoneyTransferResponse
 {
 }

 类 MoneyTransfer
 {
     私人 $ accountDao; //构造函数省略

     公共职能 transferMoney(MoneyTransferRequest $ 传输 )
     {
         $源 = $这个 - > accountDao - > 找到 ($转移 - > 的sourceID);
         $目标 = $这个 - > accountDao - > 找到 ($转移 - > destinationId);
         $钱 = 新 钱 ($转移 - > 量 );

         $源 - > 退出 ($钱 );
         $目的地 - > 存款 ($钱 );

         返回新 MoneyTransferResponse();
     }
 }

该MoneyTransferRequest和MoneyTransferResponse对象是愚蠢的PHP对象(即所谓的数据传输对象,DTO)。

您可以在我们使用的数据访问对象从某些存储子系统检索源和目标帐户实体的例子中看到。 要按照EBI的设计模式,我们通过提供一个端口(接口)脱钩从模型此数据访问对象:

  <?php的
 接口 AccountDaoInterface
 {
     公共职能 的发现 ($帐户ID);
 }

这样,我们的业务逻辑存储独立。

为一个边界的一个例子是对银行账户样品中的交易的要求。 我们需要包装在一个事务中的整体MoneyTransfer用例。 可以说,我们的用例的调用是通过某种应用程序边界对象的控制:

  <?php的
 类 BankApplicationBoundary
 {
     私人 $ applicationFactory;

     公共职能 transferMoney(MoneyTransferRequest $ 要求 )
     {
         $连接 = $这个 - > applicationFactory - > 的createConnection();
         $连接 - > 的BeginTransaction();

         尝试 {
             $用例 = 新 MoneyTransfer($厂 - > createAccountDao());
             $结果 = $ USECASE - > transferMoney($请求 );
             $连接 - > 提交 ();

             返回 $结果 ;
         }赶上 (\异常 $ E){
             $连接 - > 回滚 ();
             抛出 $ê;
         }
     }
 }

这是一个非常复杂的方式来描述,调用该转让款用例被包裹在一个事务,另一个端口的存储系统在这种情况下,管理事务。 这里的代码是非常明确一些实际任务。 在实际应用中,你可能会发现一个更通用的方法来获得这个工作做好。
边界抽象

思考的界限,我想出了一个图书馆几个月前名为上下文 ,我已经过时(原因下面)。 它可以让你通过某种代理的转换请求和响应,并处理交易,此类电话换到模型。 松散这话实际上是某种形式的AOP库,使用PHP提供了实现AOP( 魔术方法__call代理人)有限公司的方式。

随着环境下,你会做这样的事情:

  <?php的
 $语境 = $这个 - > 的getContext();

 // 1.直接调用
 $为myService = 新 的MyService();
 $语境 - > 执行 ( 阵列 ('服务'=> $为myService,' 法'=>'DoSomething的','参数'=> $ 参数));

 // 2.代理包装
 $为myService = $语境 - > 包装 (新 则将MyService());
 $为myService - > DoSomething的 ($参数);

第二种方式是明显的方式更具可读性,但它也相当神奇。

我不建议使用这个库的原因到底是不是真的有帮助那么多。 为实现服务的应用程序特定的代理工作是在极短的时间,然后解决所有您的特定需求。 与库我的主要问题是,它试图奇迹般地夺走需要设计自己的应用程序的边界 - 的方式,是不是真的统一给其他开发商。

在我自己的当前新建的应用我赶紧走了使用它,因为自定义应用程序代理,如本要点是真的简单得多实施和使用。
使用与Symfony2的

由于我目前只开发Symfony2的/ Silex的应用程序,应用EBI到Symfony2的基础架构应用程序对我来说很重要。 这里的最大的困难是表层,尤其是请求数据映射和验证的担忧,这是通常的模型的一部分​​。 有两种方法,我想出了解决这个:

    构建形式为数组或DTO的,并通过送他们到边界模型。 必须再次验证该模型,这是烦人的数据,但在这种情况下,清洁方式。 这并不是那么容易做到的复杂形式,虽然,因为你需要对请求对象映射到您的实体。
    创建一个模型请求,它包装并隐藏在一个简单的数据映射API的形式。 这样,您就可以使它看起来好像你会映射到DTO的对象,但在这种情况下,你所使用的表格API的映射。

<?php class MyService { public function edit ( EditRequest $request ) { $entity = $this -> dao -> find ( $request -> id ); $this -> dataMapper -> transform ( $request , $data ); } }

这种方法的问题是,你不能真正单元测试这些方法了,因为形式层映射的复杂性,不能用这个API被嘲笑。 相反,你的测试总是需要完整形式层(使用验证,这取决于服务等),以使实际测试。 此外,还可以使DataMapper的扔,你可以在控制器来抓,使相应的响应异常。 使用异常控制的执行路径是不是一个很好的做法,但。

另一件事,实际上帮助是SensioFrameworkExtraBundle和ParamConverters。 在我的项目,我现在的框架从HTTP请求建立按约定的示范请求的对象,所以我只需要在通过他们,可以跳过HTTP请求的实际映射到模型请求。
优点和缺点

这种设计模式非常近似于福勒调用POEAA 服务层图案 。 EBI会多一点到详细的命名模式各个部分更加明确。 没有更多的限制,但是,使用这种模式将推动你走向许多在我以前的帖子中描述的问题。

从框架干净分离实现,但是只有在显著成本取决于实际的使用情况。 永远不要忘记退一步,思考进一步抽象,否则将EBI是导致大量的代码被手写。

这已经具备了一个特别的烦恼是数据传输对象。 你需要投入相当一些工作,得到的映射从实体合作,转让对象和背部。 在这个过程中,你将失去“打开实体管理器视图”,在这里你能延迟加载任何数据要在视图访问的便利性。 这是一个相当痛苦的一步,因为你失去很多的灵活性。 更可气的是需要更新的数据传输对象的实体,需要复杂的代码部分对象图的合并。

这是什么设计模式是提高代码的可测性,也是测试的执行要好得多,当你不必去通过整个应用程序栈来测试一些东西。

比起混乱的领域驱动设计实施行为纳入用例也避免了大量的烤宽面条的代码。 你得到了什么是真正发生的事情只是通过观察模型请求和交互器类的一个很好的概述。 然而根据使用情况的类可以得到非常大的,而且可能需要大量的合作者,这使问题复杂了。

需要注意的是聚集在用例领域逻辑,其实就是将某种事务脚本处理,远离领域驱动设计是非常重要的。 我敢肯定,这不一定是从Bob大叔的POV这种设计模式的意图。 然而根据应用领域逻辑的复杂性,事务处理脚本实际上是一个很好的模式简单到中等复杂的用例,我喜欢这个作为开发者的一般规则(“把行为对用例”) 。

最后,我可以部分建议使用EBI模式。 你必须小心地发现,让你的代码干,但是SOLID抽象层,一些不自然来使用此模式。 如果你不小心,你最终得到的一切,我在我以前的博客文章中提到的“乱点”。

你应该特别小心,以避免大量的DTO的< - >实体映射代码通过使用一些代码生成为例做这个工作的一部分给你。 这种模式的最坏的结果是,当你手动的代码层的HTTP请求/表=> DTO =>实体映射和周围的其他方式。


        点击拨打北大青鸟电话  点击拨打北大青鸟电话  点击北大青鸟咨询师交谈

相关信息
没有相关内容
©Copyright2015 - 2016 , All Rights Reserved
版权所有2015-2016 北大青鸟APTECH( 北京佳音旗舰 ) 授权培训中心
地址:北京西城区北礼士路100号( 阜成门地铁旁)