Dependency Inversion Principle
Topic | Source |
---|---|
๐งน Clean Code | Clean Code - Udemy |
You should depend upon abstractions, not concretions.
Avoid having code, that needs to check which type of implementation you are concretely using.
The consuming class should not have to check if the dependencies are met.
Instead, you should make sure on the outside, that the dependencies are met, therefore inverting them.
interface Database {
storeData(data: any);
}
interface RemoteDatabase {
connect(uri: string);
}
class SQLDatabase implements Database, RemoteDatabase {
connect(uri: string) {
console.log('Connecting to SQL database!');
}
storeData(data: any) {
console.log('Storing data...');
}
}
class InMemoryDatabase implements Database {
storeData(data: any) {
console.log('Storing data...');
}
}
// this implementation hurts the Dependency Inversion Principle
class App {
private database: SQLDatabase | InMemoryDatabase;
constructor(database: SQLDatabase | InMemoryDataba) {
// the implementation needs to take care if the dependencies are met
if(database instanceof SQLDatabase) {
database.connect('my-url');
}
this.database = database;
}
saveSettings() {
this.database.storeData('Some data');
}
}
// instead, create a contract, that you handle connection outside and the concrete implementation does not care about that
class App {
private database: Database;
constructor(database: Database) {
this.database = database;
}
saveSettings() {
this.database.storeData('Some data');
}
}
const sqlDatabase = new SQLDatabase();
sqlDatabase.connect('my-url');
const app = new App(sqlDatabase);