一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
什么是设计模式?
设计模式是对软件设计中普遍存在的各种问题提出的解决方案,这个术语是由埃里希.伽马等人在1994年在书中提出的
为什么要使用设计模式
设计模式是为了让程序具有更好的代码重用性,可扩展性和可靠性等等。如果放在实际的工作中来说,当一个项目开发完后,如果客户提出了新的需求怎么办,如果需要负责维护公司的一个老项目怎么办,设计模式能在工作中灵活运用解决实际问题,优化程序结构。
设计模式的七大原则
单一职责原则
单一职责原则规定一个类应该只有一个发生变化的原因,即一个类应该只负责一项职责。如类A负责两个职责:职责1和职责2,当职责1需要变更需要改变类A时,可能会造成职责2执行错误,所以需要将类的粒度分解为A1和A2。
Vehicle类违反了单一职责原则
public class Vehicle {
public void run(String vehicle){
System.out.println(vehicle + "在公路上运行");
}
}
public class SingleResponsibility {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.run("汽车");
vehicle.run("飞机");
}
}
接口隔离原则
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。通俗来讲就是各个类建立自己的专用接口,而不是建立万能接口。
下面这个接口就违反了接口隔离原则,不是所有的动物都会飞,也不是所有的动物都会游泳
public interface Animal {
void eat();
void fly();
void swim();
}
依赖倒置原则
高层模块不应该依赖低层模块,二者都应该依赖其抽象,以抽象为基础搭建的架构比以细节为基础的架构要稳定的多,抽象的指的是接口或抽象类,细节即具体的实现类,使用接口或抽象类的目的是指定好规范,而不涉及具体的操作,将展现细节的任务交给实现类去完成。
下面用一个案例来说明,假如Study类的业务扩展,学习Python,按照逻辑应该在类中新增一个方法,高层也要追加调用,如此系统可能会出现不稳定的情况
public class Study {
public void studyJava(){
System.out.println("学习Java");
}
}
public class Responsibility {
public static void main(String[] args) {
Study s = new Study();
s.studyJava();
}
}
改进方法
public interface IStudy {
public void study();
}
public class JavaStudy implements IStudy{
@Override
public void study(){
System.out.println("学习Java");
}
}
public class PythonStudy implements IStudy{
@Override
public void study(){
System.out.println("学习Python");
}
}
public class Study {
public void study(IStudy s){
s.study();
}
}
public class Responsibility {
public static void main(String[] args) {
Study s = new Study();
s.study(new JavaStudy());
s.study(new PythonStudy())
}
}
里式替换原则
里式替换原则通俗的讲,就是子类可以扩展父类的功能,但不能改变父类原有的功能,也就是说在子类中尽量不要重写父类的方法。通过里式替换原则,我们得知继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合和依赖来处理。
放一个正确示例
public class Base {
//TODO
}
public class A extends Base{
public int fun1(int num1,int num2){
return num1-num2;
}
}
public class B extends Base{
//如果B需要使用A的方法,使用组合
private A a = new A();
public int fun1(int num1,int num2){
return num1+num2;
}
public int fun2(int num1,int num2){
return this.a.fun1(num1,num2);
}
}
开闭原则
一个软件实体如类,模块和函数等应该对扩展开放,对修改关闭,当软件出现变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化
放一个违反开闭原则的代码,假如我们要新增一种图形,需要在if-else语句中添加代码
drawShape(int type){
if(1 == type){
drawRectangle();
}else if(2 == type){
drawCircle();
}else if(3 == type){
drawTriangle();
}
}
迪米特法则
迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,迪米特法则还有个更简单的定义:只与直接的朋友通信。
直接的朋友:只要两个对象之间有耦合关系,那么我们就说两个对象之间是朋友关系,耦合的方式有很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。
现在需要实现人洗衣服的功能,需要两个类,一个表示人的类,一个表示洗衣机的类
代表洗衣机的类
public class WashingMachine {
public void receiveClothes(){
System.out.println("接收衣服");
}
public void wash(){
System.out.println("洗衣服");
}
public void dry(){
System.out.println("烘干衣服");
}
}
代表人的类
public class Person {
public void washClothes(WashingMachine washingMachine){
washingMachine.receiveClothes();
washingMachine.wash();
washingMachine.dry();
}
}
通过以上两个类就可以实现洗衣服的功能,但这种实现不符合最少知道原则,相对于Person类来说,我们是要实现洗衣服的功能,具体洗衣机如何洗,我们是不需要了解的,但上面的Person类的washClothes方法一次调用了洗衣机的三个方法,我们应该隐藏实现细节,只对外暴露一个方法。
合成复用原则
原则是尽量使用合成/聚合的方式,而不是使用继承