初涉架构,怎么着将坏的代码重新编写翻译为好

和睦的题词表达:

 本文原版的书文者:Radoslaw Sadowski,原版的书文链接为:C# BAD PRACTICES: Learn how to make a good code by bad example。

本连串还会有其它著作,后续将慢慢翻译。

 

走向.NET架构设计—第三章—分层设计,初涉架构(中篇) 

引言:

自己的名字叫Radoslaw Sadowski,作者今天是多个微软本领开采人士。我从上马职业时就直接接触的微软技能.

在办事一年后,小编看出的身分相当差的代码的多少基本上都足以写成一整本书了。

这一个经验让本人成为了三个想要清洁代码的性反常伤者。

写那篇小说的指标是为着通过展现品质非常糟糕的类的事例来申明怎么着下笔出干净的、可延长的和可爱戴的代码。小编会通过好的书写情势和设计情势来分解坏的代码带来的标题,以至替换他的好的消除情势。

第大器晚成有的是本着这一个负有C#基础知识的开拓职员——作者博览会示一些科学普及的大谬不然,然后再突显一些让代码变得可读性的点子与才干。高等部分首要针对那个最少存有设计形式概念的开垦职员——作者将会来得完全彻底的、单元可测量检验的代码。

为了能够驾驭那篇小说你供给最少了然以下八个部分的基本知识:

  • C#语言
  • 依傍注入、工厂设计情势、计谋设计方式

本文中所涉及的例证都将会是现实中确确实实的现实性的天性,并非用装饰格局来做披萨或许用政策形式来做总括器那样的亲自过问。

(ps解释:看过设计方式相关的书籍的人相应会通晓好些个那地点的书本都以用这种例子,只是为着救助读者通晓设计情势)

                              图片 1          图片 2

因为自身发觉那体系型的出品倒霉用来分解,相反那么些理论性的例证却是极度切合用来在本文中做解释的。

咱俩经常会听到说并不是用那些,要用这一个,然而却不精晓这种替换的说辞。前日自己将会全力解释和说明那多少个好的书写习贯以致设计情势是真的是在挽留我们的花费生活!

此文为译文,原来的文章地址请点击。 本文通过重构贰个破烂代码,演说了哪些写出特出的代码。开辟职员及代码审查职员需依照此标准开辟和核查代码。此标准以C#为例,JAVA的童鞋生龙活虎并参照他事他说加以考查,C 的童鞋自行脑补吧。

  前言:自从上篇公布之后,大家陈述了成都百货上千标题,因为前篇讲的事物不是很深,也许大家看完今后并未有怎么感到.本章(前篇,中篇,后篇)的首要目标其实首先是提出糟糕的布置,然后相比较的提议三个相对相比合理的支行架构,同不日常候本篇也为延续汇报架构形式和设计方式等的篇章做个铺垫。

 提示:

  •  在本文中自个儿不会花时间来解说C#的风味和涉嫌格局等等(小编也讲解不完),网络有无数关于那方面包车型客车好的说理的例子。小编将聚焦陈述怎样在大家日常专门的职业中利用这个事物。
  • 事例是生机勃勃种相比便于的凸起我们要表明的主题素材的方法,不过只限于描述的主题材料——因为本人开掘当自个儿在读书如何饱含着首要代码的例证时,笔者意识在明亮作品的总体考虑方面会有不便。
  •  作者不是说笔者文中说的艺术是当世无双的解决措施,小编只是能保证这一个措施将会是让您的代码变得更加高素质的门道。
  • 自家并不关怀上边那个代码的怎么错误管理,日志记录等等。我要抒发的只是用来缓和日常编码一些难题的章程。

那就从头吧….


 

那个不佳透了的类...

下面的事例是我们现实中的类:

 1 public class Class1
 2 {
 3   public decimal Calculate(decimal amount, int type, int years)
 4   {
 5     decimal result = 0;
 6     decimal disc = (years > 5) ? (decimal)5/100 : (decimal)years/100; 
 7     if (type == 1)
 8     {
 9       result = amount;
10     }
11     else if (type == 2)
12     {
13       result = (amount - (0.1m * amount)) - disc * (amount - (0.1m * amount));
14     }
15     else if (type == 3)
16     {
17       result = (0.7m * amount) - disc * (0.7m * amount);
18     }
19     else if (type == 4)
20     {
21       result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));
22     }
23     return result;
24   }
25 }

地点这些事例真的是意气风发种比很差的书写情势。你能知道这些类是用来干嘛的么?这些事物是用来做一些意想不到的演算的么?大家作品就从他起首初阶来说学吧…

这段日子本人来告诉你,刚刚这三个类是用来当花费者在网络买东西的时候为他们总结对应折扣的折扣总括和管理的类。

-不敢相信 无法相信吧!

-可是那是真的!

这种写法真的是将难以阅读、难以维护和麻烦扩张那三种集合在风姿浪漫道了,并且装有着太差的书写习贯和谬误的形式。

而外还应该有任何什么难题么?

1.取名格局-从源代码中大家能够连蒙带猜推断出来这么些计算方法和出口结果是怎么。并且大家想要从这几个类中领到总括算法将会是大器晚成件十三分劳累的作业。

如此推动的加害是:

最悲惨的难点是:浪费时间,

图片 3

 

风流倜傥经大家须求满意顾客的商业咨询,要像他们来得算法细节,恐怕大家供给纠正这段代码,这将花费我们相当短的时间去领略大家的揣度方法的逻辑。尽管我们不记录她或重构代码,后一次我们/别的开辟人员再看这段代码的时候,依然须要花费相通的光阴来商讨这一个代码是干嘛的。况兼在改良的还要还轻便失误,导致原来的计算全体弄错。

 2.法力数字

 图片 4

在这里个事例中type是变量,你能猜到它意味着着客商账户的品级么?If-else if言辞是用来兑现如何筛选计算出产品价格折扣的章程。

后日我们不亮堂哪些的账户是1,2,3或4。现在设想一下,当你只好为了那么些有价值的VIP顾客退换她们的折扣总括方法的时候,你试着从那多少个代码中寻找改善的措施---这一个历程恐怕会开销你十分长的年月不说,还很有不小恐怕犯错以致于改良这些基础的貌似的客户的账户,毕竟像2依旧3那些用语毫无描述性的。可是在我们犯错现在,那么些日常的顾客却很欢快,因为她们获得了VIP顾客的折扣。:)

3.并未有明确性的bug

因为大家的代码质量非常差,何况可读性很糟糕,所以大家兴许随意就忽视掉比超级多足够关键的业务。想象一下,今后溘然在系统中加进风度翩翩种新的客商类型-金卡客户,而在大家的系统中其余一种新的账户类型最后收获的价位将是0元。为啥吧?因为在大家的if-else if语句中从不别的动静是知足新的情状的,所以生机勃勃旦是未管理过的账户类型,最终再次回到值都将形成0。风度翩翩旦我们的董事长娘开采那事,他将会大动肝火-终归她早就免费卖给这么顾客超多众多东西了!

图片 5

4.从未可读性

作者们亟须承认下面这段代码的可读性是真的不得了。

他让我们开支了太多的时刻去精通这段代码,同不常间代码隐瞒不当的概率太大了,而那正是还没可读性的最关键的定义。

 5.法力数字(再一次)

你从代码中能知道好像0.1,0.7,0.5那几个数字的情致么?好的,笔者承认本人不知底。只有大家同舟共济编写那一个代码大家才理解那是什么样意思,别人是力所不及清楚的。

你尝试想想假使让您改改上边那句代码,你会怎样:

result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));

