Friday, January 22, 2016

Refactoring in Swift - Extract class

According to the Single Responsibility Principle, one class should do one thing. Also it needs to know the least amount of information to do its job.

In time though, all the classes evolve by accumulating more and more properties and functions. That is why refactoring is needed to simplify them and restrict their area of action.

One of the methods is extract class method. When a class becomes too big, extract part of it as another class.

Consider the following User class:


class User {
    var firstName, lastName: String?
    var streetName, streetNumber, city, postalCode, country: String?
   
    func formatAddress() -> String {
        var formattedAddress = ""
        //create a nice formatted address, taking into consideration
        //that each of the variables can be nil
        return formattedAddress
    }
}

As it is a simple class, it is fine as it is.

A new request comes to have the work address added, so the first version would be:

class User {
    var firstName, lastName: String?
    var homeStreetName, homeStreetNumber, homeCity, homePostalCode, homeCountry: String?
    var workStreetName, workStreetNumber, workCity, workPostalCode, workCountry: String?
 
    func homeFormatAddress() -> String {
        var formattedAddress = ""
        //create a nicely formatted address
        return formattedAddress
    }
    func workFormatAddress() -> String {
        var formattedAddress = ""
        //create a nicely formatted address
        return formattedAddress
    }
}

As this might be still fine, what if the user has two work addresses? Also what if we need more functionality for the address: check if it is valid, display it on the map, find the distance, etc.

It is clear that the User class does not need to know all details about it.

A good solution would be to extract a new class called Address:

class User {
    var firstName, lastName: String?
    var homeAddress = Address()
    var workAddress = Address()
 
    func homeFormatAddress() -> String {
        return homeAddress.formatAddress()
    }
    func workFormatAddress() -> String {
        return workAddress.formatAddress()
    }
}

class Address {
    var streetName, streetNumber, city, postalCode, country: String?

    func formatAddress() -> String {
        var formattedAddress = ""
        //create a nicely formatted address
        return formattedAddress
    }
}

Assuming that we want to add more functionality for each address, we only need to change one class.

No comments:

Post a Comment