Click here to Skip to main content
15,891,529 members
Please Sign up or sign in to vote.
2.00/5 (1 vote)
See more:
I have a class which use dependency injection.
C#
public class BoerpiDebitAccountBalanceRetriever : IDebitAccountBalanceRetriever
    {
        private readonly IAccountInfo _MyDebitAccountInfo;

        public Exception ServiceException { get; set; }

        public BoerpiDebitAccountBalanceRetriever(IAccountInfo MyDebitAccountInfo)
        {
            _MyDebitAccountInfo = MyDebitAccountInfo;
        }

        public virtual DebitAccountBalanceResult GetDebitAccountBalance()
        {
            var client = GetBoerpiClient();
            var request = GetCustomerBalanceRequest();
            DebitAccountBalanceResult debitAccountBalanceResult = new DebitAccountBalanceResult();
            var response = GetCustomerBalanceResponse(client, request);
            debitAccountBalanceResult.DebitBalance = (decimal)response.AvailableFunds;
            debitAccountBalanceResult.MethodSuccess = response.MethodSuccess;
            return debitAccountBalanceResult;
        }

        public virtual GetCustomerBalanceResponse GetCustomerBalanceResponse(iBOERPIClient client,
            GetCustomerBalanceRequest request)
        {
            var response = client.GetDebitCustomerBalance(request);
            return response;
        }

        public virtual iBOERPIClient GetBoerpiClient()
        {
            var client = new iBOERPIClient();
            return client;
        }

        public virtual GetCustomerBalanceRequest GetCustomerBalanceRequest()
        {
            var request = new GetCustomerBalanceRequest();
            request.FacilityID = Int32.Parse(_MyDebitAccountInfo.FacilityId);
            request.InmateID = _MyDebitAccountInfo.InmateId;
            request.Token = _MyDebitAccountInfo.Token;
            return request;
        }
    }


And in another class
C#
public class TestCallFlowApplication : ICallFlowApplication
   {
       public IDebitAccountBalanceRetriever DebitAccountBalanceRetriever;
       public IAccountInfo MyDebitAccountInfo;
       public IPromptPlayer PromptPlayer;
       public ILine LineApi { get; set; }
       public ICallInfo CallInfo { get; set; }

       public TestCallFlowApplication(IDebitAccountBalanceRetriever debitAccountBalanceRetriever,
           IAccountInfo MyDebitAccountInfo)
       {
           MyDebitAccountInfo = MyDebitAccountInfo;
           DebitAccountBalanceRetriever = debitAccountBalanceRetriever;
       }

       public virtual void InstantiatePromptPlayer()
       {
           PromptPlayer = new PromptPlayer(LineApi, CallInfo);
       }

       public void GetMyDebitAccountInfo()
       {
           MyDebitAccountInfo.InmateId = PromptPlayer.InmateId;
           MyDebitAccountInfo.FacilityId = PromptPlayer.FacilityId;
           MyDebitAccountInfo.Token = Token;
       }


So you see in the second class's constructor, we inject two dependency.
IDebitAccountBalanceRetriever and IAccountInfo

However in the first class, it seems BoerpiDebitAccountBalanceRetriever is injected IAccountInfo.
So in the second class, do the two dependency couple tightly? What should I do?

What I have tried:

I remove the second dependency from the constructor and just use new up instance? But not sure it is correct?
Posted
Updated 4-Mar-16 13:19pm
Comments
Sergey Alexandrovich Kryukov 4-Mar-16 19:37pm    
If you remove the second dependency, you just lost that dependency. If you don't need this dependency, there is not a problem, but if you really need it, how can you possibly remove it?
—SA

1 solution

First of all, you have not two injecting dependencies, but three. The answer is: not only two dependencies are not tightly coupled, but there is no coupling issue at all. You probably think that two instances are coupled via common IAccountInfo, but… there is nothing like that. You have, generally, too different instances of this interface, and these two instances could be even of different types. Let's see.

Your problem is just not seeing what you are doing. Perhaps this is the problem of not seeing amazingly simple thing behind a lot of unrelated code. Perhaps all you need is to shorten up the code to see at the root of the problem. Scratch all unrelated code, and you will see:
C#
interface IA { }
interface IB { }

class AGood : IA { }
class ABetter : IA { }

class B : IB {
    public B(IA a) { this.a = a; }
    IA a;
}

class C {
    public C(IB b, IA a) { this.b = b;  this.a = a; }
    IA a;
    IB b;
}

Note that the fact that your top level injection container (client) TestCallFlowApplication implement some application, it totally irrelevant to the problem. In my sample, this is C, the interface is scratched out. I intentionally provided two different implementations of IA (analog of IAccountInfo of your sample), just to justify my point. Here how you can use all those implementations:
C#
IA a1 = new AGood();
IA a2 = new ABetter();
IB b = new B(a1);
C c = new C(b, a2); // a1 is injected through b, a2 as a separate parameter

Note that you have two injected IA instances. Not only they are two independent objects, but they also could be of two different and even unrelated (not bound by inheritance relationship except to the one with this interface) types. Where do you see tightness? :-)

My second point… is harder to explain. You have to see the application behind the abstract design. Often, it requires more abstract thinking than just looking at the code construct structurally. If you think of a single interface, understanding of its purpose and qualities requires you to imagine simultaneously all possible implementations of it, from this standpoint a theoretically infinite number of them. But, to many, it would be easier to imagine some implementations related to a particular set of application goal. Seemingly, you behave like you feel your responsibility for "implementing the design pattern right". But this is not your real responsibility. It's the author of design pattern is responsible for proposing something potentially useful for some application. It's not your goal to "please" the author of some pattern or a principle. If you go from the application goals, it may help you to gain clear vision. On this topic, for some food for though, please see my past answer: Please suggest me some basic C++ project with design patters.

As to your "What I have tried" section, please see my comment to the question. It's a good idea to explain what you really tried; in this case, it would be some modified variant of your code.

—SA
 
Share this answer
 
v7
Comments
[no name] 4-Mar-16 20:24pm    
So, do you mean that my code is okay? Because they are actually unrelated? It is case C? I need the conclusion.
Sergey Alexandrovich Kryukov 4-Mar-16 21:39pm    
Didn't I answer already? They are generally unrelated. Isn't it obvious? There is no a coupling tightness issues here, that is the conclusion. Are you getting it?

In other words (this is what "generally" means), the relationships are related if, in actual construction of C, you supply related instances, and unrelated if you supply unrelated; that is, you achieve perfectly loose coupling at this point.

This conclusion does not mean that your whole code is okay or not; it depends on many factors and cannot be answered without having the rest of the code, requirements, etc. This conclusion is only about your issue: it is not an issue, that's it.

All right, are you going to accept the answer formally?

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900