因为这么些办法完全不行读,所以您改改的进度中只好尝试着把第贰个0.5改成0.4而保持第三个0.5不懂。那恐怕会是一个bug,可是却是最棒的最合适的矫正章程。因为那个0.5怎么都未有报告我们。

无差距于的事也设有将years变量调换来disc变量的改换进程中:

decimal disc = (years > 5) ? (decimal)5/100 : (decimal)years/100;

那是用来测算折扣率的,会通过账户在我们系统的时光的百分比来获取。好的,那么将来主题材料来了,如若时间刚刚好就是5啊?

6.轻便-不要频仍做无用功

虽说第意气风发当即的时候不易于看出来,不过留神钻探一下就能够发掘:大家的代码里有相当多再一次的地点。举个例子:disc * (amount - (0.1m * amount));

而与之有相参照他事他说加以考察劳的还应该有(只是变了三个参数而已):初涉架构,怎么着将坏的代码重新编写翻译为好的代码。disc * (amount - (0.5m * amount))

在这里多个算术中,唯大器晚成的区分就只是三个静态参数,而作者辈一同能够用一个可变的参数来代表。

假诺我们不试着在写代码的时候从平素ctri c,ctrl v中脱身出来,那大家将遭受的主题素材正是我们只可以改善代码中的部分功效,因为大家不领悟有稍许地点需求改进。上边包车型大巴逻辑是计量出在我们系统中各样顾客对应年限得到的折扣,所以只要大家只是贸然修改两到三处,比较轻巧导致别的地点的上下分化等。

7.每一个类具备太多的纷纭的权力和权利区域

我们写的类最少背负了八个职分:

  1. 选用总结的运算法则
  2. 为每一种分歧处境的账户总计折扣率
  3. 依据种种客人的限制期限总括出相应的折扣率

以此背离了纯粹义务原则。那么那会带来怎样损伤吗?要是大家想要退换向上申诉3个特征中的多少个,那就象征大概会碰触到有的别样的大家并不想改过的本性。所以在改变的时候大家一定要重新测量检验全体的类,那么那就导致了比较重的日子的萧条。

简介

那篇文章的指标是展现什么将后生可畏段垃圾代码重构成三个到底的、可扩大性和可爱抚的代码。小编将表明什么通过拔尖推行和越来越好的设计方式来改写它。

阅读本文你需求有以下基础:

  • c# 基础
  • 依靠注入,工厂格局,攻略格局

此文中的例子源于实际项目,这里不会有哪些使用装饰情势塑造的披萨,也不会采用政策格局的计算器,那个事例是非常好的求证,不过它们很难被在事实上项目中选用。

本篇的议题如下:

1. style="font-family: 黑体; color: red">注解示例须要

2. style="font-family: 金鼎文; color: red">业务层设计

3. style="font-family: 金鼎文; color: red">服务层设计

4. style="font-family: 燕书; color: red">数据访问层设计

5. style="font-family: 燕书; color: red">显示层设计

6. style="color: red">UI style="font-family: 宋体; color: red">层设计

那就起来重构吧…

在接下去的9个步骤中本身将向您显得大家如何幸免上诉难点来创设一个到底的易维护,同一时候又便于单元测量检验的看起来一览无遗的代码。

 

意气风发段垃圾代码

在大家真正的制品中有像这种类型三个类:

public class Class1
{
public decimal Calculate(decimal amount, int type, int years)
{
decimal result = 0;
decimal disc = (years > 5) ? (decimal)5/100 : (decimal)years/100; 
if (type == 1)
{
  result = amount;
}
else if (type == 2)
{
  result = (amount - (0.m * amount)) - disc * (amount - (0.m * amount));
}
else if (type == 3)
{
  result = (0.m * amount) - disc * (0.m * amount);
}
else if (type == 4)
{
  result = (amount - (0.m * amount)) - disc * (amount - (0.m * amount));
}
return result;
}
}

那是生机勃勃段比非常糟糕的代码(二胡:如果您没感到这段代码非常不佳,那你日前情景大概很倒霉了),大家不太明白这一个类的目标是哪些。它恐怕是一个网络商铺的折扣管理类,担当为客户总结折扣。

其风姿罗曼蒂克类完全具备了不可读、不可维护、不可扩展的表征,它采用了好多坏的履行和反格局的陈设性。

上面大家稳步解析这里毕竟有稍许难题?

  • 命名难题 - 大家一定要通过估计这么些类到底是为了总括什么。那实则是在浪费时间。 借使大家从未相关文书档案只怕重构这段代码,那大家下一回可能须要花一大波的岁月能力精晓这段代码的现实意思。

  • 魔数 - 在此个事例中,你能猜到变量type是指顾客账户的图景吧。通过if-else来选拔总计打折后的产品价格。 以往,大家压根不亮堂账户状态1,2,3,4分级是如何意思。 别的,你驾驭0.1,0.7,0.5都以何许看头吧? 让大家想像一下,假让你要修正下边那行代码: result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));

  • 掩没的BUG - 因为代码特别不好,我们只怕会失去特别主要的事体。试想一下,假诺大家的系统中新添了大器晚成类账户状态,而新的账户等第不满意任何二个if-else条件。那时,再次来到值会固定为0。

  • 不得读 - 大家一定要承认,那是后生可畏段不可读的代码。不可读=更加多的知情时间 扩充发生错误的危害

  • DKugaY – 不要产生重复的代码 我们大概不可能一眼就找寻它们,但它们确实存在。 举个例子:disc *(amount - (0.1m * amount)); 肖似的逻辑: disc *(amount - (0.5m * amount)); 这里唯有多少个数值不相近。假设大家不能够摆脱再一次的代码,大家会遇上超级多标题。比方某段代码在七个地点有双重,当我们须要改良那部分逻辑时,你相当的大概只修改到了2至3处。

  • 单纯任务规范 那些类最少存有多个义务: 1 选取总括算法 2 根据账户状态总括折扣 3 依照账户网龄总计折扣 它违反了单一职责标准。这会带动怎么着危机?纵然大家将在订正第多个功效的话,会影响到其余第1个职能。那就意味着,大家每一回改良都会改换我们本不想更正的代码。由此,大家只好对任何类举办测量检验,那件事实上很浪费时间。

 ** ** **

I:命名,命名,命名

恕作者直言,那是代码中最注重的一步。大家只是修章/参数/变量这几个的名字,而近年来大家能够直观的询问到下边这几个类代表怎么样看头。

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, int accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100; 
 7     if (accountStatus == 1)
 8     {
 9       priceAfterDiscount = price;
10     }
11     else if (accountStatus == 2)
12     {
13       priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
14     }
15     else if (accountStatus == 3)
16     {
17       priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
18     }
19     else if (accountStatus == 4)
20     {
21       priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
22     }
23  
24     return priceAfterDiscount;
25   }
26 }

尽管如此这么,大家依旧不领悟1,2,3,4象征着怎么,那就无冕往下呢!

重构

通过以下9布,作者会告诉你们怎么制止上述风险并落实贰个干净的、可保证的、可测验的代码。

  1. 取名,命名,命名 那是可观代码的最重要方面之黄金时代。大家只必要校订方法,参数和变量的命名。今后,我们能够确切的驾驭上边的类是背负什么的了。

    public decimal ApplyDiscount(decimal price, int accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
        if (accountStatus == 1)
        {
            priceAfterDiscount = price;
        }
        else if (accountStatus == 2)
        {
            priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
        }
        else if (accountStatus == 3)
        {
            priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
        }
        else if (accountStatus == 4)
        {
            priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
        }
    
        return priceAfterDiscount;
    }
    

    不过大家任然不知情账户状态1,2,3到底是怎么着意思。

  2. 魔数 在C#中幸免魔数大家常常选择枚举来替换它们。这里运用AccountStatus 枚举来替换if-else中的魔数。 public enum AccountStatus {   NotRegistered = 1,   SimpleCustomer = 2,   ValuableCustomer = 3,   MostValuableCustomer = 4 } 以后我们来探视重构后的类,大家可以超级轻便的揭露哪一个账户状态应当用怎么样算法来计量折扣。混合账户状态的高危害急迅的低沉了。

    public class DiscountManager
    {
        public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
        {
            decimal priceAfterDiscount = 0;
            decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
    
            if (accountStatus == AccountStatus.NotRegistered)
            {
                priceAfterDiscount = price;
            }
            else if (accountStatus == AccountStatus.SimpleCustomer)
            {
                priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
            }
            else if (accountStatus == AccountStatus.ValuableCustomer)
            {
                priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
            }
            else if (accountStatus == AccountStatus.MostValuableCustomer)
            {
                priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
            }
            return priceAfterDiscount;
        }
    }
    
  3. 愈来愈多的代码可读性 在此一步中,我们选取switch-case 来替换 if-else if来进步代码可读性。 相同的时间,我还将或多或少长度相当长的语句才分成两行。举例:**priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));** 被更改为: **priceAfterDiscount = (price - (0.5m * price));priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);** 以下是总体的退换:

    public class DiscountManager
    {
        public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
        {
            decimal priceAfterDiscount = 0;
            decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
            switch (accountStatus)
            {
                case AccountStatus.NotRegistered:
                    priceAfterDiscount = price;
                    break;
                case AccountStatus.SimpleCustomer:
                    priceAfterDiscount = (price - (0.1m * price));
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
                case AccountStatus.ValuableCustomer:
                    priceAfterDiscount = (0.7m * price);
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
                case AccountStatus.MostValuableCustomer:
                    priceAfterDiscount = (price - (0.5m * price));
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
            }
            return priceAfterDiscount;
        }
    }
    
  4. 免除隐形的BUG 正如大家事先涉嫌的,大家的ApplyDiscount方法或然将为新的客商景况再次回到0。 大家怎么着能力消除这么些难点?答案正是抛出NotImplementedException。 当大家的法子赢得账户状态作为输入参数,可是参数值恐怕含有大家未规划到的茫然情状。那时候,我们不可能如何也不做,抛出极其是此时最棒的做法。

        public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
        {
            decimal priceAfterDiscount = 0;
            decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
            switch (accountStatus)
            {
                case AccountStatus.NotRegistered:
                    priceAfterDiscount = price;
                    break;
                case AccountStatus.SimpleCustomer:
                    priceAfterDiscount = (price - (0.1m * price));
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
                case AccountStatus.ValuableCustomer:
                    priceAfterDiscount = (0.7m * price);
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
                case AccountStatus.MostValuableCustomer:
                    priceAfterDiscount = (price - (0.5m * price));
                    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                    break;
                default:
                    throw new NotImplementedException();
            }
            return priceAfterDiscount;
        }
    
  5. 深入分析算法 在此个例子中,大家通过多少个正规来总结客商折扣:

  • 账户状态
  • 账户网龄 通过网龄总计的算法都就如那样: (discountForLoyaltyInPercentage * priceAfterDiscount) 然则对于账户状态为ValuableCustomer的算法却是: 0.7m * price 大家把它纠正成和其他账户状态相符的算法: price - (0.3m * price)

         public class DiscountManager
        {
        public decimal ApplyDiscount(decimal price, AccountStatus     accountStatus, int timeOfHavingAccountInYears)
        {
        decimal priceAfterDiscount = 0;
        decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
        switch (accountStatus)
        {
            case AccountStatus.NotRegistered:
                priceAfterDiscount = price;
                break;
            case AccountStatus.SimpleCustomer:
                priceAfterDiscount = (price - (0.1m * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            case AccountStatus.ValuableCustomer:
                priceAfterDiscount = (price - (0.3m * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            case AccountStatus.MostValuableCustomer:
                priceAfterDiscount = (price - (0.5m * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            default:
                throw new NotImplementedException();
        }
        return priceAfterDiscount;
        }
        }
    
  1. 打消魔数的另意气风发种方式使用静态常量来替换魔数。0.1m,0.2m,0.3m,笔者m,大家并不知道它们是什么样看头。 此外decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;中,数字5也万分神秘。 大家一定要让它们更享有描述性,此时使用常量会是多个相比好的法子。 我们来定义一个静态类:

    public static class Constants
    {
    public const int MAXIMUM_DISCOUNT_FOR_LOYALTY = 5;
    public const decimal DISCOUNT_FOR_SIMPLE_CUSTOMERS = 0.1m;
    public const decimal DISCOUNT_FOR_VALUABLE_CUSTOMERS = 0.3m;
    public const decimal DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS = 0.5m;
    }
    

    跟着改过DiscountManager类:

    public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
        switch (accountStatus)
        {
            case AccountStatus.NotRegistered:
                priceAfterDiscount = price;
                break;
            case AccountStatus.SimpleCustomer:
                priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            case AccountStatus.ValuableCustomer:
                priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            case AccountStatus.MostValuableCustomer:
                priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price));
                priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
                break;
            default:
                throw new NotImplementedException();
        }
        return priceAfterDiscount;
    }
    }
    
  2. 消弭重复的代码 为了死灭重复的代码,这里将后生可畏部分算法提收取来。首先,我们创造四个扩展方法:

    public static class PriceExtensions
    {
    public static decimal ApplyDiscountForAccountStatus(this decimal price, decimal discountSize)
    {
        return price - (discountSize * price);
    }
    
    public static decimal ApplyDiscountForTimeOfHavingAccount(this decimal price, int timeOfHavingAccountInYears)
    {
        decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
        return price - (discountForLoyaltyInPercentage * price);
    }
    }
    

    由此艺术名称,我们就可见它的任务是如何,现在涂改大家的例子:

    public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        switch (accountStatus)
        {
            case AccountStatus.NotRegistered:
                priceAfterDiscount = price;
                break;
            case AccountStatus.SimpleCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS)
                  .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
                break;
            case AccountStatus.ValuableCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS)
                  .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
                break;
            case AccountStatus.MostValuableCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS)
                  .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
                break;
            default:
                throw new NotImplementedException();
        }
        return priceAfterDiscount;
    }
    }
    
  3. 去除没用的代码 我们相应写出简约的代码,因为简短的代码=减弱BUG产生的机率,何况也让大家收缩通晓事情逻辑的时辰。 大家开掘,这里二种情状的客户调用了同黄金时代的法子: .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears); 这里能够统一代码:

    public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        switch (accountStatus)
        {
            case AccountStatus.NotRegistered:
                priceAfterDiscount = price;
                break;
            case AccountStatus.SimpleCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS);
                break;
            case AccountStatus.ValuableCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS);
                break;
            case AccountStatus.MostValuableCustomer:
                priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS);
                break;
            default:
                throw new NotImplementedException();
        }
        priceAfterDiscount = priceAfterDiscount.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
        return priceAfterDiscount;
    }
    }
    

    9.末尾,获得透顶的代码 最终,让大家经过引入重视注入和工厂方法形式来收获最终的版本吧。 先来看卡最后结出:

    public class DiscountManager
    {
    private readonly IAccountDiscountCalculatorFactory _factory;
    private readonly ILoyaltyDiscountCalculator _loyaltyDiscountCalculator;
    
    public DiscountManager(IAccountDiscountCalculatorFactory factory, ILoyaltyDiscountCalculator loyaltyDiscountCalculator)
    {
        _factory = factory;
        _loyaltyDiscountCalculator = loyaltyDiscountCalculator;
    }
    
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
        priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
        return priceAfterDiscount;
    }
    }
    
    public interface ILoyaltyDiscountCalculator
    {
    decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears);
    }
    
    public class DefaultLoyaltyDiscountCalculator : ILoyaltyDiscountCalculator
    {
    public decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears)
    {
        decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
        return price - (discountForLoyaltyInPercentage * price);
    }
    }
    
    public interface IAccountDiscountCalculatorFactory
    {
    IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus);
    }
    
    public class DefaultAccountDiscountCalculatorFactory : IAccountDiscountCalculatorFactory
    {
    public IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus)
    {
        IAccountDiscountCalculator calculator;
        switch (accountStatus)
        {
            case AccountStatus.NotRegistered:
                calculator = new NotRegisteredDiscountCalculator();
                break;
            case AccountStatus.SimpleCustomer:
                calculator = new SimpleCustomerDiscountCalculator();
                break;
            case AccountStatus.ValuableCustomer:
                calculator = new ValuableCustomerDiscountCalculator();
                break;
            case AccountStatus.MostValuableCustomer:
                calculator = new MostValuableCustomerDiscountCalculator();
                break;
            default:
                throw new NotImplementedException();
        }
    
        return calculator;
        }
    }
    
    public interface IAccountDiscountCalculator
    {
    decimal ApplyDiscount(decimal price);
    }
    
    public class NotRegisteredDiscountCalculator : IAccountDiscountCalculator
    {
    public decimal ApplyDiscount(decimal price)
    {
        return price;
    }
    }
    
    public class SimpleCustomerDiscountCalculator : IAccountDiscountCalculator
    {
    public decimal ApplyDiscount(decimal price)
    {
        return price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price);
    }
    }
    
    public class ValuableCustomerDiscountCalculator : IAccountDiscountCalculator
    {
    public decimal ApplyDiscount(decimal price)
    {
        return price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price);
    }
    }
    
    public class MostValuableCustomerDiscountCalculator : IAccountDiscountCalculator
    {
    public decimal ApplyDiscount(decimal price)
    {
        return price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price);
    }
    }
    

    第风度翩翩,大家摆脱了增加方法(静态类),若是大家想对ApplyDiscount措施开展单元测量试验是相比不方便的,废除大家对PriceExtensions扩张类也实行测验。 为了幸免那一个难题,我们创建了DefaultLoyaltyDiscountCalculator 类来替换ApplyDiscountForTimeOfHavingAccount这么些扩张方法,此类还落到实处了ILoyaltyDiscountCalculator接口。今后,当大家要测量试验DiscountManager类时,大家只构造函数注入ILoyaltyDiscountCalculator接口的落实就能够。这里运用了依据注入。 通过如此做,大家将网龄折扣的算法迁移到接近DefaultLoyaltyDiscountCalculator 的区别类中,那样当我们更改某一个算法不会覆盖到此外作业。 对于根据账户状态来计量折扣的政工,我们须求在DiscountManager中剔除八个任务:

  • 听新闻说账户状态选取计算的算法
  • 落实总计算法 这里大家经过DefaultAccountDiscountCalculatorFactory工厂类来消除这几个主题素材,DefaultAccountDiscountCalculatorFactory工厂类完毕了IAccountDiscountCalculatorFactory接口。 我们的工厂将决定选拔哪二个倒扣算法。接着,工厂类被通过构造函数注入到DiscountManager类中。 上面笔者只要求在DiscountManager 中使用工厂: priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price); 以上,我们减轻了第三个难点,下边大家要求完成总买下账单法。根据账户状态,提供区别的算法,这刚刚合乎政策格局。我们须要构建四个政策:NotRegisteredDiscountCalculator,SimpleCustomerDiscountCalculator,MostValuableCustomerDiscountCalculator已经悬空出来的接口IAccountDiscountCalculator。 好了,以后大家有可意气风发段干净可读的代码了,这段代码中存有的类都只有二个任务:
  • DiscountManager - 管理
  • DefaultLoyaltyDiscountCalculator - 网龄总结折扣
  • DefaultAccountDiscountCalculatorFactory - 依据账户状态接纳折扣战术
  • NotRegisteredDiscountCalculator,SimpleCustomerDiscountCalculator,MostValuableCustomerDiscountCalculator-总结折扣算法 大家来相比较一下改正前后的代码:

    public class Class1
    {
    public decimal Calculate(decimal amount, int type, int years)
    {
        decimal result = 0;
        decimal disc = (years > 5) ? (decimal)5 / 100 : (decimal)years / 100;
        if (type == 1)
        {
            result = amount;
        }
        else if (type == 2)
        {
            result = (amount - (0.m * amount)) - disc * (amount - (0.m * amount));
        }
        else if (type == 3)
        {
            result = (0.m * amount) - disc * (0.m * amount);
        }
        else if (type == 4)
        {
            result = (amount - (0.m * amount)) - disc * (amount - (0.m * amount));
        }
        return result;
    }
    }
    

    修改后:

    public class DiscountManager
    {
    private readonly IAccountDiscountCalculatorFactory _factory;
    private readonly ILoyaltyDiscountCalculator _loyaltyDiscountCalculator;
    
    public DiscountManager(IAccountDiscountCalculatorFactory factory, ILoyaltyDiscountCalculator loyaltyDiscountCalculator)
    {
        _factory = factory;
        _loyaltyDiscountCalculator = loyaltyDiscountCalculator;
    }
    
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
        decimal priceAfterDiscount = 0;
        priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
        priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
        return priceAfterDiscount;
    }
    }
    

  1. 注脚示例必要

