0

If a School class relies on an EmailSender class you might have to inject this EmailSender through it's constructor with a generic interface like IMessagable or IMessageSender or even IEmailSender so that it can be swapped out for something else in the future.

In order to do this you would create a read-only private field in the School class.

But then you're saying that the School HAS-A MessageSender but surely it just USES it in a few of it's methods??

  • 1
    and what is the question? – MakePeaceGreatAgain Dec 13 '20 at 15:26
  • how do you define a dependency. Is it something the class has or uses? Or both, and therefore, how do you distinguish between what a class owns and what it uses? – BeingCraigSchwartz Dec 13 '20 at 15:28
  • 1
    from a class-view there´s no difference between a *has-a*-relation and a *uses*-relation. In fact you can surely *use* what you *have*, can´t you? So it´s pure fine to use the dependencies provided by a field. – MakePeaceGreatAgain Dec 13 '20 at 15:31
  • it's not the same as a School having a dependency on IStudentCollection though is it? In this relationship there's a clearer relationship. Surely the EmailSender should only be passed into the methods that it's used in and not be an attribute of the class? I hope you can clear my confusion up. Thank you! – BeingCraigSchwartz Dec 13 '20 at 15:33
  • 2
    A class must _have_ something to _use_ it. Even where that thing is an interface, it still boils down to needing a concrete type that fulfils the contract defined by `IStudentCollection`. – ProgrammingLlama Dec 13 '20 at 15:35
  • a 'School' has 'students: IStudentCollection', but a school doesn't have an 'emailSender: EmailSender'. It makes more sense for it to only be passed into the methods it's used in; this is why dependency injection baffles me. – BeingCraigSchwartz Dec 13 '20 at 15:38
  • 2
    A school doesn't, but then a school sounds like a _model_ and not a _service_. A `SchoolControllerService` would have and use an `emailSender` based on data in a `SchoolModel`. – ProgrammingLlama Dec 13 '20 at 15:38
  • 3
    This sounds to me like a modeling problem more than a DI problem. Ignoring any/all DI concepts, do you think the `School` is responsible for sending emails? It seems you agree that the answer is no. There's likely some other abstraction to be introduced that would be more responsible for sending emails/notifications in those cases (e.g. enrollment department). With the proper abstractions, the dependencies should be clear. – devNull Dec 13 '20 at 15:54
  • why would you have a **has-a**-relation if you won´t be able to use it in any way? The entire point of a dependency is to do something with it - this is to **use** it. If you don´t use it, there´no reason to have it in the first place. – MakePeaceGreatAgain Dec 13 '20 at 17:22
  • A `Shool` *has* a `Sender` in order to *use* it, doesn´t it? – MakePeaceGreatAgain Dec 13 '20 at 17:25
  • but the sender does not belong to the school does it? – BeingCraigSchwartz Dec 13 '20 at 17:28
  • well, the person probably works in the shool, so in a sense the shool *has* it, if you want so. – MakePeaceGreatAgain Dec 13 '20 at 17:36
  • but we're talking about an email sender. It could be a logger that does some logging. It could be anything that the School or SchoolService uses but doesn't own. – BeingCraigSchwartz Dec 13 '20 at 17:40

2 Answers2

3

Any property/member a class declares, is something a class HAS.

The Has-A is here to differentiate from the Is-A of inheritance.

The uses-a property, is more related to class cohesion rather than composition. If the class has-A property but it does not use it, or uses it in a small percentage of functions, it has low cohesion.

Both HAS-A and IS-A are dependencies of the class. That's why we strive to have them both as abstractions, to loosely couple the two.

Any class/interface definition without which your class won't compile, is a dependency. Even if it doesn't have a HAS-A relationship and it's just passed as a function parameter.

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
2

Even if a class only uses one of many methods in a passed-in object, the entire object is still considered a dependency of the class.

This becomes evident when you change the API (the method signatures) of an object. By handing that object to a class, you essentially guarantee that object's "contract." If you change that object's API, you risk breaking classes that depend on it.

That's why we often use Interfaces to pass dependencies to classes. The interface enforces the contract between the class and its dependency, and encourages decoupling because the passed in object has to conform only to the interface's methods.

The nomenclature IS-A and HAS-A is used primarily to distinguish inheritance from composition.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501