前言:很多优秀的开源框架(例:spring、mybatis、dubbo)都使用了大量设计模式来开发,反过来说,如果一个程序都是参照设计模式来开发,那么这个程序想不优秀也难
软件设计六大原则:
一、单一职责原则 :一个类只负责一项职责。
如图,假设我有两个Controller,OrderController:专门用来处理订单相关的请求,UserController:用来处理用户信息相关的请求,这时候它们遵循着单一职责原则,那么反过来说,如果我把OrderController和UserController写在同一个类,程序也能跑,但这种设计不仅加大了维护难度,且违背了单一职责原则。
二、开闭原则:对扩展开放,对修改关闭。
开闭原则比较宏观,从架构上来说,假设我们要新增一个产品功能,有两种实现方式(仅供理解,就不以模块化或服务的形式演练)
①新增一个ProducController
②在已有Controller写新功能
第二种方式违背了开闭原则中的对修改关闭,它涉及到了对我们原有的UserController的修改,其实分析一下还能发现它同时违背了单一职责原则
三、依赖倒置原则:面向接口编程。
如上:接口以及对应的实现类(例:UserService-UserServiceImpl),接口就是将行为或者我们需要的业务功能剥离出来的一种形式,我们一般认为:接口的变动性要比实现类的变动要小很多,所以我们一般也会用接口的形式来持有他对应的实例,如下:
面向接口编程由于是剥离出来的一种抽象行为,所以可以多实现,例如说话talk,狗Dog实现:汪,猫Cat实现:喵,也是多态的一种体现
四、里式替换原则:子类可以扩展父类的功能,但尽量不要改变父类原有的功能。
我们知道java里面有继承,子类继承了父类,那么子类就拥有了父类的功能,此时我们可以拥有两个动作:1、沿用父类的功能,2、重写覆盖父类的功能,里式替换原则就是尽量不要重写父类原有的功能,从如上代码得:对于调用者来说,同样的方法名、同样的参数,他们的行为却是不一样,这样会增加软件体系上理解的复杂度,但换句话讲,我们可以扩展一个getVipDetail方法。
五、接口隔离原则:设计接口功能尽量细粒度化,最小功能单元。
VipUserServiceImpl继承自UserServiceImpl,UserServiceImpl实现UserService
但我们想要调用VipUserServiceImpl的getVipDetail时,无法从UserService中调用
可能有人会在UserService接口中,写getVipDetail,例如
但是这样的话,会导致UserServiceImpl也要实现这个方法,可能我们并不会使用该方法,所以正确的做法应该是新建一个接口让VipUserServiceImpl实现该接口来调用getVipDetail方法
也就是我们所说的细粒度化,最小功能单元
六、迪米特法则:降低耦合(又称最少知道原则,局部变量中尽量不要引入新的类):
可以理解为减少我这个class类通过编译所依赖的类,从而降低耦合
对于UserController来说,它的编译需要依赖VipUserService、MyRequestWrapper、HttpServletResponse三个类,代码才能运行起来,但我们平时编码的时候,总是会在局部变量中new对象实例,从而导致UserController从外部(即成员变量、方法返回值、形参)来看,并没有变化
如上OrderService以及OrderServiceImpl,我们可以写成
这样的形式,从而避免额外引入OrderServiceImpl,且对于整个类结构来说,也是清晰可见的