致程序设计的五大原则
单一职责原则
概念解释:
就一个类而言,应该仅有一个引起它变化的原因,如果你能想到多于一个动机去改变一个类,那么这个类就具有多于一个类的职责。应该把多于的职责分离出去,分别再创建一些类来完成每一个职责。简而言之,一个类仅干一件事。
前端意义:
在前端的业务层中,我们有时会使用一个单例模式,创建一个对象,耦合页面中所有的业务操作,做到对命名空间的划分,和方便统一操作。但是,在这个中间,会遇到一个问题,从职责上划分,这个对象拥有多个职责,不符合单一职责原则。有什么坏处?第一点,单个程序文件的代码超过300行,我就认为这个代码是难以维护的,这里显然很容易超过这个量级。第二点,业务层的代码之后若是要抽离成组件,代价巨大,因为类的职责不够清晰。第三点,代码难以被其他业务复用,并且业务代码也很难被定制。
举个例子:
多职责:
var index = (function(){
return {
login : function() {
...
},
dialog : function() {
...
},
tab : function() {
...
},
play : function() {
...
},
...
}
})();
单一职责(利用seajs):
define(function(require, exports, module){
var $ = require("jquery");
var login = require("./login");
var dialog = require("./dialog");
var tab = require("./tab");
var play = require("./play");
$(function(){
login();
dialog();
tab();
play();
})
})
开放封闭原则
概念解释:
一个软件实体应当对扩展开发,对修改关闭.说的是,再设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展.换言之,应当可以在不必修改源代码的情况下改变这个模块的行为,在保持系统一定稳定性的基础上,对系统进行扩展。这是面向对象设计(OOD)的基石,也是最重要的原则。简而言之,修改类只能在外部扩展,不能在内部修改。
前端意义:
这个场景在前端编写js类库的时候经常用到,大名鼎鼎的jquery使用的插件机制,就是符合了这一个原则,对内封闭,对外开放。对于开放封闭原则的代码实现,我们往往要用到的是自定义事件。在对象内部,派发事件,在对象外部,通过扩展订阅事件。
自定义事件代码:
/**
* EVENT model
*/
var func = {};
;(function(func) {
var _cache = {};
/**
* 广播事件
* 目标: 为了尽可能的减少模块之间业务逻辑的耦合度, 而开发了这个eventbus, 主要用于业务逻辑的事件传递
* 使用规范: 每个js模块尽可能通过事件去通信, 减少模块之间的直接调用和依赖(耦合)
*/
/**
* 派发
* @param {[type]} type 事件类型
* @param {[type]} data 回调数据
* @return {[type]} [description]
*/
func.fire = function(type, data) {
var listeners = _cache[type],
len = 0;
if (typeof listeners !== 'undefined') {
var args = [].slice.call(arguments, 0);
args = args.length > 2 ? args.splice(2, args.length - 1) : [];
args = [data].concat(args);
len = listeners.length;
for (var i = 0; i < len; i++) {
var listener = listeners[i];
if (listener && listener.callback) {
args = args.concat(listener.args);
listener.callback.apply(listener.scope, args);
}
}
}
return this;
}
/**
* 订阅广播事件
* @param {[type]} types 事件类型,支持,分隔符
* @param {Function} callback 回调函数
* @param {[type]} scope 回调函数上下文
* @return {[type]} this
*/
func.on = function(types, callback, scope) {
types = types || [];
var args = [].slice.call(arguments);
if (typeof types === 'string') {
types = types.split(',');
}
var len = types.length;
if (len === 0) {
return this;
}
args = args.length > 3 ? args.splice(3, args.length - 1) : [];
for (var i = 0; i < len; i++) {
var type = types[i];
_cache[type] = _cache[type] || [];
_cache[type].push({
callback: callback,
scope: scope,
args: args
});
}
return this;
}
/**
* 退订
* @param {[type]} type [description]
* @param {Function} callback 假如传入则移出传入的监控事件,否则移出全部
* @return {[type]} [description]
*/
func.un = function(type, callback, scope) {
var listeners = _cache[type];
if (!listeners) {
return this;
}
if (callback) {
var len = listeners.length,
tmp = [];
for (var i = 0; i < len; i++) {
var listener = listeners[i];
if (listener.callback == callback && listener.scope == scope) {} else {
tmp.push(listener);
}
}
listeners = tmp;
} else {
listeners.length = 0;
}
return this;
}
func.removeAll = function() {
_cache = {};
return this;
}
})(func)
里氏替换原则
概念解释:
子类可以扩展父类的功能,但不能改变父类原有的功能。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。 ### 前端意义: 在前端中,比如弹出层,父类可以定义一些抽象方法,派发给子类去实现,多用于对子类代码的规范。
依赖倒置原则
概念解释:
具体依赖于抽象,抽象不依赖于具体。
前端意义:
这个很简单了,抽象的方法不应该是依赖于具体的实现的。
接口隔离原则
概念解释:
- 一个类对另外一个类的依赖性应该建立在最小的接口上
- 一个接口代表一个角色,不应该把不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染.
不应该强迫客户依赖他们不用的方法。接口属于客户,不属于他所在的类的层次结构
前端意义:
当我们使用接口时在接口里面定义的方法要做要高类聚,作用要单一,不能把什么都放在里面,要用到多接口。在前端中,业务层代码,只需用一个像单一职责模式中的例子,很容易发展成为一个胖接口。所以,我引入了一个区域模块的概念,即一个页面的一块区域的代码接口耦合,这样也方便模块的整拿争取。
举个例子:
区域模块: define(function(require, exports, module){ var $ = require("jquery"); var login = require("./login"); var dialog = require("./dialog");
function loginArea() { login(); dialog(); } return loginArea;
})
业务模块: define(function(require, exports, module){ var $ = require("jquery"); var loginArea = require("./loginArea"); var tab = require("./tab"); var play = require("./play");
$(function(){ loginArea(); tab(); play(); })
})
- Categories:
- frontend 19
- Tags:
- 代码设计 2