Encapsulation

The concept of encapsulation in OOP allows us to define all of the necessary members for an object to function while hiding the internal implementation details from the application using the object. This is a very powerful concept for us to use because it allows us to change the internal workings of a class without breaking any of its dependent objects. This could come in the form of either private members or private method implementations. The contract that has been established remains the same and the functionality that it provides is consistent, however, improvements are able to be made. In the following code segment, you can see how hiding certain members from the calling application will be beneficial:

interface IActivator {
    activateLicense(): boolean;
}
class LocalActivator implements IActivator {
    private _remainingLicenses: number = 5;
    constructor() {
    }
    public activateLicense(): boolean {
        this._remainingLicenses--;
        if (this._remainingLicenses > 0)
            return true;
        throw "Out of Licenses";
    }
}

In this example, we have an interface that defines a type that will manage the activation of licenses for a product. This is followed by a concrete implementation of the interface that locally keeps track of the remaining licenses and returns a true value if there are remaining licenses, otherwise an exception is thrown to stop program execution. The number of licenses is kept in a private variable so that the calling application can't give itself more licenses to work with. In real-world scenarios, however, the actual implementation details would likely make a call to a server that determines whether the product has licenses remaining. Thanks to encapsulation, we could change the implementation details of this class too without the client ever knowing the difference, other than the delay in making a server request. In the following code segment, you can see how we are able to swap the LocalActivator object with a ServerActivator object and program execution continues to function as expected:

class ServerActivator implements IActivator {
    constructor() {
    }
    public activateLicense(): boolean {
        var request = new XMLHttpRequest();
        var requestResponse: boolean = false;
        request.open('GET', '/license/activate', false);

        request.onload = () => {
            if (request.status == 200) {
                requestResponse = true;
            } else {
                throw "An error occured during activation!";
            }
        };

        request.onerror = () => {
            throw "An error occured during activation!";
        }
        request.send(null);
        return requestResponse;
    }
}
//var activator: IActivator = new LocalActivator();
var activator: IActivator = new ServerActivator();
var isActive = activator.activateLicense();
if (isActive) {
    //Program logic
}

The ServerActivator class implements the same interface as LocalActivator we declared earlier, but it makes a synchronous request back to the server for data rather than doing it on the client. Normally, this type of request should be made asynchronously, however, we would need to change the IActivator interface to support promises or use callbacks.

Note

Promises will be natively supported in ECMAScript 6, however several libraries have implemented their own implementation. More information on ECMAScript 6 promises can be found here at: http://www.html5rocks.com/en/tutorials/es6/promises/.

The implementation details between the two objects is vastly different but the end result is the same. The two can be used interchangeably and the application requires no further changes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset