c# – S.O.L.I.D要点遗漏点?

前端之家收集整理的这篇文章主要介绍了c# – S.O.L.I.D要点遗漏点?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经阅读了很多这方面的文章,但我还有两个问题.

问题#1 – 关于Dependency Inversion

It states that high-level classes should not depend on low-level
classes. Both should depend on abstractions. Abstractions should not
depend on details. Details should depend on abstractions.

例如 :

public class BirthdayCalculator
{
    private readonly List<Birthday> _birthdays;

    public BirthdayCalculator()
    {
        _birthdays = new List<Birthday>();// <----- here is a dependency
    }
...

修复:把它放在一个ctor.

public class BirthdayCalculator
{
    private readonly IList<Birthday> _birthdays;

    public BirthdayCalculator(IList<Birthday> birthdays) 
    {
        _birthdays = birthdays;
    }

>如果它将在ctor中 – 我必须在每次使用课程时发送它.所以在调用BirthdayCalculator类时我必须保留它.它可以这样做吗?
>我可以说,在修复之后,仍然 – IList< Birthday> _birthdays不应该在那里(IList中的生日) – 但它应该是IList< IBirthday>.我对吗 ?

问题#2 – 关于Liskov Substitution

derived classes must be substitutable for their base classes

或更准确:

Let q(x) be a property provable about objects x of type T. Then q(y)
should be true for objects y of type S where S is a subtype of T.

(已阅读this)

例如:

public abstract class Account
{
     public abstract void Deposit(double amount);
}

我有一节课:

public class CheckingAccount : Account
{
     public override void Deposit(double amount)
    {    ...
        _currentBalance += amount;
    }
}

银行想开一个按揭账户 – 所以:

public class MortgageAccount : Account
{

    public override void Deposit(double amount)
    {
        _currentBalance -= amount; //<-----notice the minus
    }
}

当有一个功能接受抵押作为账户并存款时,就会出现问题.

public class Bank
{
    public void ReceiveMoney(Account account,double amount)
    {
        double oldBalance = account.CurrentBalance;
        account.Deposit(amount); //oopssss?????
    }
}

所以这里违反了LSP.

但我不明白.

每个重写的方法在重写时都会执行不同的代码,因此它永远不会100%可替换!

该定义没有谈到“逻辑应该继续像在基类中一样(总是存入(添加)正数)”

例:

如果CheckingAccount类和MortgageAccount类都存入正数但MortgageAccount也登录到db会怎样?它还会打破LSP吗?中断/不制动LSP的边界是什么?

定义应该定义边界的内容.它没有说什么.

我错过了什么?

解决方法

LSP表示基类所做的任何承诺,子类也必须做出.在账户案例中,是的,这意味着从抵押贷款余额中扣除的存款相当混乱.对此的一种解决方法是,如果您认为余额是客户欠您的金额与您欠他的金额之间的差额. (我大约54%肯定这是“平衡”的原始含义.)积极的平衡可能意味着客户有钱,而负面的平衡可能意味着他欠钱.如果您无法解决它,以便您可以类似地处理这两个帐户,那么它们不应该相关 – 或者至少,不应该在基类上定义“存款”方法.

就DIP而言,它没有真正提到的是它并不适用于每行代码.最终你必须在某个地方有一个具体的课程.关键是要将对这些具体类的细节的依赖限制在绝对必须了解它们的代码部分,并尽可能地保持这些部分的数量和大小.这意味着尽可能使用尽可能多的通用接口.例如,如果您不需要List所做的所有保证(枚举的顺序,重复项的存在,空值等),那么您可以将_birthdays声明为IEnumerable.如果构造函数是唯一知道你的IEnumerable实际上是List的东西,那么你或多或少地遵守这个原则.

(但请注意:这并不意味着您可以通过简单地将所有内容声明为对象并根据需要进行向下转换来遵守DIP.向下转换本身可能会被视为违反DIP,因为您不再依赖于您的界面’提供了;你正试图找到一个更具体的.)

猜你在找的C#相关文章