Design Principles Link to heading
一、单一职责原则 Link to heading
一个类应该只有一个发生变化的原因。
模拟场景 Link to heading
一个视频网站有对用户分类的场景
访客用户只能观看480P视频,且有广告 普通会员只能观看720P视频,且有广告 VIP用户可以看1080P视频,且无广告
违背原则 Link to heading
public class VideoUserSerice{
public void serveGrade(String usrType){
if(usrType == "VIP"){
// 视频1080P,无广告
}else if(usrType == "普通会员"){
// 视频720P,有广告
}else if(usrType == "访客用户"){
// 视频480P,有广告
}
}
}
改进方案 Link to heading
public interface IVideoUserService{`
// 清晰度 1080P、720P、480P
void definition();
// 广告播放方式,有广告、无广告
void advertisement();
}
二、开闭原则 Link to heading
对象、类、模块和函数对扩展应该是开放的,但是对于修改是封闭的。
模拟场景 Link to heading
计算三种形状的面积,长方形、三角形、圆形。 但是后续由于pai取值的精度对于某些场景是不足的,需要扩展。
public class CalculationArea{
private final static double pai = 3.14D;
public double retangle(double x,double y){
return x * y;
}
public double triangle(double x,double y,double z){
double p = (x+y+z)/2;
return Math.sqrt(p*(p-x)(p-y)(p-z));
}
public double circular(double r){
return pai * r * r;
}
}
违背原则 Link to heading
直接修改pai值
private final static double pai = 3.141592653D;
public double circular(double r){
return pai * r * r;
}
改进方案 Link to heading
public class CalculationAreExt extends CalculationArea{
private final static double pai = 3.141592653D;
@override
public double circular(double r){
return pai * r * r;
}
}
三、里氏替换原则 Link to heading
如果S是T的子类型,那么所有T类型的对象都可以在不破坏程序的情况下被S类型的对象替换。
简单来说,子类可以扩展夫类的功能,但不能改变父类原有的功能。 当子类继承父类时,除添加新的方法且完成新增功能外,尽量不要重写父类方法。
主要包含四点含义:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(方法的输入)要比父类更宽松。
- 当子类的方法实现父类的方法(重写、重载、实现)时,方法的后置条件(即方法的输出或返回值)要比父类的方法更加严格或与父类方法相等。
模拟场景 Link to heading
实现储蓄卡和信用卡
违背原则 Link to heading
public class CashCard{
// 取钱
public String withdrawal();
// 存钱
public String recharge();
// 打印流水
public String tradeFlow();
}
public class CreditCard extends CashCard{
@override
public String withdrawal();
@override
public String recharge();
}
信用卡直接继承了储蓄卡的类并重写了有关取钱和存钱的内容,由于打印流水实现相同则没有重写。
改进方案 Link to heading
public abstract class BankCard{
// 流入钱
public String positive();
// 流出钱
public String negative();
// 打印流水
public String tradeFlow();
}
public class CashCard extends BankCard{
public String withdrawal(){
return super.negative();
}
public String recharge(){
return super.positive();
}
}
public class CreditCard extends BankCard{
public String loan(){
return super.negative();
}
public String repayment(){
return super.positive();
}
}
四、迪米特法则 Link to heading
一个对象类对于其他对象类来说,知道得越少越好。
模拟场景 Link to heading
模拟学生、老师、校长的关系。
老师需要知道具体学生的成绩,而校长只关心某个班级的总成绩。
违背原则 Link to heading
public class Student{
private double grade;
}
public class Teacher{
private List<Student> studentList;
public List<Student> getStudentList(){
return studentList;
}
}
public class Principal{
private Teacher teacher;
public double classTotalScore(){
teacher.getStudentList();
// do more
}
}
改进代码 Link to heading
public class Student{
private double grade;
}
public class Teacher{
private List<Student> studentList;
public double classTotalScore(){
// do more
}
}
public class Principal{
private Teacher teacher;
public double classTotalScore(){
teacher.classTotalScore();
}
}
五、接口隔离原则 Link to heading
客户端不应该被破依赖于它不是用的方法。 一个类对另一个类的依赖应该是建立在最小的接口上的。
要求尽量将臃肿庞大的接口拆分成更小的和更具体的接口。
模拟场景 Link to heading
王者荣耀有不同的技能特性,每个英雄的技能都属于其中
违背原则 Link to heading
public interface ISkill{
// 射箭
void doArchery();
// 隐身
void doInvisible();
// 沉默
void doSilent();
// 眩晕
void doVertigo();
}
public class HeroHouYi implements ISkill{
@Override
public void doArchery(){
// do archery
}
@Override
public void doVertigo(){
// do vertigo
}
@Override
public void doSilent(){
// do nothing
}
@Override
public void doInvisible(){
// do nothing
}
}
改进方案 Link to heading
public interface ISkillArchery{
void doArchery();
}
public interface ISkillInvisible{
void doInvisible();
}
public interface ISkillSilent{
void doSilent();
}
public interface ISkillVertigo{
void doVertigo();
}
public class HeroHouYi implement ISkillArchery,ISkillVertigo{
@Override
public void doArchery(){
// do archery
}
@Override
public void doVertigo(){
// do vertigo
}
}
六、依赖倒置原则 Link to heading
高层模块不应该依赖于底层模块,二者都应该依赖于抽象。 抽象不应该依赖于细节,细节应该依赖于抽象。
模拟场景 Link to heading
权重抽奖、随机抽奖
违背原则 Link to heading
public class BetUser{
private String userName;
private int userWeight;
}
public class DrawControl{
public List<BetUser> doDrawRandom(List<BetUser> list,int count){
// do something
}
public List<BetUser> doDrawWeight(List<BetUser> list,int count){
// do something
}
}
当业务需要扩展到的时候,只能在DrawControl中新增接口,且代码会暴增,难以维护。
改进方案 Link to heading
获取抽奖用户接口
public interface IDraw{
// 获取抽奖用户接口
List<BetUser> prize(List<BetUser> list, int count);
}
抽奖具体实现类
// 随机抽奖
public class DrawRandom implements IDraw{
@Override
public List<BetUser> prize(List<BetUser> list, int count){
// do something
}
}
// 权重抽奖
public class DrawWeight implements IDraw{
@Override
public List<BetUser> prize(List<BetUser> list, int count){
// do something
}
}
抽奖服务
// 创建抽奖服务
public class DrawControl{
private IDraw draw;
public List<BetUser> doDraw(IDraw draw, List<BetUser> betUserList, int count){
return draw.prize(betUserList, count);
}
}