II:魔法数

在C#中防止现身不知道的法力数的方法是经过枚举来代替。作者经过枚举方法来代替在if-else if 语句中现身的取代账户状态的法力数。

1 public enum AccountStatus
2 {
3   NotRegistered = 1,
4   SimpleCustomer = 2,
5   ValuableCustomer = 3,
6   MostValuableCustomer = 4
7 }

明天在看我们重构了的类,大家能够超轻松的揭露这么些计算法规是用来依据不用状态来测算折扣率的。将账户状态弄混的概率就大幅减弱了。

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;
 7  
 8     if (accountStatus == AccountStatus.NotRegistered)
 9     {
10       priceAfterDiscount = price;
11     }
12     else if (accountStatus == AccountStatus.SimpleCustomer)
13     {
14       priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
15     }
16     else if (accountStatus == AccountStatus.ValuableCustomer)
17     {
18       priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
19     }
20     else if (accountStatus == AccountStatus.MostValuableCustomer)
21     {
22       priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
23     }
24     return priceAfterDiscount;
25   }
26 }

总结

正文通过轻易易懂的措施重构了大器晚成段难点代码,它突显了怎么着在实质上意况中央银行使最好实践和设计方式来扶助大家写出到底的代码。 就笔者的干活经验来讲,本文中现身的不善做法是平时爆发的。编写这种代码的人连连感觉她们能够保证这种法规,但不幸的是系统和专业往往都会进一步复杂,每一回修正那类代码时都会带动宏大的高风险。

  本篇依然用事先的电子商务网址中的一个简便的面貌来陈说:在页面上急需出示产品的列表音讯。並且根据产品的档期的顺序差异,总计出相应的折扣。 

III:愈来愈多的可读性

在此一步中大家将经过将if-else if 语句改为switch-case 语句,来充实文章的可读性。

再就是,笔者也将四个很短的简政放权方法拆分为两句话来写。今后我们将“ 通过账户状态来计量折扣率”与“通过账户依期来测算折扣率”这两侧分别来总计。

