漫谈Java设计模式的六大原则

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情

简介

面向对象OOP的开发模式中,不论你是做后台还是前端开发,都离不开设计模式的制约。
不论什么框架和架构,都是离不开设计模式的约束。
OOP设计模式有六大原则,现在就来谈谈这六大原则,这些原则的优点,以及平时编码过程中如何按照这六大原则来进行设计的。

单一职责原则(Single Responsibility Principle)

There should never be more than one reason for a class to change.
改变一个类的原因不能超过一个。

对象:类

比如Car这个类,它有move这个功能

public class Car {

	private void move() {
		System.out.println("move");
	}
}

但是车辆也有载人load功能,那把load这方法也加到Car里面吧。

public class Car {

	private void move() {
		System.out.println("car move");
	}
	private void load() {
		System.out.println("car load");
	}
}

这样一来,Car有两个功能,一个是move,一个是load。
那么问题来了,如果需要修改move的时候,Car这个类就会变动,修改load的时候,Car这个类也会变动。
那Car这个类是否可以拆分成两个类呢?答案是是的。

还有Car如果依赖了其它类,比如:

public class Car {
	private Driver driver;
	private void init() {
		driver = new Driver();
	}
	private void move() {
		System.out.println("move");
	}
}

比如给这辆车配备司机,开始对司机进行初始化。但是Driver这个类的初始化,本身不应该在Car这个类里面进行。也就是说,Car这个类没有职责去初始化依赖的Driver类(可以用工厂模式等去实现)。
所以像Dagger2这样的框架解决的就是这类单一职责问题。

里氏替换原则(Liskov Substitution Principle)

Functions that use use pointers or references to base classes must be able to use objects of derived classes without knowing it.
对象:子类和父类
简而言之,里氏替换原则说明的是:子类可以对父类进行扩展,但是不能改变父类现有的功能。
具体就是:
1、子类继承父类后,可以扩展父类功能;
2、子类可以实现父类抽象方法,但是不能覆盖父类已实现的方法;
还是拿Car这个类来说,现在有Benz子类继承Car这个类:

public class Benz extends Car {
	private void move() {
		System.out.println("benz move");
	}
}

如果我们进行如下调用:

public class Client{
    public static void main(String[] args) {
    	Car car = new Car();
    	car.move();
        Car car = new Benz();
        car.move();
    }
}

输出的结果是:

car move
move benz

为什么说这样的输出是不符合规则的呢?
因为move()这个功能已经由父类Car实现了,子类只需要继承就可以自动获得这个功能,但是由于某些功能、需求的升级或变更,开发人员在子类对父类方法进行了重写,也就是覆盖了父类方法。这样就导致在子类中调用父类的方法实际上已经被改动了。这种情况会造成不可预估的错误,不建议这么做。
解决方案:
之类增加自己特有的方法,不用覆盖父类方法的实现,
比如:

public class Benz extends Car {
	private void newMove() {
		System.out.println("benz move");
	}
}

依赖倒置原则(Dependence Inversion Principle)

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions
对象:模块之间
底层模块:原子逻辑,不可分割的业务逻辑;
高层模块:原子逻辑的封装;
abstractons:接口或抽象类,不能被直接实例化;
details:接口或抽象类的实例化;
说白了就是“面向接口编程”。
举例来说,Benz这个车由司机来开车,这里我们把司机叫做Zhangsan,

public class Benz  {
	public void move(Zhangsan zhangsan) {
		System.out.println("driver is zhangsan");
	}
}
public class Client{
    public static void main(String[] args) {
        Benz benz = new Benz();
        Zhangsan zhangsan = new Zhangsan();
        benz.move(zhangsan);
    }
}

我们可以看到Benz车子配备了一个叫做Zhangsan的司机,而且只能由叫做张三的司机来驾驶。
万一哪天Zhangsan请假了怎么办,这辆Benz岂不是就开不了了么?
我们知道,只要拥有C驾照以上的驾驶员均可开Benz车,那么Benz的drive方法中就不能限制只对Zhangsan这个驾驶员有效。
我们定义一个接口,这个接口有个granted方法,任何实现了这个方法的驾驶员都有权限开Bens。

public interface ILicense  {
	void granted();
}
public class Lisi implements ILicense{
	public boolean granted() {
		System.out.println("driver with license");
		return true;
	}
}

这辆Benz不再只由Zhangsan驾驶:

public class Benz  {
	public void move(ILicense license) {
		if(license.granted()) {
			...
		}
	}
}

Lisi也能开了:

public class Client{
    public static void main(String[] args) {
        Benz benz = new Benz();
        ILicense license = new Lisi();
        benz.move(license);
    }
}

接口隔离原则(Interface Segregation Principle)

The dependency of one class to another one should depend on the smallest possible interface
对象:类和接口
意思就是类实现的接口应该是这个类需要的。
换句话说,我们定义接口,应当做到尽量根据业务逻辑细化。
比如车辆有move、load这两个方法:

public interface IMove {
	void move();
	void load();
}

IMove接口表示能动的物体,如果是飞机呢,飞机能飞,于是IMove接口增加fly方法:

public interface IMove {
	void move();
	void fly();
}

那这样的话,Benz implements IMove接口后,还需要实现fly方法,虽然这个方法里面也可不做处理,但是这样会增大代码冗余度,提升阅读难度。
所以fly这个方法应该放到另外的给飞机用的接口中。

迪米特法则(Law of Demeter)

Only talk to you immediate friends.
这个法则也好理解,就是说一个类尽可能少的暴露方法,能用private的就用private,尽可能少的让外界调用到你的方法。
对象:类和类
一句话:高内聚,低耦合体现。
private方法主要实现类本身的逻辑功能;
protected方法主要暴露给子类用;
public方法主要是给其它类提供的接口;

开闭原则(Open Closed Principle)

Software entities like classes,modules and functions should be open for extension but closed for modifications
对象:类、模块、函数
一句话:对扩展开放,对修改关闭
这种原则在工厂方法设计模式中体现的很明显。
还是拿上面的Benz来说,

public class Benz implements IMove{
	public void move(ILicense license) {
	}
}

如果现在要实现一辆赛车版的Benz,它的move是有赛车版的功能,
现在有两种方法实现:
1、IMove里面增加一个raceMove()接口处理赛车驾驶事宜;
2、在现有drvie方法里面处理根据传入的参数判断是赛车版的Benz然后进行处理;
但是这样的处理涉及到接口的更改,还有就是对源代码的改动,这都不是很好的方法,搞不好会对原有功能造成损害。
通过开闭原则的解决方案就是,新建一个RaceBenz类,继承Benz类,并且在RaceBenz类里面新增一个raceMove方法即可。

public class RaceBenz extends Benz{
	public void raceMove(ILicense license) {
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值