`

S.O.L.I.D五大原则之SRP(单一职责)

    博客分类:
  • js
阅读更多
文章转自:http://tech.ddvip.com

单一职责的描述如下:
一个类(JavaScript下应该是一个对象)应该有一组紧密相关的行为的意思是什么?遵守单一职责的好处是可以让我们很容易地来维护这个对象, 当一个对象封装了很多职责的话,一旦一个职责需要修改,势必会影响该对象想的其它职责代码。通过解耦可以让每个职责工更加有弹性地变化。

不过,我们如何知道一个对象的多个行为构造多个职责还是单个职责?我们可以通过参考Object Design: Roles, Responsibilies, and Collaborations一书提出的Role Stereotypes概念来决定,该书提出了如下Role Stereotypes来区分职责:
Information holder – 该对象设计为存储对象并提供对象信息给其它对象。
Structurer – 该对象设计为维护对象和信息之间的关系
Service provider – 该对象设计为处理工作并提供服务给其它对象
Controller – 该对象设计为控制决策一系列负责的任务处理
Coordinator – 该对象不做任何决策处理工作,只是delegate工作到其它对象上
Interfacer – 该对象设计为在系统的各个部分转化信息(或请求)

一旦你知道了这些概念,那就狠容易知道你的代码到底是多职责还是单一职责了。
实例代码
该实例代码演示的是将商品添加到购物车,代码非常糟糕,代码如下:

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");
    });
})();


该代码声明了2个function分别用来描述product和cart,而匿名函数的职责是更新屏幕和用户交互,这还不是一个很复杂的例子,但匿名函数里却包含了很多不相关的职责,让我们来看看到底有多少职责:
首先,有product的集合的声明
其次,有一个将product集合绑定到#product元素的代码,而且还附件了一个添加到购物车的事件处理
第三,有Cart购物车的展示功能
第四,有添加product item到购物车并显示的功能
重构代码
让我们来分解一下,以便代码各自存放到各自的对象里,为此,我们参考了martinfowler的事件聚合(Event Aggregator)理论在处理代码以便各对象之间进行通信。
首先我们先来实现事件聚合的功能,该功能分为2部分,1个是Event,用于Handler回调的代码,1个是EventAggregator用来订阅和发布Event,代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
<script type="text/javascript" src="js/mylib2.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
</head>

<body>

<ul id="products">

</ul>

<ul id="cart">

</ul>

<script type="text/javascript">
// 通过原型声明数组的forEach方法
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, thisObj) {
        var scope = thisObj || window;
        for (var i = 0, j = this.length; i < j; ++i) {
            fn.call(scope, this[i], i, this);
        }
    };
}

// 事件类
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);
    };
}
 
// 产品实现类
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);
        eventAggregator.publish("itemAdded", item);
    };
}
 
// 购物车控制器,负责给购物车绑定处理程序
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);
    });
}
 
// 产品库
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;
    }
}
 
// 产品控制器,负责取得产品,显示产品列表
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");
    });
}

(function () {
    var eventAggregator = new EventAggregator(),
        cart = new Cart(eventAggregator),
        cartController = new CartController(cart, eventAggregator),
        productRepository = new ProductRepository(),
        productController = new ProductController(eventAggregator, productRepository);
})();
</script>
</body>
</html>



注:五大原则分别是:
The Single Responsibility Principle(单一职责SRP)
The Open/Closed Principle(开闭原则OCP)
The Liskov Substitution Principle(里氏替换原则LSP)
The Interface Segregation Principle(接口分离原则ISP)
The Dependency Inversion Principle(依赖反转原则DIP)
分享到:
评论

相关推荐

    深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP

    前言 Bob大叔提出并发扬了S.O.L.I.D五大原则,用来更好地进行面向对象编程,五大原则分别是: The Single Responsibility Principle(单一职责SRP) The Open/Closed Principle(开闭原则OCP) The Liskov ...

    你知道软件设计的6大原则吗?S.O.L.I.D.设计原则

    ### S.O.L.I.D.设计原则详解 #### 一、引言 软件设计的原则是构建高质量、可维护软件的关键。本文将深入探讨S.O.L.I.D.设计原则,这一组原则由Robert C. Martin(也被称为Bob大叔)在其著作《Agile Principles, ...

    深入理解JavaScript系列.chm

    6.S.O.L.I.D五大原则之单一职责SRP 7.S.O.L.I.D五大原则之开闭原则OCP 8.S.O.L.I.D五大原则之里氏替换原则LSP 9.根本没有“JSON对象”这回事! 10.JavaScript核心(晋级高手必读篇) 11.执行上下文(Execution ...

    单一原则SRP.zip

    《单一原则(SRP)在程序设计中的应用与实践》 单一职责原则(Single Responsibility Principle,简称SRP)是面向对象设计的基本原则之一,由罗伯特·C·马丁(Robert C. Martin)在其著作《Clean Architecture》中...

    单一职责原则(SRP)

    单一职责原则(SRP)是面向对象设计的五个基本原则之一。该原则规定,一个类应当只有一个引起它变化的原因。换言之,一个类应该只有一个职责,避免一个类承担多个职责,从而降低类的耦合度和设计复杂度。 在软件...

    SRP.rar_SRP.rar_srp_srp全称_srp项目 全称_华南理工

    【标题】"SRP.rar" 是一个压缩文件,其中包含了华南理工大学学生研究计划(SRP)的相关资料。"SRP.rar_srp_srp全称_srp项目 全称_华南理工" 这个标题暗示了文件的核心内容是关于SRP项目,特别是其在华南理工大学的...

    单一职责原则.pdf

    **单一职责原则(Single Responsibility Principle, SRP)**是面向对象设计的基本原则之一,由罗伯特·C·马丁(Robert C. Martin)提出,并在《敏捷软件开发:原则、模式和实践》中阐述。这一原则是SOLID原则的首...

    Java设计模式中单一职责原则详解.rar

    其中,"单一职责原则"(Single Responsibility Principle,SRP)是面向对象设计的基本原则之一,也是Java设计模式中的重要组成部分。本篇文章将深入探讨单一职责原则的概念、意义、应用及其在Java编程中的实际运用。...

    6单一职责原则-课程内容.rar

    其中,“单一职责原则”(Single Responsibility Principle,SRP)是面向对象设计的五个核心原则之一,由罗伯特·C·马丁(Robert C. Martin)在其著作《Clean Code》中提出。这个原则强调一个类或模块应该只有一个...

    srp.rar_Because...

    标题中的"srp.rar_Because..."暗示我们正在讨论与"SRP"(Secure Remote Password 协议)相关的内容,而“Because…”可能是指在实现或理解该协议时遇到的一个问题或原因。描述中提到,“我们需要packed属性,因为SRP...

    Desafio-04-S.O.L.I.D

    【标题】"Desafio-04-S.O.L.I.D" 指向的是一个编程挑战,该挑战可能关注于SOLID原则的应用。SOLID是面向对象设计中的五个基本原则的首字母缩写,它们分别是单一职责原则(Single Responsibility Principle, SRP)、...

    设计模式六大原则(1):单一职责原则

    本文将深入探讨这六大原则中的第一个——单一职责原则(Single Responsibility Principle, SRP),并结合AcountYear.java这个文件名来解析该原则的应用。 单一职责原则指出,一个类或者一个模块应该只有一个引起它...

    深入理解JavaScript系列

    深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP 深入理解JavaScript系列(7):S.O.L.I.D五大原则之开闭原则OCP 深入理解JavaScript系列(8):S.O.L.I.D五大原则之里氏替换原则LSP 深入理解...

    PHP面向对象五大原则之单一职责原则(SRP)详解

    单一职责原则(SRP)是面向对象设计中的一个基本原则,它要求一个类应该只有一个引起它变化的原因。在PHP等面向对象编程语言中,遵守这一原则可以帮助开发人员编写出结构更清晰、维护性更强的代码。接下来,我们将详细...

    SSRP筹码峰.doc

    SSRP筹码峰.doc

    单一职责模式例子。

    在软件设计领域,单一职责原则(Single Responsibility Principle,简称SRP)是面向对象设计的六大原则之一,由罗伯特·C·马丁(Robert C. Martin)在其著作《Clean Code》中提出。这个原则强调一个类或者模块应当...

    单一职责原则

    **单一职责原则(Single Responsibility Principle, SRP)**是面向对象设计中的一个重要原则,由罗伯特·C·马丁(Robert C. Martin)提出。这一原则指出,一个类或者模块应该有且只有一个职责,即它应该只负责一项...

    软件设计的五大原则PPT课件.ppt

    软件设计的五大原则是软件开发过程中的核心指导思想,它们分别是单一职责原则(Single Responsibility Principle,SRP)、开放封闭原则(Open-Closed Principle,OCP)、里氏替换原则(Liskov Substitution ...

    6单一职责原则-MOOC课程内容.pdf

    单一职责原则(Single Responsibility Principle,简称SRP)是面向对象设计(OOD)中的一个基本原则。它强调每个类应该只有一个改变的理由,意味着一个类应该只有一个职责,只有一个因素能引起这个类的变更。当类...

Global site tag (gtag.js) - Google Analytics