例如:priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));

我们将它重构为:priceAfterDiscount = (price - (0.5m * price));
priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);

那正是更改后的代码:

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;
 7     switch (accountStatus)
 8     {
 9       case AccountStatus.NotRegistered:
10         priceAfterDiscount = price;
11         break;
12       case AccountStatus.SimpleCustomer:
13         priceAfterDiscount = (price - (0.1m * price));
14         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
15         break;
16       case AccountStatus.ValuableCustomer:
17         priceAfterDiscount = (0.7m * price);
18         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
19         break;
20       case AccountStatus.MostValuableCustomer:
21         priceAfterDiscount = (price - (0.5m * price));
22         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
23         break;
24     }
25     return priceAfterDiscount;
26   }
27 }

  在上篇中,大家曾经规划项指标逻辑分层。咱们再来回想下:

IV:未有鲜明性的bug

咱俩好不轻易找到大家隐蔽的bug了!

因为自身正要提到的我们的不二等秘书诀中对于不合乎的账户状态会在造成对于有着商品最终都重回0。固然特别不佳,但却是真的。

这大家该怎么修复这几个难点啊?那就只有因此对的误提醒了。

图片 6

您是或不是会想,那么些会不会是付出的比不上,应该不会被交给到不当提醒中去?不,他会的!

当我们的法门通过获得账户状态作为参数的时候,我们并不想程序让大家不可预知的大方向提高,变成不可预测的失误。

 这种场馆是纯属不一致意现身的,所以大家不得不通过抛出极其来防止这种景色。

上面包车型大巴代码正是经过抛出十二分后修改的以幸免现身不满意条件的动静-修正章程是将抛出非常幸免 switch-case语句中的default 句中。

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;
 7     switch (accountStatus)
 8     {
 9       case AccountStatus.NotRegistered:
10         priceAfterDiscount = price;
11         break;
12       case AccountStatus.SimpleCustomer:
13         priceAfterDiscount = (price - (0.1m * price));
14         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
15         break;
16       case AccountStatus.ValuableCustomer:
17         priceAfterDiscount = (0.7m * price);
18         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
19         break;
20       case AccountStatus.MostValuableCustomer:
21         priceAfterDiscount = (price - (0.5m * price));
22         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
23         break;
24       default:
25         throw new NotImplementedException();
26     }
27     return priceAfterDiscount;
28   }
29 }

 

V:深入分析盘算方式

在大家的例证中大家有五个概念给客商的折扣率的专门的学业:

  1. 账户状态;
  2. 账户在大家系统中留存的限制时间

对此年限的精兵简政折扣率的办法,全部的简政放权格局都有一些相符:

(discountForLoyaltyInPercentage * priceAfterDiscount)

理当如此,也依旧存在区别的:0.7m * price

之所以大家把这么些改成这么:price - (0.3m * price)

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;
 7     switch (accountStatus)
 8     {
 9       case AccountStatus.NotRegistered:
10         priceAfterDiscount = price;
11         break;
12       case AccountStatus.SimpleCustomer:
13         priceAfterDiscount = (price - (0.1m * price));
14         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
15         break;
16       case AccountStatus.ValuableCustomer:
17         priceAfterDiscount = (price - (0.3m * price));
18         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
19         break;
20       case AccountStatus.MostValuableCustomer:
21         priceAfterDiscount = (price - (0.5m * price));
22         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
23         break;
24       default:
25         throw new NotImplementedException();
26     }
27     return priceAfterDiscount;
28   }
29 }

这段时间我们将整合治理全数通过账户状态的图谋方式改为同风姿罗曼蒂克种格式:price - ((static_discount_in_percentages/100) * price)

图片 7

VI:通过其余事办公室法再摆脱法力数

接下去让我们的目光放在通过账户状态总结折扣率的猜测划办公室法中的静态变量:(static_discount_in_percentages/100)

接下来带入上面数字间隔试试:0.1m,0.3m,0.5m

这个数字其实也是生龙活虎体系型的法力数-他们也从没直接告知我们他们代表着怎么样。

作者们也会有同生龙活虎的意况,比方将“有账户的时刻”折价为“忠诚折扣”。

decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;

数字5让大家的代码变得神秘了起来。

小编们一定要做些什么让那一个变得更具表现性。

本人会用其余生龙活虎种艺术来防止法力数的表明的面世-约等于C#中的常量(关键词是const),小编刚烈提出在大家的应用程序中特地定义二个静态类来积攒那些常量。

在我们的事例中,作者是创设了上面包车型地铁类:

1 public static class Constants
2 {
3   public const int MAXIMUM_DISCOUNT_FOR_LOYALTY = 5;
4   public const decimal DISCOUNT_FOR_SIMPLE_CUSTOMERS = 0.1m;
5   public const decimal DISCOUNT_FOR_VALUABLE_CUSTOMERS = 0.3m;
6   public const decimal DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS = 0.5m;
7 }

通过一定的改进,大家的DiscountManager类就改成了如此了:

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY/100 : (decimal)timeOfHavingAccountInYears/100;
 7     switch (accountStatus)
 8     {
 9       case AccountStatus.NotRegistered:
10         priceAfterDiscount = price;
11         break;
12       case AccountStatus.SimpleCustomer:
13         priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price));
14         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
15         break;
16       case AccountStatus.ValuableCustomer:
17         priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price));
18         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
19         break;
20       case AccountStatus.MostValuableCustomer:
21         priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price));
22         priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
23         break;
24       default:
25         throw new NotImplementedException();
26     }
27     return priceAfterDiscount;
28   }
29 }

本人愿意您也承认自个儿这几个办法会愈加使代码本人变得更有着表达性:)

唯恐有的朋友认为从Smart UI登时跳到这种分层设计,就如快了些。其实也毕竟贰个图谋的踊跃吧。上面就来探视这种分层是怎样减轻此前SmartUI的主题素材的。 

VII:不要再重新啦!

图片 8

 

大家得以经过分拆算法的办法来移动大家的测算办法,并不是单独简单的复制代码。

大家会经过扩大方法。

首先大家会创制八个扩大方法。

 1 public static class PriceExtensions
 2 {
 3   public static decimal ApplyDiscountForAccountStatus(this decimal price, decimal discountSize)
 4   {
 5     return price - (discountSize * price);
 6   }
 7  
 8   public static decimal ApplyDiscountForTimeOfHavingAccount(this decimal price, int timeOfHavingAccountInYears)
 9   {
10      decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY/100 : (decimal)timeOfHavingAccountInYears/100;
11     return price - (discountForLoyaltyInPercentage * price);
12   }
13 }

正如方法的名字平常,小编不再需求单独解释贰次他们的功效是何许。以后就起来在大家的例证中选取这几个代码吧:

 

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     switch (accountStatus)
 7     {
 8       case AccountStatus.NotRegistered:
 9         priceAfterDiscount = price;
10         break;
11       case AccountStatus.SimpleCustomer:
12         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS)
13           .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
14         break;
15       case AccountStatus.ValuableCustomer:
16         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS)
17           .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
18         break;
19       case AccountStatus.MostValuableCustomer:
20         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS)
21           .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
22         break;
23       default:
24         throw new NotImplementedException();
25     }
26     return priceAfterDiscount;
27   }
28 }

扩大方法让代码看起来越发友善了,然而这些代码照旧静态的类,所以会让您单元测量试验的时候遭遇困难,以至不容许。那么出于摆脱这些主题素材的希图大家在最终一步来消除这一个标题。笔者将显得那几个是什么样简化我们的干活生活的。可是对于本人个人来讲,作者爱怜,可是并不算是热衷粉。

