`

设计模式--6大原则和评析

 
阅读更多

 

迪米特法则    设计模式之禅5:迪米特法则[这篇写得比较易懂]

接口隔离原则

 

单一职责原则 【其中之一是行为应该和属性有关】

里氏置换原则

依赖倒置原则

 开闭原则

 

我的评注:

1、单一职责 【应该有且仅有一个原因引起类的变更】

1、依赖倒置原则(Dependence Inversion Principle),【原理是利用接口的方法调用来执行子类方法】DIP中,cook意思是做了就能吃,既noodles.eat() 之前有些做东西的过程的代码省略没有写出。 而且我建议eat改成beEat,更接近自然语义。 

eat的方法放Tutu里,不过这样要表达兔兔做了饭再吃饭就会是这样:tutu.cook(food);  tutu.eat(food); 当然如果做饭需要时间,且要求做了才能吃就需要同步:tutu.cook(food, function(food1){ tutu.eat(food1) })  做完回调时才吃。这样的话面条类就没啥方法了,不如移到Tutu里变成一个更抽象的“食物类”属性,毕竟食物没有什么主动行为。 如:

function Tutu {
    Foods food=null;
    //涂涂是个女孩,会煮面
    function cook(food, callback)
    {
        //do cook
		console.log('做完食物:'+ food)
        callback(food)
    }
    function eat(food1)
    {
        //do eat
		console.log('吃'+food1)
    }
}


function Home {
    tutu = new Tutu();
	tutu.cook('米饭');
	tutu.eat('米饭');
}

 也是做什么吃什么,不过食物作为兔兔的属性也怪。毕竟兔兔不是吃货,不用老带着个食物,食物确实应该单独一个类和兔兔去耦合。  如果以后还要求多煮几种饭放在冰箱里,这就要求Foods在做的时候要多加存冰箱动作,这动作就又耦合到了兔兔类里了【属性关联的方法在类里】,就算兔兔是个吃货也不能总随身拖着个冰箱啊(⊙﹏⊙b汗),cook好后就把Foods的实例(某种饭)存冰箱不就行了吗?  于是回之前的代码,并给食物加个储存方法(store),回顾前面说的eat,发现和store是相似的啊,难道要移回Tutu类? 这样食物岂不又没方法又可以移回Tutu里? 再分析下eat移回的原因是这动作属于Tutu发出的。。。

 

2、接口隔离

【2.1客户端不应该强行依赖它不需要的接口(依赖原文是以来).

2.2 类间的依赖关系应该建立在最小的接口上()】

如果完全遵循接口隔离原则的话,会出现一个问题。即接口的设计粒度会越来越小【粒度原文是力度】

接口隔离原则与单一职责原则有些相似,不过不同在于:单一职责原则要求的是类和接口职责单一,注重的是职责,是业务逻辑上的划分。而接口隔离原则要求的是接口的方法尽量少,尽量有用(针对一个模块)

 

3、里氏置换:如果子类参数范围比父类的小:

f.say(map); //父类被执行...  本该调用子类的方法的,因为传入的的是 HashMap类型的,

//但是因为 父类 say的参数类型 Map比 HashMap范围更广(Map是HashMap的父类), 于是父类的say方法被执行

//【这用到规则是:用到父类的地方能用子类替换】

 

s.say(map); //子类被执行...

 

3、迪米特法则 【不要让友类在一个逻辑里使用太多本类的方法,有这种逻辑最好提供一个门面函数(我借用门面模式说,就是把组合的几个函数合成一个大函数,这类似于RISC的强功能指令是把几个基本指令的功能合在一起提供的)】

例1讲teacher和陌生类girl不要有依赖,只让体育委员和girl有依赖,并在场景中注入这依赖。老师通知体育委员清点学生人数。老师是不需要知道所有学生的(不依赖于girl类)。体育委员则像个代理。

例2中讲的是如果Wizard的朋友InstallSoftware的对它依赖太多(InstallSoftware某一个方法调用Wizard的很多方法,这样耦合也更紧密)这样只要改变Wizard中的其中一个被调用的方法(first)就会影响整块调用,造成影响范围太广)。

而如果只依赖一个统一的安装过程方法(Wizard里)就不会有此影响。 总结:只要是依赖是1对多{设为集合more}的,那么多的这方改变任何一个{m}的元素就可能会影响到整块{m}。

 

6、开闭原则 【对扩展开放,对修改关闭】

扩展接口来达到扩展其问题领域

 

我提问:

1、LSP里氏里说到了覆盖和重载,发现js原生语言里只能覆盖(不能通过参数类型不同实现重载),那么重载的好处有哪些?

1.1第一想到的就是同一行为要处理不同数据类型.

1.2介绍里面讲的子类实例调用从父类重载而来的方法say和自己的方法say【同名而参数类型不同】( 例子3的意思是(例子有点小问题,应该是在把父类和子类的say方法的参数类型变换后,子类传入父类say方法的参数类型. 本例要抓住重载方法,子类要使用从父类重载来的方法·[这里是函数名相同都是say,而参数类型不同]):场景里传入HashMap对象后,父类调用自己的say方法,子类实例由于传入的是HashMap类型的参数,所以调用的是从父类重载来的say方法,而不是自己的say(参数类型不同),这样就可以根据参数的类型决定调用的是否是重载的方法。但如果父类里被重载的方法say里的参数声明的是Map类型 而子类的反而是比它范围还小的HashMap,那 f.say(); s.say()得到结果是 “父类被调用了”,“子类被调用了” ,后一句明明传入的是父类类型(Map)的参数,却不是执行从父类重载来的方法,而是执行了自己的say)

总之:重载方法的参数类型应该>=父类的参数类型

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics