当前位置: 首页 > news >正文

网站建设的主要流程有哪些企业通用网站模板

网站建设的主要流程有哪些,企业通用网站模板,用php做的网站论文,wordpress表情无插件概述作为领域驱动设计战术模式中最为核心的一个部分-值对象。一直是被大多数愿意尝试或者正在使用DDD的开发者提及最多的概念之一。但是在学习过程中#xff0c;大家会因为受到传统开发模式的影响#xff0c;往往很难去运用值对象这一概念#xff0c;以及在对值对象进行持久… 概述作为领域驱动设计战术模式中最为核心的一个部分-值对象。一直是被大多数愿意尝试或者正在使用DDD的开发者提及最多的概念之一。但是在学习过程中大家会因为受到传统开发模式的影响往往很难去运用值对象这一概念以及在对值对象进行持久化时感到非常的迷惑。本篇文章会从值对象的概念出发解释什么是值对象以及怎么运用值对象并且给出相应的代码片段本教程的代码片段都使用的是C#,后期的实战项目也是基于 DotNet Core 平台。何为值对象首先让我们来看一看原著 《领域驱动设计:软件核心复杂性应对之道》 对值对象的解释很多对象没有概念上的表示他们描述了一个事务的某种特征。用于描述领域的某个方面而本身没有概念表示的对象称为Value Object值对象。此时作者是这样的而我们是这样的然后作者用“地址”这一概念给大家扩充了一下什么是值对象我们应该怎么去发现值对象。所以你会发现现在很多的DDD文章中都是用这个例子给大家来解释。当然读懂了的人就会有一种醍醐灌顶的感觉而像我这种菜鸡以后运用的时候感觉除了地址这个东西会给他抽象出来之外其他的还是该咋乱写咋写。For Example public class DemoClass{ public Address Address { get; set; } //…………}OK现在我们来仔细理解和分析一下值对象虽然概念有一点抽象但是至少有一关键点我们能够很清晰的捕捉到那就是值对象没有标识也就是说这个叫做Value Object的东西他没有ID。这一点也十分关键他方便后面我们对值对象的深入理解。既然值对象是没有ID的一个事物东西那么我们来考虑一下什么情况下我们不需要通过ID来辨识一个东西“在超市购物的时候我有五块钱你也有五块钱” 这里会关心我的钱和你的钱是同一张同一个编码同一个组合方式一张五块五张一块吗显然不会。因为它们的价值是一样的就购买东西来说所以它是不需要ID的。“去上厕所的时候同时有两个空位都是一样的马桶都一样的干净” 这里你会关心你要上的马桶是哪一个生产规格哪一个编码吗显然不会你只关心它是否结构完好能够使用。当然有的人可能要说“我上厕所的时候我每次都认准要上第一排的第一号厕所。” 那么反思一下当十分内急的时候你还会考虑这个问题吗虽然这个例子举的有点奇葩但却值得我们反思在开发过程中我们所发现的一些事物类它是否真的需要一个身份ID。通过上面的两个例子相信你一个没有身份ID的事物类已经在你脑袋里面留下了一点印象。那么让我们再来看一下原著中所提供给我们的一个案例当一个小孩画画的时候,他注意的是画笔的颜色和笔尖的粗细。但如果有两只颜色和粗细相同的画笔他可能不会在意使用哪一支。如果有一支笔弄丢了他可以从一套新笔中拿出一支同颜色的笔来继续画画根本不会在意已经换了一支笔。值对象是基于上下文的请注意这是一个非常重要的前提。你会发现在上面的三个案例中都有一个同样的前缀“???的时候”。也就是说我们考虑值对象的时候是基于实际环境因素和语境条件上下文的。这个问题非常好理解比如你是一个孩子的爸爸当你在家里面的时候听到了有孩子叫“爸爸”哪怕你没有看到你的孩子你也知道这个爸爸指的是你自己当你在地铁上的时候突然从旁边车厢传来了一声“爸爸”你不会认为这个是在叫你。所以在实现领域驱动的时候所有的元素都是基于上下文所考虑的一切脱离了上下文的值对象是没有作用的。当前上下文的值对象可能是另一个上下文的实体实体是战术模式中同样重要的一个概念但是现在我们先不做讨论我们只需要明白实体是一个具有ID的事物就行了。也就是说一个同样的东西在当前环境下可能没有一个独有的标识但可能在另一个环境下它就需要一个特殊的ID来识别它了。考虑上面的例子同样的五块钱此时在一个货币生产的环境下。它会考虑这同样的一张五块钱是否重号显然重号的货币是不允许发行的。所以每一张货币必须有一个唯一的标识作为判断。同样的马桶此时在一个物管环境中。它会考虑该马桶的出厂编码如果马桶出现故障它会被返厂维修并且通过唯一的id进行跟踪。显然同样的东西在不同的语境中居然有着不同的意义。怎么运用值对象此时你应该可以根据你自己的所在环境和语境上下文捕获出属于你自己的值对象了比如货币呀姓名呀颜色呀等等。下面我们来考虑如何将它放在实际代码中。以第一个五块钱的值对象例子来作为说明此时我们在超市购物的上下文中我们可能已经捕获倒了一个叫做“钱”Money的值对象。按照以往我们的写法来看一看会有一个什么样的代码public class MySupmarketShopping{ public decimal Money { get; set; } public int MoneyCurrency { get; set;}}尽量避免使用基元类型仔细看上面的代码你会发现这没有问题呀表明的很正确。我在超市购物中我所具有的钱通过了一个属性来表明。这也很符合我们以往写类的风格。当然这个写法也并不能说明它是错的。只是说没有更好的表明我们当前环境所要表明的事物。这个逻辑可能很抽象特别是我们写了这么多年的代码已经养成了这样的定性思维。那么来考虑下面的一个问卷运动调查表(1)姓名________性别________ (字符串)周运动量________(整型)常用运动器材________(整型)运动调查表(2)姓名________性别________ (男\女)周运动量________(0~1000cal\1000-1000cal)常用运动器材________(跑步机\哑铃\其他)现在应该比较清晰的能够理解该要点了吧。从运动表1中仿佛出了性别之外我们都不知道后面的空需要表达什么意思而运动表2加上了该环境特有的名称和选项一下就能让人读懂。如果将运动表1转换为我们熟悉的代码是否类似于上面的MySupmarketShopping类呢。所谓的基元类型就是我们熟悉的int,long,string,byte…………。而多年的编码习惯让我们认为他们是表明事物属性再正常不过的单位但是就像两个调查表所给出的答案一样这样的代码很迷惑至少会给其他读你代码的人造成一些小障碍。值对象是内聚并且可以具有行为接下来是实现我们上文那个Money值对象的时候了。这是一个生活中很常见的一个场景所以有可能我们建立出来的值对象是这样的class Money{ public int Amount { get; set; } public Currency Currency { get; set; } public Money(int amount,Currency currency) { this.Amount amount; this.Currency currency; }}Money对象中我们还引入了一个叫做币种Currency)的对象它同样也是值对象表明了金钱的种类。接下来我们更改我们上面的MySupmarketShopping。public class MySupmarketShopping{ public Money Amountofmoney { get; set; }}你会发现我们将原来MySupmarketShopping类中的币种属性通过转换为一个新的值对象后给了money对象。因为币种这个概念其实是属于金钱的它不应该被提取出来从而干扰我的购物。此时Money值对象已经具备了它应有的属性了那么就这样就完成了吗还是一个问题的思考也许我在国外的超市购物我需要将我的人民币转换成为美元。这对我们编码来说它是一个行为动作因此可能是一个方法。那么我们将这个转换的方法放在哪儿呢给MySupmarketShopping很显然你一下就知道如果有Money这个值对象在的话转换这个行为就不应该给MySupmarketShopping而是属于Money。然后Money类就理所当然的被扩充为了这个样子class Money{ public int Amount { get; set; } public Currency Currency { get; set; } public Money(int amount,Currency currency) { this.Amount amount; this.Currency currency; } public Money ConvertToRmb(){ int covertAmount Amount / 6.18; return new Money(covertAmount,rmbCurrency); }}请注意在这个行为完成后我们是返回了一个新的Money对象而不是在当前对象上进行修改。这是因为我们的值对象拥有一个很重要的特性不可变性。值对象是不可变的一旦创建好之后值对象就永远不能变更了。相反任何变更其值的尝试其结果都应该是创建带有期望值的整个新实例。来看一个例子其实我们在平时的编码过程中有些类型就是典型的值对象只是我们当时并没有这个完整的概念体系去发现。比如在.NET中DateTime类就是一个经典的例子。有的编程语言他的基元类型其实是没有日期型这种说法的比如Go语言中是通过引入time的包实现的。尝试一下如果不用DateTime类你会怎么去表示日期这一个概念又如何实现日期之间的相互转换比如DateTime所提供的AddDaysAddHours等方法。这是一个现实项目中的一个案例也许你能通过它加深值对象概念在你脑海中的印象。该案例的需求是将一个时间段内的一部分时间段扣除并且返回剩下的小时数。比如有一个时间段 12:00 - 14:00.另一个时间段 13:00 - 14:00。返回小时数1。//代码片段 1 string StartTime_ Convert.ToDateTime(item[StartTime]).ToString(HH:mm); string EndTime_ Convert.ToDateTime(item[EndTime]).ToString(HH:mm); string CurrentStart_ Convert.ToString(item[CurrentStart]); string CurrentEnd_ Convert.ToString(item[CurrentEnd]); //计算开始时间 string[] s StartTime_.Split(:); double sHour double.Parse(s[0]); double sMin double.Parse(s[1]); //计算结束时间 string[] e EndTime_.Split(:); double eHour double.Parse(e[0]); double eMin double.Parse(e[1]); DateTime startDate_ hDay.AddHours(sHour).AddMinutes(sMin); DateTime endDate_ hDay.AddHours(eHour).AddMinutes(eMin); TimeSpan ts new TimeSpan(); if (StartDate startDate_ EndDate endDate_) { ts endDate_ - startDate_; } else if (StartDate startDate_ EndDate startDate_ EndDate endDate_) { ts EndDate - startDate_; } else if (StartDate startDate_ StartDate endDate_ EndDate endDate_) { ts endDate_ - StartDate; } else if (StartDate startDate_ StartDate endDate_ EndDate startDate_ EndDate endDate_) { ts EndDate - StartDate; } if (OverTimeUnit minute) { Duration_ Duration_ ts.TotalMinutes ? Duration_ - ts.TotalMinutes : 0; } else if (OverTimeUnit hour) { Duration_ Duration_ ts.TotalMinutes ? Duration_ - ts.TotalMinutes : 0; }//代码片段 2 DateTimeRange oneRange new DateTimeRange(oneTime,towTime); DateTimeRange otherRange new DateTimeRange(oneTime,towTime); var resultHours oneRange.GetRangeHours() - oneRange.GetAlphalRange(otherRange);首先来看一看代码片段1使用了传统的方式来实现该功能。但是里面使用大量的基元类型来描述问题可读性和代码量都很复杂。接下来是代码片段2在实现该过程时我们先尝试寻找该问题模型中的共性因此提取出了一个叫做时间段DateTimeRange类的值对象出来而赋予了该值对象应有的行为和属性。//展示了DateTimeRange代码的部分内容public class DateTimeRange{ private DateTime _startTime; public DateTime StartTime { get { return _startTime; } } private DateTime _endTime; public DateTime EndTime { get { return _endTime; } } public DateTimeRange GetAlphalRange(DateTimeRange timeRange) { DateTimeRange reslut null; DateTime bStartTime _startTime; DateTime oEndTime _endTime; DateTime sStartTime timeRange.StartTime; DateTime eEndTime timeRange.EndTime; if (bStartTime eEndTime oEndTime sStartTime) { // 一定有重叠部分 DateTime sTime sStartTime bStartTime ? sStartTime : bStartTime; DateTime eTime oEndTime eEndTime ? eEndTime : oEndTime; reslut new DateTimeRange(sTime, eTime); } return reslut; }}通过寻找出的该值对象并且丰富值对象的行为。为我们编码带来了大量的好处。值对象的持久化有关值对象持久化的问题一直是一个非常棘手的问题。这里我们提供了目前最为常见的两种实现思路和方法供参考。而该方法都是针对传统的关系型数据库的。因为Nosql的特性所以无需考虑这些问题将值对象映射在表的字段中该方法也是微软的官方案例Eshop中提供的方案通过EFCore提供的固有实体类型形式来将值对象存储在依赖的实体表字段中。具体的细节可以参考 EShop实现值对象。通过该方法我们最后持久化出来的结果比较类似于这样将值对象单独用作表来存储该方式在持久化时将值对象单独存为一张表并且以依赖对象的ID主为自己的主键。在获取时用Join的方式来与依赖的对象形成关联。可能持久化出来的结果就像这样可能没有完美的持久化方式正如这个小标题一样目前可能并没有完美的一个持久化方式来供关系型数据库持久化值对象。方式一的方式可能会造成数据大量的冗余毕竟对值对象来说只要值是一样的我们就认为他们是相等的。假如有一个地址值对象的值是“四川”那么有100w个用户都是四川的话那么我们会将该内容保存100w次。而对于一些文本信息较大的值对象来说这可能会损耗过多的内存和性能。并且通过EFCore的映射获取值对象也有一个问题你很难获取倒组合关系的值对象比如值对象A中有值对象B值对象B中有值对象C。这对于建模值对象来说可能是一个很正常的事情但是在进行映射的时候确非常困难。对于方式二来说建模中存在了大量的值对象我们在持久化时不得不对他们都一一建立一个数据表来保存这样造成数据库表的无限增多并且对于习惯了数据库驱动开发的人员来说这可能是一个噩梦当尝试通过数据库来还原业务关系时这是一项非常艰难的任务。总之还是那句话目前依旧没有一个完美的解决方案你只能通过自己的自身条件和从业经验来进行对以上问题的规避从而达到一个折中的效果。总结总结可能就是没有总结了吧。有时间的话继续扩充战术模式中其它关键概念实体仓储领域服务工厂等的文章。
http://www.zqtcl.cn/news/850045/