不管如何,你以往允许我们的代码看起来友善多了那一点么?

那大家就继续下去吧!

 

VIII:移除这一个多余的代码

在写代码的时候条件上是大家的代码越是精简越好。精简的代码的表示,越少的失实的恐怕性,在阅读驾驭代码逻辑的时候开支的光阴越少。

于是未来开班精简我们的代码吧。

咱们得以随性所欲发掘大家二种客户账户下具有雷同的法子:

.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);

咱俩行还是不行只写一回啊?大家从前将未注册的客商放在了抛出非常中,因为我们的折扣率只会臆度注册客商的为期,并从未给未注册顾客留有作用设定。所以,大家理应给未注册客户设定的小时为多少呢? -0年

那正是说相应的折扣率也将产生0了,那样我们就能够无思无虑的将折扣率交付给未注册客商采用了,这就从头吧!

 1 public class DiscountManager
 2 {
 3   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
 4   {
 5     decimal priceAfterDiscount = 0;
 6     switch (accountStatus)
 7     {
 8       case AccountStatus.NotRegistered:
 9         priceAfterDiscount = price;
10         break;
11       case AccountStatus.SimpleCustomer:
12         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS);
13         break;
14       case AccountStatus.ValuableCustomer:
15         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS);
16         break;
17       case AccountStatus.MostValuableCustomer:
18         priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS);
19         break;
20       default:
21         throw new NotImplementedException();
22     }
23     priceAfterDiscount = priceAfterDiscount.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
24     return priceAfterDiscount;
25   }
26 }

咱俩还足以将那风度翩翩行移除到switch-case语句外面。好处正是:越来越少的代码量!

  2.  业务层设计

IX:进步-最终的赚取通透到底整洁的代码

好了,以往我们能够像阅读一本书同样方便来审视大家的代码了,然而那就够了么?大家能够将代码变得最好轻易的!

图片 9

好的,那就从头做一些改观来兑现这一个指标吗。大家可以动用依赖注入和选用政策形式那二种形式。

那就是我们后天最后收拾出来的代码了:

 1 public class DiscountManager
 2 {
 3   private readonly IAccountDiscountCalculatorFactory _factory;
 4   private readonly ILoyaltyDiscountCalculator _loyaltyDiscountCalculator;
 5  
 6   public DiscountManager(IAccountDiscountCalculatorFactory factory, ILoyaltyDiscountCalculator loyaltyDiscountCalculator)
 7   {
 8     _factory = factory;
 9     _loyaltyDiscountCalculator = loyaltyDiscountCalculator;
10   }
11  
12   public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
13   {
14     decimal priceAfterDiscount = 0;
15     priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
16     priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
17     return priceAfterDiscount;
18   }
19 }

 1 public interface ILoyaltyDiscountCalculator
 2 {
 3   decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears);
 4 }
 5  
 6 public class DefaultLoyaltyDiscountCalculator : ILoyaltyDiscountCalculator
 7 {
 8   public decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears)
 9   {
10     decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY/100 : (decimal)timeOfHavingAccountInYears/100;
11     return price - (discountForLoyaltyInPercentage * price);
12   }
13 }

 1 public interface IAccountDiscountCalculatorFactory
 2 {
 3   IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus);
 4 }
 5  
 6 public class DefaultAccountDiscountCalculatorFactory : IAccountDiscountCalculatorFactory
 7 {
 8   public IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus)
 9   {
10     IAccountDiscountCalculator calculator;
11     switch (accountStatus)
12     {
13       case AccountStatus.NotRegistered:
14         calculator = new NotRegisteredDiscountCalculator();
15         break;
16       case AccountStatus.SimpleCustomer:
17         calculator = new SimpleCustomerDiscountCalculator();
18         break;
19       case AccountStatus.ValuableCustomer:
20         calculator = new ValuableCustomerDiscountCalculator();
21         break;
22       case AccountStatus.MostValuableCustomer:
23         calculator = new MostValuableCustomerDiscountCalculator();
24         break;
25       default:
26         throw new NotImplementedException();
27     }
28  
29     return calculator;
30   }
31 }

 1 public interface IAccountDiscountCalculator
 2 {
 3   decimal ApplyDiscount(decimal price);
 4 }
 5  
 6 public class NotRegisteredDiscountCalculator : IAccountDiscountCalculator
 7 {
 8   public decimal ApplyDiscount(decimal price)
 9   {
10     return price;
11   }
12 }
13  
14 public class SimpleCustomerDiscountCalculator : IAccountDiscountCalculator
15 {
16   public decimal ApplyDiscount(decimal price)
17   {
18     return price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price);
19   }
20 }
21  
22 public class ValuableCustomerDiscountCalculator : IAccountDiscountCalculator
23 {
24   public decimal ApplyDiscount(decimal price)
25   {
26     return price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price);
27   }
28 }
29  
30 public class MostValuableCustomerDiscountCalculator : IAccountDiscountCalculator
31 {
32   public decimal ApplyDiscount(decimal price)
33   {
34     return price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price);
35   }
36 }

先是大家摆脱了扩充方法(也正是静态类),之所以要摆脱这种是因为扩大方法与折扣总计格局之间存在了紧耦合的关系。假使大家想要单元测量检验大家的不二秘诀ApplyDiscount的时候将变得不太轻巧,因为我们亟须联合测验与之紧凑关联的类PriceExtensions。

为了幸免这几个,作者创造了DefaultLoyaltyDiscountCalculator 类,那之中包括了ApplyDiscountForTimeOfHavingAccount扩大方法,同事本身透过架空切口ILoyaltyDiscountCalculator暗藏了她的宛在如今贯彻。以后,当小编想测量检验我们的类DiscountManager的时候,小编就能够透过 ILoyaltyDiscountCalculator依傍注入假造对象到DiscountManager类中经过构造函数突显测验作用。这里大家利用的就叫信任注入方式。

图片 10

在做这一个的同一时候,我们也将总括折扣率这几个成效安全的移交到另一个不后生可畏的类中,假使大家想要改正那生机勃勃段的逻辑,那大家就只供给改正DefaultLoyaltyDiscountCalculator** **类就好了,而没有必要改动其余之处,那样收缩了在改动他的时候发生破坏其余地方的风险,同期也无需再追加单独测量试验的年华了。

上边是大家在DiscountManager类中应用分其余逻辑类:

priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);

为了针对账户状态的逻辑来测算折扣率,作者创造了部分相比较复杂的东西。大家在DiscountManager类中有多个权利要求解释出去。

  1. 据悉账户状态怎么着筛选相应的总结办法。
  2. 非凡总结方法的细节

为了将首先个职分移交出去,我创造了工厂类(DefaultAccountDiscountCalculatorFactory),为了兑现工厂形式,然后再把那么些隐形到虚幻IAccountDiscountCalculatorFactory里面去。

图片 11

大家的工厂会垄断取舍哪一种总计形式。最后大家透过信任注册形式构造函数将工厂方式注射到DiscountManager类中

上面就是选取了工厂的DiscountManager类:

priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);

 以上会针对分裂的账户状态重临何时的计策,然后调用ApplyDiscount 方法。

先是个权利已经被接通出去了,接下去正是第三个了。

 接下来我们就起来商量计策了…..

图片 12

因为分化的账户状态会有永不的折扣总括方法,所以大家供给不一样的兑现政策。座椅非常适用于政策情势。

在我们的例证中,我们有二种政策:

NotRegisteredDiscountCalculator SimpleCustomerDiscountCalculator MostValuableCustomerDiscountCalculator**

他们带有了切实的折扣总计方法的兑现并被藏在了聊以自慰IAccountDiscountCalculator里。

