-1

I was reading an article recently about the SOLID principles and I can't seem to understand the example about the Dependency inversion principle (DIP). The article gave the following example. First the incorrect way, then the correct way.

INCORRECT WAY

class Login { 
  login(googleLogin: any) { 
    // some code which will be used for google login.
  }
}

Makes sense, the article explains that if the client wanted to add a Facebook login tomorrow, you would have to modify the Login class, which should not be necessary with DIP. Dependent on abstractions and not concretions. Understood.

CORRECT WAY

interface ISocialLogin {
  login(options: any);
}

class GoogleLogin implements ISocialLogin { 
  login(googleLogin: any) { 
    // some code which will be used for google login.
  }
}

class FBLogin implements ISocialLogin { 
  login(fbLogin: any) { 
    // some code which will be used for fb login.
  }
}

class Login {
  constructor(private login: ISocialLogin) {}

  onLogin() {
    this.login();
  }
}

Now, in this example.. how do we know which class the Login class is going to use? I could see if in the constructor you specified GoogleLogin vs FBLogin, but just implementing the interface is confusing to me. Can somebody please explain? Thanks in advance.

Editing for additional question...

I'm still missing something basic I think. In this example (Angular specific), say I have the following UX. Inside of a LoginComponent, I have a GoogleLoginComponent and a FacebookLoginComponent. In both of those child component examples, I would use the GoogleLogin and FBLogin classes, correct?

enter image description here

Nick
  • 592
  • 6
  • 12
  • 21
  • 1
    "how do we know which class the Login class is going to use?" --- that's the idea: you should not care. As soon as it can authenticate - you're good. – zerkms Feb 14 '18 at 22:57
  • 1
    Note that `googleLogin` and `fbLogin` are just names; they don't carry any meaning. They could just as easily be named `options`. – Heretic Monkey Feb 14 '18 at 23:15
  • see question addition please. – Nick Feb 14 '18 at 23:59
  • 1
    @Nick the visual design you provided shares nothing in common with the rest of the question. They implement 3 types of authentication, it has nothing to do with the DI. – zerkms Feb 15 '18 at 00:52
  • @zerkms Well maybe that's my problem then. I'm trying to apply the principle to a real world example and can't connect the dots. Thanks for trying. – Nick Feb 15 '18 at 02:01
  • 1
    @Nick you're trying to apply application design (the structure) approaches to the visual design domain. – zerkms Feb 15 '18 at 02:09

1 Answers1

3

TL;DR: zerkms gave you the right answer in the comments.

Long answer: The point of the Dependency Inversion Principle for this problem is that you'll have your Login implementation independent of the actual implementation of ISocialLogin. You are bound to using only the attributes and methods provided by ISocialLogin, but as long as the class received as the argument for your Login constructor implements them all, your component will be independent of the underlying login implementation.

The trick here is that now Login isn't required to select the instance to use for the login implementation, as it's provided from outside. This will let you use your Login+ISocialLogin component everywhere. For instance one new application may provide a different social login implementation, and you'd be able to reuse that component. In the former (i.e., the incorrect way), the constructor, and any other method in Login using it, would need to be redone as it'd depend on the GoogleLogin implementation.

To sum up, you've gone from this dependency (separate components delimited by parenthesis; arrow direction means "depends on"):

(Login) -> (GoogleLogin)

to:

(Login -> ISocialPlugin) <- (GoogleLogin)