java 七大设计原则之依赖倒置,里氏替换原则,文字代码相结合理解
喜欢就争取,得到就珍惜,错过就忘记。人生也许不尽完美,正因为不完美,我们才需要不断地努力创造努力奋斗。时间就是生命,所以我们必须珍惜宝贵的生命,执着地守候生命中每一个必经的十字路口。
七大设计原则有哪些?
- 单一职责原则
- 接口隔离原则
- 依赖倒转(倒置)原则
- 里氏替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
通常大家理解的是前六个,并没有合成复用原则
为什么要使用七大设计原则?
- 代码重用性(相同的代码不用多次编写);
- 可读性(编程的规范性,便于其他程序员的阅读和理解);
- 可拓展性(当需要添加新的功能时,非常的方便也称为可维护性);
- 可靠性(当我们添加新的功能后对原来的功能没有影响);
- 使程序呈现高内聚,低耦合等特性
依赖倒置原则
依赖倒置原则定义:
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 依赖倒转原则的中心思想就是面向接口编程
- 使用接口或者抽象类的目的是制定好规范,而不涉及任何的具体操作,把细节的任务交给实现类去完成
依赖倒转原则是基于这样的设计理念:相对于细节得多变性,抽象的东西要稳定的多。以抽象为基础搭建的框架比细节为基础的架构要稳定得多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类
普通代码:
//输出消息
public class QQNews {
public void run(){
Log.i("Inversion","我是 QQ 发送的消息 ");
}
}
//接收消息
public class Information {
public void showInfo(QQNews qqNews){
qqNews.run();
}
}
//使用代码:
Information information = new Information();
information.showInfo(new QQNews());
问题:
- 直接与类之间交互,传输消息比较固定
- 如果我现在想接收微信消息他是没办法接收的,因为代码已经固定了,现在只接受QQ的消息,如果需要接收微信的消息,还需要在Information类中重新写接收微信消息的方法.
- 没有’缓冲层’,showInfo()方法直接与QQNews类交互,'弹性度’太低
- 没有遵守依赖倒置原则,依赖倒转原则的中心思想就是面向接口编程
遵守依赖倒置原则代码:
///接收的消息
public interface Iinversion {
void run();
}
//QQ发送消息
public class QQNews implements Iinversion {
@Override
public void run() {
Log.i("Inversion", "我是 QQ 发送的消息");
}
}
//微信发送消息
public class WeChatNews implements Iinversion{
@Override
public void run() {
Log.i("Inversion","我是 微信 发送的消息");
}
}
代码使用:
InversionBean inversionBean = new InversionBean();
inversionBean.run(new QQNews());
inversionBean.run(new WeChatNews());
优点:
- 客户端(InversionBean)只与Iinversion(接口)之间交互,耦合性降低了,而且准守了依赖倒置中面向接口编程原则
- 不会像上面一样代码固定,也不需要判断任何条件,我传入QQ就接收QQ的消息,传入微信就接收微信的消息.相对于细节得多变性,抽象的东西要稳定的多,细节就是具体实现类
依赖倒置原则三种方法:
方式一:
通过传递接口(Iinversion)的实现类(QQNews)完成接口的传递
public interface Iinversion {
///接收的消息
void run();
}
public class QQNews implements Iinversion {
@Override
public void run() {
Log.i("Inversion", "我是 QQ 发送的消息");
}
}
Information information = new Information();
information.showInfo(new QQNews());
方式二:
通过有参构造方法,完成接口的传递
public interface Iinversion {
///接收的消息
void run();
}
public class Information {
Iinversion mIinversion;
public Information(Iinversion iinversion) {
mIinversion = iinversion;
}
public void showInfo(){
mIinversion.run();
}
}
//使用代码
Information information = new Information(new QQNews());
information.showInfo();
方式三:
通过set方法完成接口传递:
public interface Iinversion {
///接收的消息
void run();
}
//传递消息
public class QQNews implements Iinversion {
@Override
public void run() {
Log.i("Inversion", "我是 QQ 发送的消息");
}
}
public class Information {
private Iinversion mIinversion;
public void showInfo(){
mIinversion.run();
}
public void setIinversion(Iinversion iinversion) {
mIinversion =iinversion;
}
}
//使用代码:
Information information = new Information();
information.setIinversion(new QQNews());
information.showInfo();
里氏替换原则
基本介绍:
- 里氏替换原则是1988年麻省理工学院一位姓里的女性提出
里氏替换原则定义:
- 在继承时,遵守里氏替换原则,在子类中尽量不要去重写父类的方法
- 所有引用基类的地方必须能透明地使用其子类的对象
- 里氏替换原则告诉我们,继承实际上让两个类的耦合性增强,在适当的情况下,可以通过聚合,组合,依赖来解决问题
- 程序中的父类可以被子类替换
未遵守里氏替换原则代码:
public class ReplaceA {
public int show(int a, int b){
return a+b;
}
}
public class ReplaceB extends ReplaceA{
@Override
public int show(int a, int b){
return a-b;
}
}
//使用代码:
//里氏替换原则
ReplaceA replaceA = new ReplaceA();
ReplaceB replaceB = new ReplaceB();
Log.i("LiReplace","2 + 3 = "+replaceA.show(2,3)+"");
Log.i("LiReplace","2 + 3 = "+replaceB.show(2,3)+"");
可以看出:
- 在A类中输出的是 a + b 的和
- 在B类中重写了A类的show()方法,输出的是a-b
问题:
- 因为B类继承了A类,所以A类中的方法B类都可以使用,那么就导致了B类耦合性非常高
- 而且如果说A类新增加一些方法,B类用不到,也会导致耦合性提高,如果说B类用不到,还能调用的话,是不是提高了B类的入侵性
- 在这段代码中,我replaceB的本意是调用父类的show()方法求和,可是我忘记我重写了父类的show()方法求成差了!
假设一:
现在我现在忘记B类重写了A类的方法,我使用B类中的show()我想要的结果是求和,但是呢,B类重写了A类的方法,给我算成求差了,可能大家看看代码就能找出问题,那我在举一个例子.
假设二:现在有BCD三个类,都继承自A类
如果说我现在更改需求,我要C类求乘法,D类求除法,那又该怎么写呢?一个一个判断吗?而且这样写耦合性太高了,现在A,B,C,D这四个类感觉已经有点混乱了,这才是一个方法,如果有百八十个那不是直接凉凉了o(╥﹏╥)o
在来看看遵守里氏替换原则的写法:
遵守里氏替换原则的写法:
解决思路:
让A类和B类共同继承一个更通俗的父类(BaseReplace)
public class BaseReplace {
}
public class ReplaceA extends BaseReplace{
public int show(int a, int b){
return a+b;
}
}
public class ReplaceB extends BaseReplace{
public int show(int a, int b){
return a-b;
}
}
UML图(2.1)
:
分析:
- A类和B类完全没有关系,完全是两个单独的模块,
- 耦合性完全没有
如果在B类中使用A类的方法:
通过组合/聚合的方式:
public class ReplaceB extends BaseReplace{
ReplaceA replaceA = new ReplaceA();
public int show(int a, int b){
return a-b;
}
public void useAshow(int a,int b ){
replaceA.show(a,b);
}
public class ReplaceA extends BaseReplace{
public int show(int a, int b){
return a+b;
}
}
}
//使用代码
ReplaceB replaceB = new ReplaceB();
replaceB.useAshow(2,3)
可以看到在B类中使用组合的方法 ,依然可以使用到A类的方法
这就是里氏替换原则
猜你喜欢:
原创不易,记得点个赞哦~