那就允许大家的类DiscountManager利用方便的安插,而无需知器械体的落到实处。大家的类只须求驾驭与ApplyDiscount方法相关的IAccountDiscountCalculator 接口再次来到的目的的花色。

NotRegisteredDiscountCalculator, SimpleCustomerDiscountCalculator, MostValuableCustomerDiscountCalculator那些类包括了具体的经过账户状态接纳切合总计的谋算办法的落实。因为大家的那多个政策看起来近似,大家唯黄金时代能做的基本上就独有针对那二种总括攻略创立多个形式然后各种战术类通过多个并不是的参数来调用她。因为那会让大家的代码变得愈加多,所以作者明日调整不那样做了。

好了,到如今停止大家的代码变得可读了,并且每一个类都独有一个权力和义务了-这样修正他的时候会独自意气风发大器晚成对应了:

  1. DiscountManager-管理代码流
  2. DefaultLoyaltyDiscountCalculator-可信赖的总计折扣率的方法
  3. DefaultAccountDiscountCalculatorFactory-决定依靠账户状态选取哪个计谋来总计
  4. **NotRegisteredDiscountCalculator, SimpleCustomerDiscountCalculatorMostValuableCustomerDiscountCalculator **– 依照账户状态总计折扣率

前些天开头比较今后与在此以前的不二等秘书诀:

 1 public class Class1
 2 {
 3     public decimal Calculate(decimal amount, int type, int years)
 4     {
 5         decimal result = 0;
 6         decimal disc = (years > 5) ? (decimal)5 / 100 : (decimal)years / 100;
 7         if (type == 1)
 8         {
 9             result = amount;
10         }
11         else if (type == 2)
12         {
13             result = (amount - (0.1m * amount)) - disc * (amount - (0.1m * amount));
14         }
15         else if (type == 3)
16         {
17             result = (0.7m * amount) - disc * (0.7m * amount);
18         }
19         else if (type == 4)
20         {
21             result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));
22         }
23         return result;
24     }
25 }

这是我们的新的重构的代码:

1 public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
2 {
3   decimal priceAfterDiscount = 0;
4   priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
5   priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
6   return priceAfterDiscount;
7 }

  记得在事先的斯马特 UI的例子中,程序的业务逻辑是平素写在了ASPX页前面边的cs代码中的。将来,接纳分段的措施,大家接纳了世界模型来组织来电子商务中的业务逻辑。

总结

在本文中,代码被Infiniti简化了,使得全体的才能和情势的解释更便于了。它展现了什么样消除广大的编程难点,以致利用非凡的进行和设计形式以适度、干净的措施减轻这么些问题的好处。

在自身的做事经验中,笔者反复在此篇文章中重申了蹩脚的做法。它们鲜明存在于广大选取场面,实际不是在一个类中,如在自己的例子中那样,那使得挖掘它们更是不便,因为它们隐蔽在适宜的代码之间。写这种代码的人三番五次争论说,他们依照的是简约鲁钝的平整。不幸的是,差不离具备的系统都在成年人,变得特别复杂。然后,这些大约的、不可扩张的代码中的每三个改革都是可怜关键的,并且带来了震天撼地的危害。

请记住,您的代码将长时间存在于生产条件中,并就要每一个职业需求变动上举行改正。因而编写过于简短、不可扩大的代码极快就能发生严重的结果。最终一点是对开拓人士有利,特别是那多少个在您本身事后维护你的代码。

举例你有风度翩翩对主题素材依据小说不要犹豫联系本人!

  有关世界模型的局部东西,大家在这起彼伏的作品中会疏解的。

图片 13PS:

基于随笔敲的源代码:

链接: 密码:9spz

  注:领域模型格局被规划用来组织复杂的事情逻辑和涉及。

 

  上边包车型大巴类图就显示了大家事先的电子商务的必要中所用到的业务模型。

图片 14

  Product类就代表了电子商务中的每贰个成品。

  Price类将会蕴藏可算折扣的业务逻辑,並且用政策格局来具体贯彻折扣的算法-。

  在Model加多一个接口类:IDiscountStrategy:

  

public interface IDiscountStrategy
{
        decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice);
}

 

 

 

  这么些接口就用来贯彻区别减价的计策,那是政策格局的朝气蓬勃种接纳。那么些格局允许大家在运行的时候改换分歧的算法完毕。在本例子中,普赖斯类将会基于分化的出品来得以达成不一致的降价计谋。在我们事先的极其SmartUI例子中,其实那一个优惠的算法大家早已写了,可是并未有抽离出来,导致了每一回加二个巨惠的算法的政策,程序就要求更改,重新编写翻译,安顿。也便是说降价的有的是个变化点,我们理应抽离出来的。 

注:战略方式:用一个类来封装三个算法的兑现,况且经过切换算法的落实允许在运维时改进叁个指标的一言一动。

 

在电子商务中,不是每一个商品都会减价的,其实大家要促成的减价战术只有生机勃勃种。不过尽管如此,大家在写代码的时候将要if-else剖断是不是是优惠的商品,其实这里依旧暴露了变化点的:假若国庆那天,全部的货物都巨惠了,那么大家就得改过代码。其实大家能够那样考虑:不减价的情事也毕竟意气风发种优惠,别的的货物减价可能是7折,不减价的事态就是10折。 

 

图片 15图片 16代码

 public class TradeDiscountStrategy : IDiscountStrategy 
{        
        public decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice)
        {
            decimal price = OriginalSalePrice;            
            
            price = price * 0.6M;            

            return price;
        }     
}

public class NullDiscountStrategy : IDiscountStrategy
{       
        public decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice)
        {
            return OriginalSalePrice;
        }
}

 

 

下边大家来拜见Price类的兑现。

 

图片 17图片 18代码

public class Price
{
        private IDiscountStrategy _discountStrategy = new NullDiscountStrategy(); 
        private decimal _rrp;
        private decimal _sellingPrice;

        public Price(decimal RRP, decimal SellingPrice)
        {
            _rrp = RRP;
            _sellingPrice = SellingPrice;
        }

        public void SetDiscountStrategyTo(IDiscountStrategy DiscountStrategy)
        {
            _discountStrategy = DiscountStrategy; 
        }

        public decimal SellingPrice
        {
            get { return _discountStrategy.ApplyExtraDiscountsTo(_sellingPrice); }
        }

        public decimal RRP
        {
            get { return _rrp; }
        }

        public decimal Discount
        {
            get { 
                if (RRP > SellingPrice) 
                    return (RRP - SellingPrice); 
                else
                    return 0;}
        }

        public decimal Savings
        {
            get{
                if (RRP > SellingPrice)
                    return 1 - (SellingPrice / RRP);
                else
                    return 0;}
        }        
}

  

  Price类在设计中正是用了“正视倒置原则”,因为它未有使用某一个切实可行的促销实现算法,何况信赖于接口抽象,至于今后毕竟会哪类的巨惠算法,其实是由商品的花色来决定的。 

  大家照旧继续的看,现在探视Product类。

  

public class Product
{
        public int Id { get; set; }
        public string Name { get; set; }
        public Price Price { get; set; }
}

 

        

         今后具有的事情实体就已经创设了。至于对商品是不是打折,其实这是由客商代码来调控:遵照客商代码传入的商品的类型区别,然后调用分歧的国策,采取了分裂的打折算法总结折扣。所以大家那边来添加贰个意味着商品类别的枚举:  

 public enum CustomerType
 {
        Standard = 0,
        Trade = 1
 }

 

 

  大家将会把筛选哪一类优惠的国策的逻辑写在三个独立之处,也正是说:只要客商代码传入相应的参数音信,大家就自动的创立三个适宜的巨惠计谋对象。很分明,这里能够动用工厂方法来实现,如下:  

 

