一.单一职责原则(Single Responsibility Principle)缩写SRP
就一个类而言,应该仅有一个引起它的变化原因(换句话说,也就是一个类最好制作一件事(这个一件事的定义比较难定义,看个人))
例子:imageLoader
最开始的imageLoader里面有 图片加载逻辑 和 处理图片缓存的逻辑 ,这在我们看来就不符合SRP原则,所以要分开,分成图片加载逻辑(ImageLoader),和缓存部分(ImageCache)
二.开闭原则(Open Close Principle)缩写是OCP
开闭原则定义是:软件中的对象(类,模块,函数等)应该对于扩展是开放的,但是对于修改是封闭的。(换句话说,让软件需要变化时,我们应该尽量通过扩展的方式来实现变化,而不是通过修改已有的代码来实现)
例子:ImageLoader 需要加个缓存机制(本地或者网络)
问题:怎么让缓存机制变得可扩展,可以让用户随便改
public class ImageLoader {
//图片缓存
ImageCache mImageCache = new MemoryCache();
.....//一些代码
//注入缓存实现
public void setmImageCache(ImageCache cache){
mImageCache = cache;
}
public void display(String imageUrl,ImageView imageView){
//如果图片不是null就设置图片
//如果图片是null就去获取 //提交到线程池去下载
submitLoadRequest(imageUrl,imageView);
}
public void submitLoadRequest(final String imageUrl ,final ImageView imageView){
....//一些代码
@Override
public void run () {
...//一些代码
mImageCache.put(imageUrl, imageView);
}
}
}
上面是最终代码,可以看出解决了问题,用什么缓存机制由我们自己说了算通过setImageCache(这里默认用了Memory)
public interface ImageCache{
public Bitmap get(String url);
public void put(String url,Bitmap bmp);
}
然后不管是内存缓存还是本地缓存,或者两者都有都继承这个就行,然后用户自己定制就可以了
比如
MemoryCache,DiskCache,DoubleCache都是实现接口ImageCache,所以可以这么干
imageloader.setImageCache(new MemoryCache())
imageloader.setImageCache(new DiskCache())
imageloader.setImageCache(new DoubleCache())
三.里氏替换原则(Liskov subsitution Princile)简称LSP
所有引用基类的地方必须能透明地使用其子类的对象。(说白了就是只要父类能出现的地方子类就能出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类,但是反过来就不行,有子类的地方,父类未必就能适应,最后其实就是抽象)
MemoryCache,DiskCache,DoubleCache都是实现接口ImageCache,所以可以这么干
imageloader.setImageCache(new MemoryCache())
imageloader.setImageCache(new DiskCache())
imageloader.setImageCache(new DoubleCache())
这个就是用到了里氏替换原则。
四.依赖倒置原则(Dependence Inversion Principle)
依赖倒置原则有以下几个关键点。
(1)高层模块(调用端)不应该依赖低层模块(具体实现类),两者都应该依赖抽象
(2)抽象(接口或者抽象类)不应该依赖细节
(3)细节(实现接口或继承抽象类而产生的类就是细节)应该依赖抽象
在Java语言中的表现就是:模块间的依赖通过抽象发生,实现类之间不发生直接依赖关系,其依赖关系是通过接口或抽象类产生的。
例如上面的例子:
public class ImageLoader {
//图片缓存
ImageCache mImageCache = new MemoryCache();
.....
}
可以看出ImageLoader依赖的是接口ImageCache,这个就是对的
如果是下面这样那就是依赖细节了
public class ImageLoader {
//图片缓存
MemoryCache memoryCache = new MemoryCache();
.....//
}
这样就不行,不方便扩展
ImageCache mImageCache = new MemoryCache();
这样写的话,如果有需求要改的话只需要实现ImageCache类或者继承其他已有的ImageCache子类完成相应的缓存功能。这样就保证了高扩展性!!!
五.接口隔离原则(Interface Segregation Principles)简称ISP
其实就是客户端不应该依赖他不需要的接口(也可以理解为:类间的依赖关系应该建立在最小的接口上)
public void put(String url,Bitmap bmp){
try{
FileOutputStream fileOutputStream = null;
fileOutputStream = new FileOutputStream(cacheDir + url);
bmp.compress(Bitmap.CompressFormat.PNG, 100 , fileOutputStream);
}catch (FileNotFoundException e){
e.printStackTrace();
}finally {
if(fileOutputStream != null){
try{
fileOutputStream.close();
}catch{
e.printStackTrace();
}
}
}
}
Try catch各种嵌套,这样看起来很不好看影响代码阅读性
<span style="font-family: Arial, Helvetica, sans-serif;">public final class CloseUtils{</span>
private CloseUtils(){}
/**
* 关闭Closeable对象
* @param closeable
* */
public static void closeQuitely(Closeable closeable){
if(null != closeable){
try{
closeable.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
public void put(String url ,Bitmap bmp){
FileOutputStream fileOutputStream = null;
try{
FileOutputStream fileOutputStream = null;
fileOutputStream = new FileOutputStream(cacheDir + url);
bmp.compress(Bitmap.CompressFormat.PNG, 100 , fileOutputStream);
}catch (FileNotFoundException e){
e.printStackTrace();
}finally {
CloseUtils.closeQuitely(fileOutputStream);
}
}
这个方法的基本原理就是依赖于Closeable抽象而不是具体实现,并且建立在最小化依赖原则的基础上,他只需要知道这个对象是否可关闭,其他的一概不关心
六.迪米特原则(Law of Demeter)缩写LOD
一个对象应该对其他对象有最少的了解
例子:在北京租房
/**
* 房间
* */
public class Room{
public Room(float area ,float price){
this.area = area;
this.price = price;
}
@Override
public void toString(){
return "Roomasdsad"
}
}
/**
* 中介
* */
public class Mediator{
List<Room> mRooms = new ArrayList<>(Room)();
public Mediator(){
for(int i =0;i<5;i++){
mRooms.add(new Room(14+i,(14+i)*150));
}
}
public List<Room> getAllRooms(){
return mRooms;
}
}
/**
* 租户
* */
public void Tenant{
public float roomArea;
public float roomPrice;
public static final float diffPrice = 100.0001f
public static final float diffArea = 0.00001f;
public void rentRoom(Mediator mediator){
List<Room> rooms = mediator.getAllRooms();
for(Room room : rooms){
if(isSuitable(room)){
System.out.println("租到房间啦 !" +room);
break;
}
}
}
}
可以看出Tenant不仅依赖Mediator类,还需要频繁地与Room类打交道
,租户类的要求只是通过中介找到一间适合自己的房间罢了,如果把这些检测条件都放在Tenant类中,那么中介类的功能就被弱化了,而导致Tenant与Room的耦合较高
(会导致当Room变化时Tenant也必须跟着变化,Tenant又与Mediator耦合)
/**
* 房间
* */
public class Room{
public Room(float area ,float price){
this.area = area;
this.price = price;
}
@Override
public void toString(){
return "Roomasdsad"
}
}
/**
* 中介
* */
public class Mediator{
List<Room> mRooms = new ArrayList<>(Room)();
public Mediator(){
for(int i =0;i<5;i++){
mRooms.add(new Room(14+i,(14+i)*150));
}
}
public void rentOut(float area,float price){
for(Room room : rooms){
if(isSuitable(area ,price ,room)){
System.out.println("租到房间啦 !" +room);
break;
}
}
private boolean isSuitable(float area , float price,Room room){
return Math.abs(room.price - price )<Tenant.diffPrice &&Math.abs(room.area -area ) - Tenant.diffprice;
}
}
}
/**
* 租户
* */
public void Tenant{
public float roomArea;
public float roomPrice;
public static final float diffPrice=100.0001f
public static final float diffArea=0.00001f;
public void rentRoom(Mediator mediator){
System.out.println("租到房了"+mediator.rentOut(roomArea,roomPrice))
}
}
这里只是将对于room的判定操作转移到了Mediator类中,这本应该是Mediator的职责