Deep understanding of the JavaScript series (6): single responsibility SRP, s. o. l. I. dsrp

Source: Internet
Author: User

Deep understanding of the JavaScript series (6): single responsibility SRP, s. o. l. I. dsrp
Preface

Uncle Bob proposed and carried forward the Five Principles S.O.L. I. D to better implement object-oriented programming. The five principles are:

  1. The Single Responsibility Principle (Single Responsibility SRP)
  2. The Open/Closed Principle (Open and Closed Principle OCP)
  3. The Liskov Substitution Principle (LSP)
  4. The Interface Segregation Principle (Interface separation Principle ISP)
  5. The Dependency Inversion Principle (Dependency Inversion Principle DIP)

I believe that the five principles have been discussed in the blog Park, especially the implementation of C #, but there are still a few dynamic types of languages like JavaScript Based on prototype, this series will be divided into five articles to demonstrate the application of the five principles based on the JavaScript programming language. Okay. Let's start with our first article: single responsibility.

Http://freshbrewedcode.com/derekgreer/2011/12/08/solid-javascript-single-responsibility-principle/.

Single responsibility

A single responsibility is described as follows:

A class shoshould have only one reason to change class should have only one reason

What does a class (JavaScript should be an object) mean by a group of closely related behaviors? The benefit of following a single role is that we can easily maintain this object. When an object encapsulates many responsibilities, once a role needs to be modified, it will inevitably affect other responsibility codes of this object. Through decoupling, each employee can change more elastically.

However, how do we know whether multiple actions of an object construct multiple responsibilities or a single responsibility? We can determine the Role by referring to the Role Stereotypes concept proposed in Object Design: Roles, Responsibilies, and Collaborations. This book proposes the following Role Stereotypes to differentiate responsibilities:

  1. Information holder-this object is designed to store objects and provides object Information to other objects.
  2. Structurer-this object is designed to maintain the relationship between objects and information.
  3. Service provider-this object is designed to process tasks and provide services to other objects.
  4. Controller-this object is designed to control decisions and handle a series of tasks
  5. Coordinator-this object does not make any decision processing work, but delegate only works on other objects.
  6. Interfacer-this object is designed to convert information (or requests) in each part of the system)

Once you understand these concepts, it is easy to know whether your code is multi-responsibility or single-responsibility.

Instance code

The example code demonstrates how to add a product to the shopping cart. The code is very bad. The Code is as follows:

function Product(id, description) {    this.getId = function () {        return id;    };    this.getDescription = function () {        return description;    };}function Cart(eventAggregator) {    var items = [];    this.addItem = function (item) {        items.push(item);    };}(function () {    var products = [new Product(1, "Star Wars Lego Ship"),            new Product(2, "Barbie Doll"),            new Product(3, "Remote Control Airplane")],cart = new Cart();    function addToCart() {        var productId = $(this).attr('id');        var product = $.grep(products, function (x) {            return x.getId() == productId;        })[0];        cart.addItem(product);        var newItem = $('<li></li>').html(product.getDescription()).attr('id-cart', product.getId()).appendTo("#cart");    }    products.forEach(function (product) {        var newItem = $('<li></li>').html(product.getDescription())                                    .attr('id', product.getId())                                    .dblclick(addToCart)                                    .appendTo("#products");    });})();

The Code declares two functions to describe the product and cart respectively, while the role of an anonymous function is to update the screen and interact with the user. This is not a very complex example, however, anonymous functions contain a lot of irrelevant responsibilities. Let's see how many responsibilities are there:

  1. First, there is a declaration of the product set.
  2. Second, there is a code that binds the product set to the # product element, and adds an event to the shopping cart.
  3. Third, the Cart shopping Cart display function is available.
  4. Fourth, you can add the product item to the shopping cart and display it.
Code Reconstruction

Let's break down the code so that the code can be stored in their own objects. For this reason, we refer to the Event Aggregator theory of martinfowler to process the code so that the objects can communicate with each other.