图片 19图片 20代码

public static class DiscountFactory
{
        public static IDiscountStrategy GetDiscountStrategyFor(CustomerType customerType)
        {
            switch (customerType)
            {
                case CustomerType.Trade:
                    return new TradeDiscountStrategy(); 
                default:
                    return new NullDiscountStrategy(); 
            }
        }
}

 

 

  在地点的逻辑分层中,大家建设构造了三个Repository的类库,其实大家尽管想采用Repository情势来促成”持久化无关性”-----业务类完全不用管什么保存和获取数据。并且由Repository决定数据的根源和保存的地点,也许是数据库,也或许正是内部存款和储蓄器,不过不管怎么,业务类是并不是管这个的。所以上面用三个接口来促成灵活性:  

 

 public interface IProductRepository
 {
        IList<Product> FindAll();
 }

 

 

  若是以后有许多的货物,我们想知道她们的折扣价格,最轻巧易行的诀要就是遍历他们,决断项目,然后使用不一致的巨惠攻略。为了进一步的可读,我们可感到商品列表创设增添方法,如下:

  

图片 21图片 22代码

 public static class ProductListExtensionMethods
 {
      public static void Apply(this IList<Product> products, IDiscountStrategy discountStrategy)
      {
            foreach (Product p in products)
            {
                p.Price.SetDiscountStrategyTo(discountStrategy);
            }
      }
 }

 

 

  为了简化客商代码的调用职业,大家提供二个近乎门户(gateway),或许是Façade的概念:把复杂的操作逻辑遮盖,留给客户代码三个简易易用的API。大家这边创办二个Service类,如下:

  

图片 23图片 24代码

public class ProductService
{
   private IProductRepository _productRepository;

   public ProductService(IProductRepository productRepository)
   {
         _productRepository = productRepository;
   }

   public IList<Product> GetAllProductsFor(CustomerType customerType)
   {
      IDiscountStrategy discountStrategy = DiscountFactory.GetDiscountStrategyFor(customerType);
      IList<Product> products = _productRepository.FindAll();
      products.Apply(discountStrategy);
      return products;
    }    
}

 

 

  只要顾客代码(如出示层中的代码)直接调用上面包车型大巴方法就足以了,並且商品的折扣也依据传入的货品品种不相同来计算。

 

  3.       服务层设计

  服务层就出任应用程序的进口的角色。不时候,能够被感到是façade.不止如此,因为service分为领域逻辑的service和门户的service。门户的service平常为呈现层提供强类型的View Model(临时也叫做Presentation Model)。 贰个View Model正是给贰个特意的View来使用的。在本例中,大家将会树立Product的View Model来展现商品的消息。平日意况下,大家决不把事情类直接暴光给展现层,那样超轻易紧耦合,所以在中游就上二个View Model,其实View Model和业务类的组织基本上,只是View Model做了部分调动,便于最终的呈现。关于View Model详细的,后文陈说。

  注:Façade方式:为在那之中担负的子系统提供三个简练的接口供外界访谈。

** 

  下边大家就来探视Product的View Model是哪些写的:

 

图片 25图片 26代码

public class ProductViewModel
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public string RRP { get; set; }
        public string SellingPrice { get; set; }
        public string Discount { get; set; }
        public string Savings { get; set; }
    }

 

 

  可以观看,其实View Model就是做了大器晚成部分体现逻辑的管理。在这里处正是多加了一些字段,这个字段正是在UI的GridView中展现用的。大家前边的斯马特 UI的不二诀窍中,还确立了模版列来展现Product类中尚无的字段,其实就一定于在UI中作了一定的显得逻辑的拍卖。这里大家直接呈现ViewModel.

 

  大家应该很熟知Web 瑟维斯:在客商端和劳动使用供给/响应的消息机制进行通讯的。大家那边的客商代码和Service也利用这种格局,因为很有非常的大希望大家在配置的时候瑟维斯的代码和客户代码(展现层)在不一样机器上。

  须求的音信的组织如下:  

 

 public class ProductListRequest
 {
        public CustomerType CustomerType { get; set; }
 }

 

 

  服务在响应诉求的时候也要定义格式,并且大家能够在响应中参加越多的天性来推断这么些伏乞是或不是成功。所以在上面包车型大巴代码中,我们投入了Message属性,用来在伸手战败的时候显得错误音讯,还加多了一个Success属性用来剖断央浼的境况:  

 

public class ProductListResponse
{
   public bool Success { get; set; }
   public string Message { get; set; }
   public IList<ProductViewModel> Products { get; set; }
}

 

 

  还会有有些决不遗忘了:因为Product和它对应的View Model结构不风流罗曼蒂克的,而Service重返的又是ViewModel的响应,那么就须求把收获到的Product转变为View Model的布局。能够把转换的代码写在二个一定的地点(能够以为是个Mapping的历程),为了阅读的便利,大家可认为List<Product>加多扩大方法,直接调用,如下:

  

 

图片 27图片 28代码

public static class ProductMapperExtensionMethods
    {
        public static IList<ProductViewModel> ConvertToProductListViewModel(this IList<Model.Product> products)
        {
            IList<ProductViewModel> productViewModels = new List<ProductViewModel>();

            foreach(Model.Product p in products)
            {
                productViewModels.Add(p.ConvertToProductViewModel());  
            }

            return productViewModels;
        }

        public static ProductViewModel ConvertToProductViewModel(this Model.Product product)
        { 
            ProductViewModel productViewModel = new ProductViewModel();
            productViewModel.ProductId = product.Id;
            productViewModel.Name = product.Name;
            productViewModel.RRP =product.Price.RRP;
            productViewModel.SellingPrice =product.Price.SellingPrice;
            
            if (product.Price.Discount > 0)
                productViewModel.Discount = product.Price.Discount;

            if (product.Price.Savings < 1 && product.Price.Savings > 0)
                productViewModel.Savings = product.Price.Savings.ToString("#%");

            return productViewModel;
        }
    }

 

 

  最终,大家参预贰个ProductService来与业务层的瑟维斯 类实行交互,业务层的瑟维斯会重返商品列表,然后大家前不久增加的这么些ProductService会把列表转为ProductViewModels。

 

我们也许感到意外:为何这里增多了四个ProductService,在此以前在作业层加一个,今后又加贰个,是还是不是命名有标题照旧功用重新?其实在上生机勃勃篇已经提过:一时在事情层类增加一个service层,首如果用来协会业务流程的,日常要多少个业务类组合在同步利用,这样关键是为着简化顾客程序(也等于调用那么些业务层的代码)的调用,完毕相同Façade的职能。

 

大家以后丰硕的ProductService便是政工层中**service层**的客商程序,因为大家调用了业务层的service,往往不常,我们不想把本人系统的业务类的布局平素暴光给外部,如呈现层,而且也期待提供越来越适合突显层所需的数据结构,那么大家就增添了那么些ProductService,提供从事情类到ViewModel的转移。而且在这里个ProductSevice中,大家也能够兑现部分相当管理机制,如若波及到了布满式调用,那么我们还是可以用那一个Product瑟维斯类向展现层和UI那边遮掩遍及式的信息:实今世理格局。

昨日就写在到这里,在写的经过中发觉那篇有一些长了,所以分为3篇(前,中,后)发表!不知道的地点大家多探讨一下,也能够告知作者!下篇前日通知!见谅!

 

本文由星彩网app下载发布于计算机编程,转载请注明出处:初涉架构,怎么着将坏的代码重新编写翻译为好

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。