面向对象的六大基本原则

来源:互联网 发布:玉虚男捏脸数据 编辑:程序博客网 时间:2024/06/05 11:12

一.单一职责原则(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类中,那么中介类的功能就被弱化了,而导致TenantRoom的耦合较高

(会导致当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的职责

0 0
原创粉丝点击