领域驱动设计,让程序员心中有码(七)

领域驱动设计- 让程序员心中有码(七)

-设计原则和设计模式,互联网开发者们共同的追求

      前言

  多年来,笔者一直从事传统软件企业的软件开发和项目管理工作。笔者发现在众多的传统软件企业中,评判优秀开发者的标准往往是技能的熟练程度,基本上都是以梭代码的速度论英雄。有人评价说,这种开发可以称之为cv编程,即ctrl+c和ctrl+v编程为主。这种开发往往对开发者的技能要求并没有想象中的那么高,由于工时和合同的限制,不得不压缩开发时间,通过靠密集的劳动力资源、较高的工作强度来完成项目的开发。这种模式,通过简单的复用历史代码,可以更快的输出结果,对于中小型企业和一些外包企业来说,也意味着更快的项目完成速度、而越快做完项目,也意味着可以越快收回合同款,尽快开始下一个项目。

  然而,也必须承认,在这种模式下,代码的质量取决于项目管理者对于技术和代码的把握能力,如果摊上不懂技术的项目管理者以及对于代码质量没有要求的研发人员,可能最终输出的代码,将成为一团乱麻,只能在一个个项目中无穷次的积累,直到遇到一群优秀的开发人员费劲心力把体系重构为止。

  而当今互联网时代下,面向互联网的应用开发,不再追求短期成效,更在乎长期技术的沉淀,这个过程中,也对开发者提出了更高的要求。互联网行业的开发者,不仅仅要求代码梭得快,还在乎编写代码编写的质量,谁能编写出更加优美的代码,往往也更容易受人欢迎。于是,作为优美代码代名词的SOLID设计原则和很多种设计模式实际上成为了非常基础的一种能力,甚至于许多资深的开发者,经常会乐此不疲的进行各种代码的重构,也是期待能够更好的将设计模式揉碎了,应用到代码中,更好的实现高内聚、低耦合的目标。

      《head first》中的工厂模式

   在著名小红书《Head First》一书中,描述了多种设计模式,这些由资深IT技术大牛们抽象化出来的最佳代码实践,初读起来也许简单明了,但是细细品味起来,却意味深长。

   在传统软件开发实践工程中,往往会下意识的使用New关键字产生对象实例。通过这种方式进行代码的编写,固然会带来代码上的开发速度,但是同样也会给对象的生成带来一些问题。例如,对象的构造,往往附带了许多复杂的条件:如需要进行一些初始值的设置,如需要初始化与之相关的子类,或者需要预先执行许多初始化方法,那么就可能意味着代码的构造中会产生一系列复杂、与主流程无关的代码。如何让轻松方便的构造代码、而不去关心具体的实现细节呢?

  工厂模式成为解决问题的方案,通过工厂模式,适当的创建接口,将代码中的具体过程进行屏蔽,从而提高了代码的灵活性。又分为静态工厂、简单工厂模式、工厂方法模式、抽象工厂模式等多种不同的模式。例如,我们可能会编写一段下面的代码。   

640?wx_fmt=gif

 1 public abstract class FactoryPizzaStore 2 { 3         public Pizza OrderPizza(string type) 4         { 5  6             Pizza pizza = CreatePizza(type); 7             return pizza; 8         } 9         public abstract Pizza CreatePizza(string type);10 }

640?wx_fmt=gif

      我们可以看到,这只是一段最普通的工厂代码,定义了一个抽象对象,如果需要实现成员,只需继承此对象,并重载方法,这种方法可以非常便捷的将内部对象的创建过程进行封装,实现了代码内聚性的显著提高。

领域驱动中的工厂模式和仓储模式

         在领域驱动中,将工厂模式引入其中,让其产生了不同的含义。在上一章,我们了解到,随着软件系统复杂性的显著提高,维护模型实例的生命周期变成了一件非常困难的事情,因此通过引入一个聚合Aggregate对象,可以有效的将复杂的模型复杂的生命周期的各个阶段进行封装,通过一系列固定的规则,实现了对数据更加的控制。而这种控制,则是通过工厂模式和仓储模式来实现的。这两种模式,实现了对Aggregate对象的操作,实现了复杂的生命周期转换复杂性的良好封装。

