理解开闭原则和依赖倒置






4.72/5 (26投票s)
本文将帮助你更好地理解 OCP 和 DI。
引言
在这里,我将讨论 S<code>O
LID 的开放封闭原则和依赖倒置原则。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
方法中创建 Desktop
和 Laptop
类的对象来违反了该规则。因为如果出现一种新的类型,我们需要修改函数以及类枚举。
我们如何违反 DI 原则?
是的,我们通过在高级对象 (ComputerShop
) 上创建低级对象(Desktop
和 Laptop
)来违反了该原则。因此,高级模块 (ComputerShop
) 依赖于低级模块(Laptop
,desktop
),并且这里没有抽象。
现在,我添加一个新的类型 (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
) 以消除 ComputerShop
、Desktop
和 Laptop
类中的依赖。此外,现在高级和低级模块都依赖于抽象,而不是彼此依赖,并且抽象不依赖于细节,因此如果细节发生更改,它们不应影响抽象(满足 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。