65.9K
CodeProject 正在变化。 阅读更多。
Home

理解开闭原则和依赖倒置

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (26投票s)

2013年5月2日

CPOL

3分钟阅读

viewsIcon

42429

本文将帮助你更好地理解 OCP 和 DI。

引言

在这里,我将讨论 S<code>OLID 的开放封闭原则和依赖倒置原则。SOLID 是什么意思?SOLID 是一种面向对象的设计原则,其中每个字母都有其自身的含义。

  • S-> 单一职责
  • O-> 开放封闭
  • L-> 里氏替换
  • I-> 接口隔离
  • D-> 依赖倒置

根据 维基百科,SOLID 的定义是

"SOLID 是可以在软件开发中应用的指南,通过使程序员重构软件的源代码,直到它既清晰又可扩展,来消除代码异味"

Using the Code

在开始技术讨论之前,我想回答以下问题

什么是开放封闭原则?

答案:软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭

什么是依赖倒置?

答案

  • 高级模块不应该依赖于低级模块。两者都应该依赖于抽象。
  • 抽象不应依赖于细节。细节应依赖于抽象。

让我们考虑一个例子来更好地理解它。假设我需要一台计算机,但还没有决定我需要笔记本电脑、台式机、平板电脑或其他设备。假设我去了电脑商店,要求买一台台式电脑。让我们把我的需求转换成代码。

public class Desktop 
{
    public string GetComputerDescription()
    {
        return " You get a Desktop";
    }
}

public class Laptop
{   
    public string GetComputerDescription()
    {
        return " You get a Laptop";
    }
}

public class ComputerShop
{
    public enum ComputerType
    {
        Laptop, Desktop
    }
 
    public ComputerShop()
    {
    }
    public string GetMyComputerDescription(ComputerType cmptype)
    {
        var myComp = string.Empty;
        if (ComputerType.Desktop == cmptype)
        {
            myComp = new Desktop().GetComputerDescription();
        }
        else if (ComputerType.Laptop == cmptype)
        {
            myComp = new Laptop().GetComputerDescription();
        }       
        return myComp;
    }
}

所以,我要买一台台式电脑,对吧?

var computerShop = new ComputerShop();
computerShop.GetMyComputerDescription(ComputerShop.ComputerType.Desktop);

如果运行代码,它将执行良好并给出输出“你得到了一台台式机”。那么有什么问题呢?在这里,我们违反了 OCP(开放封闭原则)和 DI(依赖倒置)的规则。

  • 对修改关闭(我们违反了 OCP)
  • 高级模块不应该依赖于低级模块。两者都应该依赖于抽象。(我们违反了 DI)

仍然困惑?没问题,我来解释一下。

我们如何违反修改规则?

是的,我们通过在 GetMyComputerDescription 方法中创建 DesktopLaptop 类的对象来违反了该规则。因为如果出现一种新的类型,我们需要修改函数以及类枚举

我们如何违反 DI 原则?

是的,我们通过在高级对象 (ComputerShop) 上创建低级对象(DesktopLaptop)来违反了该原则。因此,高级模块 (ComputerShop) 依赖于低级模块(Laptopdesktop),并且这里没有抽象。

现在,我添加一个新的类型 (Tablet) 并通过违反 OCP 来修改我的类。看看下面违反的代码

public class ComputerShop
{
    public enum ComputerType
    {
        Laptop, Desktop, Tablet  // Violation of OCP
    }
 
    public ComputerShop()
    {
    }
    public string GetMyComputerDescription(ComputerType cmptype)
    {
        var myComp = string.Empty;
        if (ComputerType.Desktop == cmptype)
        {
            myComp = new Desktop().GetComputer();
        }
        else if (ComputerType.Laptop == cmptype)
        {
            myComp = new Laptop().GetComputer();
        }                                         // Violation of OCP
        else if (ComputerType.Tablet == cmptype)
        {
            myComp = new Tablet().GetComputer();
        }
        return myComp;
    }
} 

你注意到违规了吗?是的,我们修改了类,因为引入了新的类型。现在让我们遵循 OCP 和 DI 规则并实现一个新的结构。如果我们可以在不创建商店类中的对象的情况下获得所需的计算机,那么我们就可以实现我们的目标。现在我们将引入抽象。

public interface IComputer
{
    string GetComputerDescrption();
}
 
public class Desktop : IComputer
{
   
    public string GetComputerDescrption()
    {
        return " You get a Desktop";
    }
}
public class Laptop:IComputer
{   
    public string GetComputerDescrption()
    {
        return " You get a Laptop";
    }
}
public class Tablet : IComputer
{
    public string GetComputerDescrption()
    {
        return " You get a new Tablet yahooooooooooooooooo";
    }
}

public class ComputerShop
{   
    public string GetMyComputerDescription(IComputer cmptype)
    {
        // No matter how many types of computer comes 
        var myComp = cmptype.GetComputerDescrption();
        return myComp;
    }
}

var computer = new ComputerShop();
computer.GetMyComputerDescription(new Tablet());

我们引入一个接口 (IComputer) 以消除 ComputerShopDesktopLaptop 类中的依赖。此外,现在高级和低级模块都依赖于抽象,而不是彼此依赖,并且抽象不依赖于细节,因此如果细节发生更改,它们不应影响抽象(满足 DI)。现在我们扩展我们的新项目 (Tablet),而无需修改 ComputerShop 类(满足 OCP)。

关注点

因此,该接口提供了可扩展性并消除了依赖性。现在无论出现什么计算机类型,Shop 类都不需要依赖于任何低级模块。

public class AnotherNewItem: IComputer
{
    public string GetComputer()
    {
        return " You get a Another New Item Hurrayyyyyyy";
    }
}

它只是从抽象中提供了我们需要的产品

public class Shop
{   
    public string GetMyComputer(IComputer cmptype)
    {
        // No matter how many types of computer comes 
        var myComp = cmptype.GetComputer();
        return myComp;
    }
}

所以现在我们的代码满足了 DI 和 OCP。

© . All rights reserved.