领域工厂模式

  一个复杂的软件系统,往往如同生产一台汽车,它由许多个不同的部件组成,每个部件间通过一系列复杂的协同运动来实现整体的职能。对于用户而言,汽车是如何装配的,并不是他所关心的问题,他只在乎如何驾驶这辆汽车。这意味着,装配过程,应该与对象要执行的工作分开。软件系统同样如此,我们设计了一个复杂的聚合对象,这个对象内部有大量的实体或者值对象。如果开发者需要使用这个对象,必须按照一系列规则来进行操作。

在这个聚合对象的生命周期中,如果将创建的过程按照调用的场景,分拆到不同的环节中,可能使代码的耦合性急剧提高,带来的将是后期高昂的更改成本。

  在领域驱动设计中,复杂对象的创建过程往往是领域层的核心职能,但是,对于这个复杂对象创建过程,又显然不能有简单的Service对象来实现,因此,需要引入工厂模式。封装创建复杂对象或聚合对象

的全部规则,并通过提供相关接口、创建对象的抽象视图,让创建的过程符合规则。

  在领域工厂模式中,往往有以下要求:

    1、创建过程的原子性、满足创建所需的所有规则。由于我们引入工厂的目的,是为了将复杂的常见过程进行封装,因此我们应当确保创建过程要产生一致状态的对象。例如创建实体,应当满足聚合的全部规则、创建值对象,应该被设置为默认的参数,如果无法创建参数,应该抛出异常,或者提供处理机制,确保不会影响代码的执行。

    2、工厂模式是一种抽象对象,而不是具体对象。意味着这个过程,不会产生具体对象,也就避免了与下层对象间不必要的耦合。

    工厂模式不仅仅可以应用于对象生命周期的开始阶段,也可以在对象的重建过程中发挥作用,例如在使用关系型数据库和非关系数据库组成的复杂体系中,通过对象映射技术,可以实现对现有数据的装载。

领域仓储对象

  在软件系统研发过程中,我们通常需要使用SQL语句,直接调用基础设施层中的某个方法,实现了一系列数据转换。有时候,我们会引入AutoMap组件,实现从实体层到模型层对象的封装,这种模式广泛存在于我们的开发过程中,但是如果直接访问基础设施层,则可能增加对于数据库不必要的操作,并导致模型的价值可有可无。而且随着开发过程的推进,有可能会倾向于直接使用多次遍历的方式,提取具体对象,而忽略了Aggregate,并使得实体层成为单纯的数据容器。

  因此,通过引入仓储模式,可以为我们的实现过程提供便利。通过仓储模式,封装一系列数据库操作的方法,让我们的注意力更关注于模型中。客户端通过查询方法,向仓储中请求对象,然后再返回用户所需的对象。

  这段代码大概是这样的:

 

public interface IRepository<T> where T : EntityBase
{T GetById(int id);IEnumerable<T> List();IEnumerable<T> List(Expression<Func<T, bool>> predicate);  
   
void Add(T entity);  
   
void Delete(T entity);    void Edit(T entity); }


  仓储的引入有很多优点:

      1、为访问者提供简单的模型,可用来获取持久化对象并管理他们的生命周期。

      2、实现数据源解耦。

      3、实现了对象访问策略的分离。

      4、便捷的访问内存对象,减少对数据库的吞吐压力。

  在仓储的设计过程中,应当注意一下事项:

      1、对类型进行抽象。仓储的目的是为了传递具有特定类型的实例,但并非每个对象都有一个仓储来与之对应。

      2、充分解耦。仓储聚合不同的查询方法,例如将关系数据库和缓存数据库的查询方法进行封装,使得代码的过程变得易于操纵。

   3、事务可控。提供事务操作的方式,便于用户自行实现事务的管理。

      结语

    在领域驱动设计中,通过在领域层中灵活的应用仓储模式和工厂模式,实现对象的创建过程和传递过程的不同阶段,可以让代码的执行过程更加的简洁、关系更加的清晰,这也将客观上有利于我们编写出更加优秀的代码。

相关文章:

  • 领域驱动设计,让程序员心中有码

  • 领域驱动设计,让程序员心中有码(二)

  • 领域驱动设计,让程序员心中有码(三)

  • 领域驱动设计,让程序员心中有码(四)

  • 领域驱动设计,让程序员心中有码(五)

  • 领域驱动设计,让程序员心中有码(六)

原文地址:https://www.cnblogs.com/xiyuanMore/p/10274752.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cf1504. Travelling Salesman Problem

cf1504. Travelling Salesman Problem 题意&#xff1a; n个城市&#xff0c;编号1~n&#xff0c;每个城市有美丽值a[i]&#xff0c;现在要从城市1出发&#xff0c;其他所有城市走一遍&#xff0c;最后回到城市1&#xff0c;城市i到j的花费为max(ci,aj-ai)&#xff0c;ci为第…

[NOIP-S 2020]游记(附考前注意事项)

呜呼起飞T1&#xff1a;排水系统T2&#xff1a;字符串匹配T3&#xff1a;移球游戏T4&#xff1a;微信步数总述考前注意事项T1&#xff1a;排水系统 嗯—— 怎么说呢&#xff1f;&#xff1f; 比赛开始后迅速通读三遍题 顶着第一题肯定是打卡题的心态 哪怕是恶心模拟也得上&…

程序猿修仙之路--数据结构之你是否真的懂数组?

数据结构但凡IT江湖侠士&#xff0c;算法与数据结构为必修之课。早有前辈已经明确指出&#xff1a;程序算法数据结构 。要想在之后的江湖历练中通关&#xff0c;数据结构必不可少。数据结构与算法相辅相成&#xff0c;亦是阴阳互补之法。开篇说道数组&#xff0c;几乎每个IT江…

Rolling The Polygon Gym - 102222B

Rolling The Polygon Gym - 102222B 题意&#xff1a; 给你一个多边形&#xff0c;给你内部一个点Q&#xff0c;多边形在平面上滚动一周&#xff08;当有一个边第二次触地滚动停止&#xff09;&#xff0c;问Q的轨迹长度 题解&#xff1a; 计算几何题目 自己一直不是很擅长…

Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章

前言事情的起因是由于一段简单的数据库连接代码引起&#xff0c;这段代码从语法上看&#xff0c;是没有任何问题&#xff1b;但是就是莫名其妙的报错了&#xff0c;这段代码极其简单&#xff0c;就是打开数据库连接&#xff0c;读取一条记录&#xff0c;然后立即更新到数据库中…

try.dot.net 的正确使用姿势

来源&#xff1a;https://www.cnblogs.com/7tiny/p/10277600.html【简介】微软官方前不久发布了 try.dot.net 这个有趣的网址&#xff0c;开始只是图个新鲜看了一下&#xff0c;后面通过自身实践过后&#xff0c;发现这着实算是个“有趣”的站点&#xff01;首先我们大概地列举…

A - TOYS POJ - 2318

A - TOYS POJ - 2318 题意&#xff1a; 一个盒子中有n个隔板&#xff0c;分出n1个空间&#xff08;从左往右空间的编号分别是0…n&#xff09;&#xff0c;&#xff08;隔板之间不会相交&#xff0c;且按照从左往右的顺序给出&#xff09;&#xff0c;现在给你m个坐标的物品&…

[BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)

文章目录titlesolutioncodetitle solution 针对数据编程才是坠吊的&#xff01;&#xff01;&#xff01; 观察数据&#xff0c;发现分隔数据的LLL跨度过大&#xff0c;没有衔接——推测很有可能是分数据做法 ①&#xff1a;考虑L≤100L\le100L≤100的情况 可以暴力DPDPDP转移…

[国家集训队]middle(二分+主席树[中位数思维题])

文章目录点击查看solutioncode点击查看 solution 简单口胡一下就跑 考虑二分答案ansansans 区间[x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d][x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d][x1,x2],x1∈[a,b]&#xff0c;x2∈[c,d] 大于等于ansansans的设为111&#xff0c;小于ansans…

使用Roslyn脚本化C#代码,C#动态脚本实现方案

来源&#xff1a;https://www.cnblogs.com/7tiny/p/10279349.html【前言】Roslyn 是微软公司开源的 .NET 编译器。编译器支持 C# 和 Visual Basic 代码编译&#xff0c;并提供丰富的代码分析 API。Roslyn不仅仅可以直接编译输出&#xff0c;难能可贵的就是上述描述中的开放了编…

[构造训练]CF1227G Not Same,CF1375H Set Merging,CF1364E X-OR

