TaherHassan
TaherHassan

Reputation: 91

SOLID Design Principles : Liskov Substitution Principle and Dependency Inversion Principle

Just a thought and a question to the Stack Overflow and Microsoft Development Community about the OO software design principles called SOLID. What is the difference between the Liskov Substitution Principle and the Dependency Inversion Principle please ? I have thought about this for a while and I'm not sure of the difference. Please could you let me know ? Any thoughts / feedback very welcome.

Upvotes: 7

Views: 5649

Answers (3)

christophperrins
christophperrins

Reputation: 153

Liskov's substitution Principle states the following:

A class should be directly substitutable with its base-class

What this means is that if a child class extends a parent class, it should be directly substitutable. Image viewable here

If you take Bird for example. Not all birds fly - but some do.

Lets look at a java example:

Bird  ostrich = new Ostrich();

If I am going to treat my ostrich as a Bird (is base/parent class), and we have functionality in Bird for that ostrich to fly, even though they shouldn't!

So we can separate out the structure: Refactored hierarchy for Liskov's

Dependency Inversion is easier when thought of as a separate principle.

If we have a class call a class. It makes it very hard to change it later and it is going to need us to change source code. Again lets look at a code example.

public class App {
    public static void main(String[] args) {
        Greeting greeting = new Greeting();
        greeting.sayHello(new Friend()); 
        greeting.sayHello(new Enemy());
    }
}

public class Greeting {
    public void sayHello(Person person) {
         person.greet();
    }
}

public interface Person {
    public void greet();
}

public class Friend implements Person {
    public void greet() {
        System.out.println("Hello my friend");
    }
}

public class Enemy implements Person {
    public void greet() {
        System.out.println("Go away");
    }
}

Here we pass a parent object (Person) of both of items (Friend and Enemy). If we passed through a Friend object, we would need a separate identical method for the Enemy method. We can use the Open/Closed principle to have a single method which can call either Friend or Enemy or anything in the future which might extend Person. Dependency inversion is that rather than the sayHello() method creating a class, the Parent object is passed through. This means that which Parent object we call is dependent on App, rather than sayHello() determining which object to call.

It is better practice to use dependency inversion. The class greet() calls is not set in stone, as long as the class being passed is that which implements Person.

What this means is that instead of App being dependent on Friend. Whether Friend or Enemy gets called is dependent on App.

Passing responsibility up like this means that our code can be easily maintained and changed. Using Context and Dependency Injection, it is possible for configuration files to determine which type of object we want to use when a specified interface is referenced.

Upvotes: 11

jurez
jurez

Reputation: 4667

Substitution principle means that you use abstractions. Abstractions are good because they make your code more universal, reusable and valuable. For example, if your code works with an abstract Vehicle instead of a more concrete Car, then you can also use the same code without any changes also with other vehicles such as Bicycle, Truck or even Ship and it will continue to work without problems. Of course, to make this "substitution" work, you must ensure that all Vehicles follow the same contract, which usually means that they implement a common interface or extend a common superclass.

Dependency injection makes your code better because it cuts the unneccessary ties between classes. This, again, makes those classes reusable in different scenarios. For example, if your class is getting data from a file, then you will run into problems the next time your data will be in a database. Your class will suddenly become a swamp of if-then-else cases that try to deal with different things, and it will be a nightmare to maintain. Dependency injection frees your class from this responsibility - i.e. your class just "needs data" and it is the responsibility of the caller to make sure that the data is connected (aka "injected") into it. Technically, dependency injection is simply just setting a variable, such as myObject.dataSource = databaseDataSource, or myObject.dataSource = fileDataSource.

Upvotes: 1

jaco0646
jaco0646

Reputation: 17104

In one sense, the LSP and the DIP are opposites.

  • The LSP governs the relationship between classes in an inheritance hierarchy
    (i.e. classes that are parent and child).
  • The DIP governs relationships among classes outside an inheritance hierarchy
    (i.e. classes that are not parent and child).

For a visual, consider six potential relationships among two parent and two child classes.

  • LSP is concerned with relationships 1 and 2.
    • 1 and 2 are OK only if Child1 and Child2 are subtypes and not just subclasses.
  • DIP is concerned with relationships 3, 4, 5, and 6.
    • 3 is OK.
    • 6 is prohibited.
    • 4 and 5 can point upwards but not down.

object relationships

Upvotes: 4

Related Questions