相关文章:

  • 做租号玩网站赚钱吗网站下的源代码和自己做的区别
  • 关于校园网站的策划书久久建筑网的账号
  • 网站宣传的方式怎么查看一个网站有没有做推广
  • 台州房产网站建设自助开通网站
  • 佛山正规网站建设报价二级域名需要申请吗
  • 网站用户体验比较论坛类网站可以做移动端吗
  • 佛山网站优化建设网站设计公司种类
  • 永嘉高端网站建设效果空间设计手法有哪些
  • 好模板网站盐城做网站价格
  • 农村自建房设计图 效果图常州百度推广优化
  • 北京便宜网站建设为什么自己做的网站别的电脑打不开
  • 濮阳网站建设哪里便宜html页面模板
  • 个人推广网站wordpress 交友模板
  • 新乡网站建设价格中国反钓鱼网站联盟
  • 在线工具网站网站建设公司ejiew
  • 个人搭建网站教程王牌网站做代理
  • 网站地图什么意思电子商务营销推广
  • 手机排行榜网站教育平台网站开发
  • 佛山市顺德区建设局网站萧山网站建设
  • 合肥百度团购网站建设怀化网站开发
  • 网站建设ppt模板彩票网站开发dadi163
  • 网站建设4435建筑设计一般用什么软件
  • 河南网站建设重庆森林台词
  • 网站一直没收录雄安做网站
  • 全国网站直播平台被摧毁响应是网站怎么做
  • 衡阳建设网站做网站和app多少费用
  • 怎么做付费网站蚌埠网站建设专业公司哪家好
  • 学网站建设需要多长时间成都网站建设定制开发服务
  • 建站宝盒后台深圳建网站公司怎么选择
  • 什么是大型门户网站网站建设的经验之谈