文章目录T1&#xff1a;CF1227G Not SamesolutioncodeT2&#xff1a;CF1364E X-ORsolutioncodeT3&#xff1a;CF1375H Set Mergingsolutioncode~~脑子是个好东西&#xff0c;希望人人都有构造真的不是个东西&#xff0c;看了一天视频&#xff0c;没有一道题会做~~ T1&#xff…

asp.net core 环境(Development、Staging 、Production)

一.在asp.net core中使用多个环境ASP.NET Core 配置是基于运行时环境, 使用环境变量。ASP.NET Core 在应用启动时读取环境变量ASPNETCORE_ENVIRONMENT&#xff0c;并将该值存储在 IHostingEnvironment.EnvironmentName 中。ASPNETCORE_ENVIRONMENT 可设置为任意值&#xff0c;但…

ASP.NET Core 2.1 : 图解路由(2.1 or earler)

本文通过一张图来看一下路由的配置以及请求处理的机制。 一、概述路由主要有两个主要功能&#xff1a;将请求的URL与已定义的路由进行匹配&#xff0c;找到该URL对应的处理程序并传入该请求进行处理。根据已定义的路由生成URL这两个功能看起来这两个是相反的。A.路由的配置路由…

[数据结构专训][GXOI/GZOI2019]旧词,[hdu5118]GRE Words Once More!,[hdu6333]Problem B. Harvest of Apples

文章目录T1&#xff1a;[GXOI/GZOI2019]旧词solutioncodeT2&#xff1a;GRE Words Once More!solutioncodeT3&#xff1a;Problem B. Harvest of ApplessolutioncodeT1&#xff1a;[GXOI/GZOI2019]旧词 点击查看 solution 考虑k1k1k1的情况 由于dep[lca(x,y)]∣{z,zdep[lca(…

浅谈c#垃圾回收机制(GC)

写了一个window服务&#xff0c;循环更新sqlite记录&#xff0c;内存一点点稳步增长。三天后&#xff0c;内存溢出。于是&#xff0c;我从自己的代码入手&#xff0c;查找到底哪儿占用内存释放不掉&#xff0c;最终明确是调用servicestack.ormlite更新sqlite数据库造成的。至于…

洛谷P2497:基站建设(splay、斜率优化)

所谓splay斜率优化dp&#xff0c;就是利用splay和斜率对dp进行优化 &#xff08;逃&#xff09; 解析 在斜优的时候&#xff0c;有时我们会发现我们插入的点的横坐标并不单调 这个时候我们就无法利用单调队列维护凸包了 这时&#xff0c;我们就要请出今天的主角&#xff1a;s…

MediatR 知多少

引言首先不用查字典了&#xff0c;词典查无此词。猜测是作者笔误将Mediator写成MediatR了。废话少说&#xff0c;转入正题。先来简单了解下这个开源项目MediatR&#xff08;作者Jimmy Bogard&#xff0c;也是开源项目AutoMapper的创建者&#xff0c;在此表示膜拜&#xff09;&a…

网络分析(带权并查集)

网络分析 题意&#xff1a; 有n个节点&#xff0c;一开始彼此独立&#xff0c;有两个操作&#xff0c;第一个操作时是连接两个节点&#xff0c;第二个操作是对一个节点x&#xff0c;&#xff08;在进行第二个操作时&#xff0c;与该点相连的点也会x&#xff09; 问每个节点的…

良心发现,时隔一年再回首莫比乌斯反演(公式性质证明+题目练习)

文章目录莫比乌斯反演引入公式性质模板公式证明莫比乌斯函数前缀和题目练习完全平方数[HAOI2011]ProblembYY的GCD[SDOI2014]数表[国家集训队]Crash的数字表格/JZPTAB[SDOI2015]约数个数和寒假疫情期间跟着lmm学了一遍&#xff0c;完全是懵逼到底状态&#xff0c;以至于后面考到…

平面切分

平面切分 问题描述 题解&#xff1a; 我对这种题极其非常不擅长。。。 另外吐槽为什么acwing的数据卡的这么死&#xff0c;蓝桥杯官网数据那么水 其实题目很简单&#xff0c;如果只有一个直线&#xff0c;那么就是两部分&#xff0c;如果是两个直线&#xff0c;这两个直线不相…