First, let's implement the Event aggregation function. This function is divided into two parts: one is Event, the code used for Handler callback, and the other is EventAggregator used to subscribe to and publish events. The Code is as follows:

        function Event(name) {            var handlers = [];            this.getName = function () {                return name;            };            this.addHandler = function (handler) {                handlers.push(handler);            };            this.removeHandler = function (handler) {                for (var i = 0; i < handlers.length; i++) {                    if (handlers[i] == handler) {                        handlers.splice(i, 1);                        break;                    }                }            };            this.fire = function (eventArgs) {                handlers.forEach(function (h) {                    h(eventArgs);                });            };        }        function EventAggregator() {            var events = [];            function getEvent(eventName) {                return $.grep(events, function (event) {                    return event.getName() === eventName;                })[0];            }            this.publish = function (eventName, eventArgs) {                var event = getEvent(eventName);                if (!event) {                    event = new Event(eventName);                    events.push(event);                }                event.fire(eventArgs);            };            this.subscribe = function (eventName, handler) {                var event = getEvent(eventName);                if (!event) {                    event = new Event(eventName);                    events.push(event);                }                event.addHandler(handler);            };        }

Then, declare the Product object. The Code is as follows:

function Product(id, description) {    this.getId = function () {        return id;    };    this.getDescription = function () {        return description;    };}

Then declare the Cart object. In the addItem function of this object, we will trigger the release of an event itemAdded and then pass the item as a parameter.

function Cart(eventAggregator) {    var items = [];    this.addItem = function (item) {        items.push(item);        eventAggregator.publish("itemAdded", item);    };}

CartController is mainly used to accept cart objects and event aggregators. By subscribing to itemAdded, A li element node is added and added by subscribing to productSelected events.Product.

function CartController(cart, eventAggregator) {    eventAggregator.subscribe("itemAdded", function (eventArgs) {        var newItem = $('<li></li>').html(eventArgs.getDescription()).attr('id-cart', eventArgs.getId()).appendTo("#cart");    });    eventAggregator.subscribe("productSelected", function (eventArgs) {        cart.addItem(eventArgs.product);    });}

The purpose of Repository is to obtain data (which can be obtained from ajax) and then expose the get data method.

function ProductRepository() {    var products = [new Product(1, "Star Wars Lego Ship"),            new Product(2, "Barbie Doll"),            new Product(3, "Remote Control Airplane")];    this.getProducts = function () {        return products;    }}

ProductController defines an onProductSelect method, which is mainly used to publish and trigger the productSelected event. forEach is mainly used to bind data to the product list. The Code is as follows:

function ProductController(eventAggregator, productRepository) {    var products = productRepository.getProducts();    function onProductSelected() {        var productId = $(this).attr('id');        var product = $.grep(products, function (x) {            return x.getId() == productId;        })[0];        eventAggregator.publish("productSelected", {            product: product        });    }    products.forEach(function (product) {        var newItem = $('<li></li>').html(product.getDescription())                                    .attr('id', product.getId())                                    .dblclick(onProductSelected)                                    .appendTo("#products");    });}

Finally, declare the anonymous function (make sure that the HTML is fully loaded before this code can be executed, for example, in the ready method of jQuery ):

(function () {    var eventAggregator = new EventAggregator(),cart = new Cart(eventAggregator),cartController = new CartController(cart, eventAggregator),productRepository = new ProductRepository(),productController = new ProductController(eventAggregator, productRepository);})();

We can see that the code of the anonymous function is much reduced, mainly because of the instantiation code of an object. In the code, we introduce the concept of Controller, which accepts information and passes it to action, we also introduced the concept of Repository, which is mainly used to process the display of product. The result of refactoring is to write a lot of object declarations, but the advantage is that each object has its own clear responsibilities, this shows the data presentation, and changes the processing set of the processing set, so that the coupling degree is very low.

Final code Summary

Looking at the reconstruction result, some bloggers may ask, is it really necessary to make it so complicated? I can only say: whether or not to do so depends on your project.

If your project is a very small project with less code, there is no need to refactor it so complicated, however, if your project is a very complex and large project, or your small project may grow rapidly in the future, you have to consider the SRP principle for separation of duties in the early stage, this will facilitate future maintenance.

Copyright statement: This article is the original author of the http://www.zuiniusn.com, not allowed by the blogger can not be reproduced.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.