基于《Android源码设计模式解析与实战》
- 单一职责原则
- 开闭原则
- 里氏替换原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特原则
单一职责原则
定义:就一个类而言,应该仅有一个引起它变化的原因。
简单来说就是把类的功能拆分开,不要那么臃肿,不然扩展性非常差。
我接着拿书中的例子来说事:
一开始是:
单一职责原则-bug.png
将缓存的处理和显示都放到了一个类里面,代码严重耦合;
明确一些单一职责原则,重构:
单一职责原则.png
将图片加载和图片缓存的职责单独提出来了。
开闭原则
定义:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。
简单来说就是面向抽象编程,就比如说我们去点菜,假设就一次机会,你说你要吃猪肉,这要是没有那岂不是糟糕,但是如果你说你要吃肉,这就有的聊了,鸡肉猪肉牛肉可以随便上,总有一样有的;
还是借助书上的例子:
在此基础上需要本地缓存
开闭原则-bug.png
两种缓存策略在displayImage中通过isUseDiskCache来判断;该策略的bug就是用户只能在这两种策略中二选一,不能同时使用内存缓存和磁盘缓存;
开闭原则-bug2.png
通过设置两个标签可以使用内存缓存/磁盘缓存/双缓存;这边的问题是每次加入新的缓存实现就要修改代码,而且用户还不能自定义缓存;
开闭原则.png
这样ImageLoader只依赖ImageCache这个抽象,用户可通过实现这个接口来完成自定义缓存;
对扩展是开放的,对修改是封闭的。主要是通过抽象来实现;
里氏替换原则
定义:所有引用基类的地方必须能透明地使用其子类的对象。
里氏替换原则.png
主要是通过继承和多态的形式提高代码的扩展性。
依赖倒置原则
定义:一种特定的解耦形式,使得高层次的模块不依赖与低层次的模块的实现细节的目的,依赖模块被颠倒了。
关键点:
- 高层模块不应该依赖低层模块,二者都应该依赖抽象;
- 抽象不应该依赖细节;
- 细节应该依赖抽象;
Java中,抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类;
依赖倒置原则.png模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系;
ImageCache抽象,这里就是当用户使用不同的缓存实现时,直接通过依赖注入即可,保证了系统的灵活性。
主要思想就是依赖抽象。
接口隔离原则
定义:客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。
接口隔离原则将非常庞大、臃肿的接口拆分成更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。
import java.io.Closeable;
import java.io.IOException;
/**
*
* @author xy
*
*/
public class CloseUtils {
private CloseUtils() {
}
/**
* 关闭Closeable对象
*
* @param closeables
*/
public static void closeQuietly(Closeable... closeables) {
if (null != closeables) {
for (Closeable closeable : closeables) {
if (null != closeable) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
只要实现了Closeable这个接口,就可以通过这个方法关闭,而不用去关注其他的东西。
举个简单的例子:
人的一生的生活习惯有很多:吃什么,喝什么,玩什么。。。。。。
用接口来描述行为:
package com.principle.isp;
public interface Life {
/**
* 吃啥
*/
void eatWhat();
/**
* 怎么吃
*/
void eatHow();
/**
* 在哪吃
*/
void watWhere();
/**
* 喝啥
*/
void drinkWhat();
/**
* 怎么喝
*/
void drinkHow();
/**
* 去哪喝
*/
void drinkWhere();
/**
* 等等......
*/
}
如果我们想研究一个人的生活习惯--吃的时候,我们要实现这个接口,就抛不开喝还有玩等等;但是如果我们使用接口隔离:
package com.principle.isp;
/**
*
* @author xy
*
*/
public interface Eat {
/**
* 吃啥
*/
void eatWhat();
/**
* 怎么吃
*/
void eatHow();
/**
* 在哪吃
*/
void watWhere();
}
package com.principle.isp;
/**
*
* @author xy
*
*/
public interface Drink {
/**
* 喝啥
*/
void drinkWhat();
/**
* 怎么喝
*/
void drinkHow();
/**
* 去哪喝
*/
void drinkWhere();
}
这样当我研究吃的时候,我可以只关注吃,研究喝的时候只关注喝;
就像我想学设计模式、算法、混合开发、网络、h5等等,我要是每个都去关注一下,我不知道要耗费多少时间,还不一定会学的通透,还不如我就学习设计模式,等我设计模式学好了,我再去只关注算法,每次我只关于一样,平时融会贯通;不好意思,牛逼吹大了,我给自己一巴掌。
迪米特原则
定义:一个对象应该对其他对象有最少的了解。
迪米特原则-bug.png一个类应该对自己需要耦合或调用的类知道的最少,类的内部如何实现与调用者或者依赖着没有关系,调用者或者依赖着只需要知道它需要的方法即可,其他的可一概不用管。类与类之间关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
中介和房源,客户耦合,客户和房源、中介耦合,耦合太严重;
迪米特原则.png
中介和房源、客户打交道;而客户只与中介打交道,降低耦合度。
现在可以来总结一下:主要有六个原则:
- 单一职责原则
- 开闭原则
- 里氏替换原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特原则
简单点概括就是:要功能细化,面向抽象,降低耦合。
/**
* 1、功能要单一;
* 2、多态抽象
* 3、降低耦合
*
* 我就以一部仙侠的大背景来展开描述;
* 上古时期,群魔乱舞,世人可不堪言,急需大能者救世;
* 救世分两种:救人和救世(单一职责)
* 目前世间有大造化者:儒释道,统称救世主,救世主集团封锁了整片战场;主要你有大能力,就可以得到救世主铭牌,就可以进入主战场,
* 主战场的大门识别系统识别铭牌(依赖倒置原则);主战场里面有大阵,当一个阵法师被消灭后,他的族人后代就继续顶替他,毕竟他们家都会xxxx大阵(里氏替换原则)
* 救世主铭牌是根据个人的功法,经验,德行来评判,不限制具体的考核(开闭原则)
* 每个救世主集团要根据不同的任务类型去派遣不同的弟子(接口隔离原则):炼制武器,炼制丹药
* 救世主只负责救世,由任务堂统一分配任务,任务堂接触受难者,了解任务,接触弟子,分配任务(迪米特原则)
*
*/
网友评论