Skip to content

Instantly share code, notes, and snippets.

@koingdev
Last active June 20, 2022 09:57
Show Gist options
  • Save koingdev/0e48183e7eed388cecabe0804d4c0400 to your computer and use it in GitHub Desktop.
Save koingdev/0e48183e7eed388cecabe0804d4c0400 to your computer and use it in GitHub Desktop.
S.O.L.I.D Design Principe Explanation with Example by me

Single-responsibility Principle

A class should have only one responsibility.

Bad

class ViewController: UIViewController {
	func fetchDataFromServer() { //Perform network request code... }
	func insertDataIntoDatabase() { //Perform database insertion code... }
}

ViewController should only take care of UI works.

Good

class Database {
	//Code related to DB...
}
class Webservice {
	//Code related to network request...
}

Open-closed Principle

Adding new functionality to a class/method without changing the existing code. Use polymorphism to avoid if else condition.

Bad

enum Exam {
	case computerScience
	case accounting
}
func takeExam(subject: Exam) {
	switch (subject) {
    	case .computerScience:
        	print("This is computer science exam.")
        case .accounting:
        	print("This is accounting exam.")
    }
}

If we want to add new english subject, we have to modify takeExam function by adding new case.

Good

protocol Exam {
    var description: String { get set }
}
class ComputerScienceExam: Exam {
    var description: String {
        return "This is computer science exam."
    }
}
class AccountingExam: Exam {
    var description: String {
        return "This is accounting exam."
    }
}
func takeExam(subject: Exam) {
	print(subject.description)
}
// Want to add new feature without breaking takeExam() ?
class EnglishExam: Exam {
    var description: String {
        return "This is english exam."
    }
}

Liskov substitution principle

A child class should be able to be used in the same manner as the parent class.

A child should be substitutable for its parent.

Bad

class ScrollView {
    func scrollTo(position: Double) { }
}
class UIView: ScrollView {
    func scrollTo(position: Double) {
        print("Sorry, cannot scroll!")
    }
    func animate() { }
}

UIView is now no longer substitute for the parent.

Good

class ScrollView {
    func scrollTo(position: Double) { }
}
class HorizontalScrollView {
    func scrollTo(position: Double) { }
}
class VerticalScrollView {
    func scrollTo(position: Double) { }
}

Interface segregation principle

A class should not implement interface which has methods the class doesn't use.

Bad

protocol OrderService {
    func orderPizza()
    func orderNoodle()
}
class PizzaOrder: OrderService {
    func orderPizza() { }
    func orderNoodle() {
        print("Sorry, we serve only Pizza!")
    }
}

Pizza doesn't serve noodle.

Good

protocol PizzaOrderService {
    func orderPizza()
}
protocol NoodleOrderService {
    func orderNoodle()
}
class PizzaOrder: PizzaOrderService {
    func orderPizza() { }
}
class NoodleOrder: NoodleOrderService {
    func orderNoodle() { }
}

Dependency inversion principle

Depend on abstraction rather than concretion.

Bad

class ViewModel {
    private let databaseProvider: SQLite
    init(databaseProvider: SQLite) {
        this.databaseProvider = databaseProvider
    }
}

In the future, if we want to change the provider to Realm, we will have to change ViewModel code to support new provider.

Good

protocol DatabaseProvider {
    func create()
    func delete()
}
class SQLite: DatabaseProvider {
    func create() { }
    func delete() { }
}
class ViewModel {
    private let databaseProvider: DatabaseProvider
    init(databaseProvider: DatabaseProvider) {
        this.databaseProvider = databaseProvider
    }
}
// Want to change database provider without breaking ViewModel ?
class Realm: DatabaseProvider {
    func create() { }
    func delete() { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment