A class should have only one responsibility.
class ViewController: UIViewController {
func fetchDataFromServer() { //Perform network request code... }
func insertDataIntoDatabase() { //Perform database insertion code... }
}
ViewController should only take care of UI works.
class Database {
//Code related to DB...
}
class Webservice {
//Code related to network request...
}
Adding new functionality to a class/method without changing the existing code. Use polymorphism to avoid if else condition.
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.
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."
}
}
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.
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.
class ScrollView {
func scrollTo(position: Double) { }
}
class HorizontalScrollView {
func scrollTo(position: Double) { }
}
class VerticalScrollView {
func scrollTo(position: Double) { }
}
A class should not implement interface which has methods the class doesn't use.
protocol OrderService {
func orderPizza()
func orderNoodle()
}
class PizzaOrder: OrderService {
func orderPizza() { }
func orderNoodle() {
print("Sorry, we serve only Pizza!")
}
}
Pizza doesn't serve noodle.
protocol PizzaOrderService {
func orderPizza()
}
protocol NoodleOrderService {
func orderNoodle()
}
class PizzaOrder: PizzaOrderService {
func orderPizza() { }
}
class NoodleOrder: NoodleOrderService {
func orderNoodle() { }
}
Depend on abstraction rather than concretion.
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.
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() { }
}