“理上网来·辉煌十九大”-热点专题-中工网
Current License: CC BY-SA 4.0
36 events
when toggle format | what | by | license | comment | |
---|---|---|---|---|---|
May 14, 2023 at 9:01 | comment | added | szx | To me, all the explanations I've read seem to bil down to the fact that we just add one more layer of abstration between the high and low level components, and that's it. I din't see any "inversion" here.... IMO this is the most vague and confusing principle of SOLID. And there is no clear difference between dependency INVERSION and INJECTION either... | |
Sep 2, 2022 at 15:15 | history | edited | Derek Greer | CC BY-SA 4.0 |
minor edits
|
Feb 11, 2022 at 17:29 | comment | added | Derek Greer | @AlanEvangelista Consider if you package MyService as a jar file or NuGet package and the logging implementation is log4j or Log4Net. If I use MyService, I'm taking a transitive dependency on log4j or Log4net. The higher level component (MyService) is depending on the lower level component (a logging library), requiring me to use your logging library choice. By expressing MyService's logging capabilities in terms of its own interface, I can provide whatever implementation adaptor I choose. | |
Nov 11, 2020 at 10:30 | comment | added | Alan Evangelista | 1) I have read that the brackets supposedly express that the classes between them are in the same (e.g. Java?) package, but I'm unable to see the difference in practice between MyService → [ILogger ? Logger] and [MyService → IMyServiceLogger] ? Logger. Assuming that ILogger and IMyServiceLogger are classes I created in my application to abstract the implementation details of the logging library I'm using, what's the difference of putting them in different packages? 2) Where is the dependency inversion if MyService depends on an interface and Logger implements that interface in both cases? | |
Jan 18, 2020 at 1:48 | history | edited | Mark Amery | CC BY-SA 4.0 |
edited body
|
Jun 25, 2019 at 15:29 | history | edited | Derek Greer | CC BY-SA 4.0 |
fixed grammar
|
Jun 19, 2019 at 15:21 | comment | added | Derek Greer | With the arrows, I was trying to approximate the UML class diagram functions of association and generalization with → and ? respectively. The brackets are indicative that the classes involved are in the same "package" (e.g. in the same assembly in .Net). Understanding the notion of package is a key distinguishing concept when talking about DIP. Otherwise you just end up with the general advice of "Program to an Interface not an Implementation". | |
Jun 10, 2019 at 10:36 | comment | added | Mark Amery |
What's the meaning of the syntax with arrows and square brackets (→ , ? , [ , ] ) that you use in this answer? They're left undefined here, but are alien to me.
|
|
May 31, 2019 at 15:17 | comment | added | Derek Greer | I updated the answer to include a link to another article I wrote in 2012 about how the principle applies in dynamically-typed languages like JavaScript. | |
May 31, 2019 at 15:16 | history | edited | Derek Greer | CC BY-SA 4.0 |
Added link to Javascript article
|
May 31, 2019 at 15:12 | comment | added | Derek Greer | That article could use a little touch-up. I wrote it about 10 years ago and I believe I'd probably do a better job writing it today. That aside, the take-away is that following the DIP shifts ownership of the interface from the concrete implementation to the consumer which naturally leads to differences in how the interface is expressed (i.e. the behavior the consumer needs vs. the behavior the concrete implementation generically offers). Each application tends to have its own Domain-Specific Language, so the interfaces defined will tend to reflect this. | |
May 31, 2019 at 0:04 | comment | added | Wael | @derekgreer The article is amazing, I love it. Thank you! But I have one question though. In the article you mentioned "Additionally, the association of the interface with the higher-level component(s) may in some cases impact the style and naming conventions used in the creation of the interface." What is this impact, and does it matter? | |
Feb 20, 2019 at 16:19 | history | edited | Derek Greer | CC BY-SA 4.0 |
Added further discussion of the second use case.
|
Feb 20, 2019 at 15:57 | history | edited | Derek Greer | CC BY-SA 4.0 |
formatting
|
Feb 16, 2019 at 0:08 | comment | added | Derek Greer | I updated the article to include discussion about goals of isolation verses merely library portability. | |
Feb 16, 2019 at 0:06 | history | edited | Derek Greer | CC BY-SA 4.0 |
Elaborated upon the concept of reuse
|
Feb 15, 2019 at 22:08 | comment | added | Derek Greer | @humbaba I had occasion to read back over this exchange and went back to the book "Agile Principles, ... in C#" wherein it states on pg. 154: "Moreover, it is high-level, policy-setting modules that we want to be able to reuse." So, Martin most definitely has reuse in mind when discussing the DIP. Understand too, reuse doesn't necessarily necessitate multiple uses. When an application's core exists alongside one set of implementation detail components, you can consider that to be one use. When you need to change the impl. details for the same application, that is essentially a second use. | |
Sep 7, 2018 at 12:22 | comment | added | Derek Greer | I’m curious what you believe the primary benefits to be if not reuse. I certainly don’t deny that Uncle Bob sees higher level components as those containing business logic, but pointing that out doesn’t say anything about why this would be a useful practice. | |
Sep 6, 2018 at 9:40 | comment | added | humbaba | If we define the high level components only in terms of reusability, then we cannot understand what DIP is or what its benefits are. High level components are the ones that include the business rules, it does not have much to do with reusability indeed. Everything else should depend on the business rules, not the other way around. You can see that Uncle Bob defines high level components like this while explaining DIP in his Clean Architecture book. | |
Mar 22, 2017 at 8:28 | comment | added | Birb | @DerekGreer: Your example with John and Sam should be in your original reply. Great one! | |
Mar 10, 2017 at 14:26 | comment | added | FaceBro | Inherit to be used instead of using base class, the essence can be summarized as so | |
Nov 25, 2016 at 17:47 | comment | added | Derek Greer | @VF1 That's correct. Components can be either physically coupled (makes a reference to a specific library/assembly), or they can be semantically coupled (nominal interface over a specific implementation). The DIP already presumes the implementation is going to be defined in terms of the interface rather than an interface being defined in terms of the implementation. | |
Nov 23, 2016 at 18:07 | comment | added | VF1 |
@DerekGreer I think I understand. Sam's adapter could still be written for an ILogger , but I think the point to drive home is that the easiest interface (in the sense that it's the most minimal) such that it satisfies the requirements necessary to make MyService operate.
|
|
Nov 23, 2016 at 17:49 | comment | added | Derek Greer | @VF1 Regarding your scenario of needing to change your logging implementation, if your logging requirements necessitates you making changes throughout your system then you haven't defined your abstraction correctly whether you're following the DIP or not. A logging interface that needs to be changed if you decide not to log to the file system is an interface that is semantically coupled to the implementation details. | |
Nov 23, 2016 at 17:39 | comment | added | Derek Greer | @VF1 As stated in the summary paragraph, the importance of the Dependency Inversion Principle is primarily with reuse. If John releases a library that has an external dependency on a logging library and Sam wishes to use John's library, Sam takes on the transient logging dependency. Sam will never be able to deploy his application without the logging library John selected. If John follows the DIP, however, Sam is free to provide an adapter and use whatever logging library he chooses. The DIP isn't about convenience, but coupling. | |
Jul 21, 2016 at 16:01 | comment | added | VF1 |
And in cases where the new Logger impl can conform to the old interface, how does this save us anything over the old approach?
|
|
Jul 21, 2016 at 16:00 | comment | added | VF1 |
This is probably the clearest explanation of DIP I've seen. That said, why is it so glorified? As I see it, what we're trying to do is minimize work re-done by changes by making the coupling occur "in the most convenient place possible." If I need to make big changes to Logger (say I'm no longer allowed to use a local file system), I still won't be able to adhere to IMyServiceLogger . It seems like we'd have to make the same amount of changes, everywhere, whether the architecture is MyService → [ILogger ? Logger] or [MyService → IMyServiceLogger] ? Logger .
|
|
Apr 2, 2013 at 15:59 | comment | added | TSmith | @ Casper Leon Nielsen - D.I.P. has nothing to do with D.I. They are not synonyms nor equivalent concepts. | |
Jan 8, 2013 at 17:58 | comment | added | Casper Leon Nielsen | How I wished people would stop using loggers as the canonical usecase for dependency injection. Especially in connection with log4net where its almost an anti pattern. That aside, kickass explanation! | |
Jan 8, 2013 at 17:29 | history | edited | Derek Greer | CC BY-SA 3.0 |
Added blurb about the DIP's importance
|
Dec 13, 2012 at 13:37 | comment | added | ejaenv | In the same line its very well explained here: lostechies.com/derickbailey/2011/09/22/… | |
Aug 15, 2012 at 13:26 | history | suggested | asbachb | CC BY-SA 3.0 |
updated url in answer
|
Aug 15, 2012 at 13:24 | review | Suggested edits | |||
Aug 15, 2012 at 13:26 | |||||
Aug 31, 2009 at 13:45 | comment | added | Patrick McElhaney | Thanks. I see now how my answer misses the point. The difference between MyService → [ILogger ? Logger] and [MyService → IMyServiceLogger] ? Logger is subtle but important. | |
Jul 11, 2009 at 18:05 | history | edited | Derek Greer | CC BY-SA 2.5 |
fixed bolded text
|
Jul 11, 2009 at 15:20 | history | answered | Derek Greer | CC BY-SA 2.5 |