1.设计原则
-
开闭原则
开放封闭原则 是所有面向对象原则的核心 软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现 定义: 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对已有代码进行任何修改 -
单一职责原则
如果一个类有一个以上的职责,这些职责就耦合在了一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。 当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性 定义: 不要存在多于一个导致类变更的原因 -
依赖倒置原则
高层模块可看作一个平台,把低层模块放在这个平台上,才能实现其作用 定义: 高层模块不应该依赖低层模块。两个都应该依赖抽像 抽像不应该依赖细节,细节应该依赖抽像 -
里氏替换原则
如果对每个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类。换句话说,所有引用基类的地方必须透明地使用其子类对象。 在使用继承时,遵循里氏替换原则在子类中尽量不要重写父类得方法 里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当得情况下,可以通过聚合,组合,依赖来解决问题 -
接口隔离原则
实例接口:比如定义了一个Person类,然后 Person p = new Pserson(); 产生一个实例,Person类就是 p 的接口 类接口:就是Java中使用 interface 定义的接口 定义: 1、客户端不应依赖它不需要的接口 2、类间的依赖关系应该建立在最小的接口上 其实通俗来理解就是,不要在一个接口里面放很多的方法,这样会显得这个类很臃肿。接口应该尽量细化,一个接口对应一个功能模块,同时接口里面的方法应该尽可能的少,使接口更加灵活轻便。 单一职责原则是在业务逻辑上的划分,注重的是职责。接口隔离原则是基于接口设计考虑。例如一个接口的职责包含10个方法,这10个方法都放在同一接口中,并且提供给多个模块调用,但不同模块需要依赖的方法是不一样的,这时模块为了实现自己的功能就不得不实现一些对其没有意义的方法,这样的设计是不符合接口隔离原则的。接口隔离原则要求"尽量使用多个专门的接口"专门提供给不同的模块。 -
迪米特法则
定义: 迪米特法则的定义是只与你的直接朋友交谈,不与"陌生人"说话。如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该应用。其目的是降低类之间的耦合度,提高模块的相对独立性。 迪米特法则中的朋友是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。 优点: 1、降低类之间的耦合度,提高模块的相对独立性。 2、由于亲和度降低,从而提高了类的可复用率和系统的扩展性。 缺点: 过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需 要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。 使用迪米特法则需要注意: 1、在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。 2、在类的结构设计上,尽量降低类成员的访问权限。 3、在类的设计上,优先考虑将一个类设置成不变类。 4、在对其他类的引用上,将引用其他对象的次数降到最低。 5、不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。 6、谨慎使用序列化(Serializable)功能。
2.设计模式
创建型
工厂模式
目的:方便我们大量创建对象
应用场景:当某一个对象需要经常创建的时候
function Factory(type){
switch(type){
case 'type1':return new Type1();
case 'type2':return new Type2();
case 'type3':return new Type3();
}
}
工厂模式就是写一个函数,只需要调用这个方法,就能拿到想要的对象
建造者模式
目的:需要组合出一个全局对象;
应用场景:当要创建单个,庞大的组合对象时(eg:轮播图,编辑器插件)
function Mode1(){}
function Mode2(){}
function Final(){
this.model = new Mode1()
this.mode2 = new Mode2()
}
把一个复杂的类各个部分,拆分成独立的类,然后在最终类李组合在一起,final为最终给出去的类;
单例模式
目的:需要确保全局只有一个对象
应用场景:为了避免重复新建,避免多个对乡村在相互干扰(eg:vue-router)
let Singleton = function(name){
this.name = name
}
Singleton.getInstance = function(name){
if(this.instance){
return this.instance
}
return this.instance = new Singleton(name)
}
通过定义一个方法,使用只允许通过此方法拿到存在内部的同一实例化对象
function store(){
this.store = {}
if(store.install){
return store.install
}
store.install = this
}
store.install = null
var s1 = new store()
var s2 = new store()
//此时s1 和 s2 指向的是同一个实例对象
结构型
桥接模式
目的:通过桥接代替耦合
应用场景:减少模块之间的耦合
通过将不变化部分和变化部分离开,通过独立方法间的桥接来形成整体功能,这样每个方法都可以被高度复用
function menuItem(word,color){
this.word = word
this.dom = document.createElement('div')
this.dom.innerHTML = word
this.color = color
}
menu.prototype.bind = function(){
var self = this
this.dom.onmounseover = function(){
this.style.color = self.color.colorOver
}
this.dom.onmounseout = function(){
this.style.colorOut = self.color.colorOut
}
}
function menuColor(colorOver,colorOut){
this.colorOver = colorOver
this.colorOut = colorOut
}
var data = [
{word:'menu1',color:'red'},
{word:'menu2',color:'green'},
{word:'menu3',color:'yellow'}
]
for(let i=0;i<data.length;i++){
new menuItem(data[i].word,new menuColor(data[i][0],data[i][1])).bind()
}
享元模式
目的:减少对象/代码数量
应用场景:当代码中创建了大量类似对象和类似的代码块;即行为相同,但是内容不同(eg:jq的extend方法)
将公共部分提取出来,私有部分提取出来作为一个享元
适配器模式
目的:通过适配器,来代替替换
应用场景:面临接口不通用的问题
装饰者模式
目的:不重写方法的拓展方法
应用场景:当一个方法需要拓展,但是又不好去修改方法
命令模式
目的:解耦实现和调用,让双方互不干扰
应用场景:调用的命令充满不确定性