面向对象的六大基本原则

一.单一职责原则(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的职责

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值