我正在阅读关于SOLID原则的内容,我在此处停止了“依赖性倒置原则”,这意味着对象应该已经通过实例化到另一个对象,这意味着组合不能应用依赖性倒置原则对吗?或者有什么我想念的? 更新************************************************* * 假设你有一个类,这个类有一个引用anther对象的属性,我们有2个解决方案(对我来说):
答案 0 :(得分:7)
你的困惑来自于你对构图的理解。另一个拥有的对象取决于拥有对象的生命周期。这并不意味着你必须在拥有类中创建拥有的对象。
如果在类中创建对象,则此类与创建的类紧密耦合。你不能在不改变创造另一个的类的情况下交换实现。
在上图中,您有类Client,它使用类Server。假设这是一个组合,客户端具有Server类型的属性。
如果在客户端类中创建类服务器的实例,它可能如下所示:
public class Client {
private Server server;
public Client(){
this.server = new Server();
}
}
现在假设你要交换服务器的实现。您需要更改Client类的实现,因为交换它的唯一方法是创建另一个类的实例(可能称为AnotherServer)。
public class Client {
private AnotherServer anotherServer;
public Client(){
this.anotherServer = new AnotherServer();
}
}
这表明,Client类高度依赖于类Server。
为了轻松更改服务器的已使用实现并因此修改客户端的行为,最好从抽象(抽象类或接口)中组合客户端。这样做意味着您无法在拥有类中创建所需的对象,因为您只能创建具体的类。创建类意味着调用构造函数并依赖于创建的类。
实现组合的更好方法( - 客户端由服务器组成 - )是通过setter方法或构造函数注入它。像这样你可以隐藏接口背后的实现类。
在第二张图片中,我们保护客户免受有关服务器具体实现的了解。它只取决于服务器接口。这种依赖性并不那么引人注目,因为客户端定义了接口。他决定了Server接口所需的功能。为了表明服务器的接口属于客户端,它被称为" ClientServer"。
要编写客户端,您必须为类外部的ClientServer接口创建具体类,并通过构造函数或setter方法注入它。
...
FirstServer first = new FirstServer();
Client client = new Client(first);
client.setServer(new SecondServer());
...
像这样,即使在运行时,您也可以轻松地在客户端中交换使用过的Server实现。
这种机制称为依赖性倒置原则(DIP)。但为什么? Client类仍然依赖于服务器接口。如果界面发生变化,客户也必须更改。是的,这是正确的。但客户决定在该界面中需要哪些功能。因此,当客户端说需要更改时,通常会更改界面。由于客户端更改,接口会更改。
因为具体服务器" FirstServer"和#34; SecondServer"实现它们依赖于该接口的ClientServer接口。而且因为继承是一种比组合更强的依赖,所以具体的服务器类比Client类更依赖于接口。
这就是为什么依赖性被颠倒了。具体的服务器类现在依赖于" Client-ClientServer" -conglomerate。
因此,您的问题的答案是:当您在另一个班级中创建班级时,您无法达到DIP。但是你可以通过定义一个注入继承这个接口的具体类的接口来达到DIP的组合。
答案 1 :(得分:3)
一个。高级模块不应该依赖于低级模块。两者都应该取决于抽象。
B中。抽象不应该依赖于细节。细节应该取决于抽象。
你说:
表示对象应该已经实例化到另一个对象
依赖性反转原则与类构造函数之类的编程实现细节没有任何关系,它们用于初始化正在构造的对象。
除非您将构造函数参数定义为实现而不是抽象,并且/或者注入的依赖项具有比目标依赖项更高的层,否则您不会违反整个原则。