single responsibility principle 单一职责
ConfigReader 类只负责读取配置文件,符合单一职责原则
举例:
在这个例子中,User 类既负责用户的增删改查,又负责用户的登录验证。这违反了单一职责原则。
正确的:
我们将用户的增删改查和登录验证分成了两个类,分别是 UserManager 和 UserAuth。这样符合单一职责原则。
open closed principle 开闭原则(开放封闭原则)
对扩展开放 扩展是指对业务的抽象 和封装的变化
对修改关闭 更改业务逻辑
举例:
假设我们的电商系统支持多种支付方式,如支付宝、微信、银行卡等。如果我们使用开闭原则来设计支付模块,那么我们可以定义一个
抽象的支付类,然后让各种具体的支付方式继承这个类,并实现其抽象方法。这样,当我们需要增加新的支付方式时,只需要新增一个
子类,并不需要修改原有的代码。
liskov substitution principle 里氏替换原则
对于继承关系的父子类来说,子类可以对父类的功能进行扩展,但不能改变父类中已经定义的功能。
把这句话引申出来可以得出以下三点的内容:
子类可以添加自己独有的方法(废话,不然定义子类干什么)
子类重载父类方法时,方法的入参要比父类的入参更为宽松(接收更抽象的类),但返回值要比父类更严格(返回更具体的
类)
子类必须实现父类抽象方法,但不能覆盖父类中非抽象的正常业务逻辑
public abstract class Teacher {
public void saySomthing(){
System.out.println(“我们的口号是” + “同学们好” );
}
}
// 正常老师
public class NormalTeacher extends Teacher {
public void saySomthing(){
System.out.println("我们的口号是" + “同学们好” );
}
}
// 不正常老师
public class FengSaoTeacher extends Teacher {
@Override
public void saySomthing(){
System.out.println("Hello慕课网的各位同学们大家好" );
}
}
以上结构在实现功能上没有问题,但是违反了里式替换原则里的一点 - 子类必须实现父类抽象方
法,但不能覆盖父类中非抽象的正常业务逻辑。更加合理的结构是这样的:
public abstract class Teacher {
public void saySomthing(){
System.out.println("我们的口号是" + say() );
}
public abstract String say();
}
// 正常老师
public class NormalTeacher extends Teacher {
@Override
public abstract String say() {
return "同学们好";
}
}
// 不正常老师
public class FengSaoTeacher extends Teacher {
@Override
public String say() {
return "慕课网的同学们大家好";
}
}
law of demeter 迪米特法则
是指一个对象应该尽可能的保持高冷的姿态,少和其他对象勾搭, 尽量对自己以外的对象保持最小了解。因此,迪米特原则又叫做最少知道原则(Least
Knowledge Principle)。一句话总结就是 - 不要和陌生人说话。
举例:
有一波未来的架构师们(对没错就是你们)来慕课网上学习,学习何等枯燥,得找个有意思的老师 跟着学才学的下去,同学们就跟慕课的小姐姐打听哪个老师
学风最风骚。这个过程可以用以下的三 个类来表示:public class IMoocGirls(小姐姐) { public void findFengSaoTeacher(List list) { Teacher teacher =
list.stream().sorted(xxx).findFir System.out.println(“最风骚的老师配最风骚的课程 ” + } }
public class Architect { public void chatWithImoocGirl(IMoocGirl girl) { List teacherList = Lists.newArrayList(); // xxxx 读取所有老师列表 girl.
findFengSaoTeacher(teacherList); } }
这样的话架构师跟老师就发生关系了
架构师通过勾搭小姐姐,打听到最风骚的讲师是谁。从这个例子中可以看出,Architect架构师只想 获取结果就行了,他并不需要和讲师直接产生关系,在这个
例子中,小姐姐是Architect的朋友,而 Teacher是陌生人。 应用迪米特法则,我们应该如何修正架构呢?这样来:
public class IMoocGirls { public void findFengSaoTeacher() { List teacherList = Lists.newArrayList(); // xxxx 读取所有老师列表 Teacher teacher =
teacherList().sorted(xxx).findFir System.out.println(“最风骚的老师配最风骚的课程 ” + } } public class Architect { public void chatWithImoocGirl(IMoocGirl girl) {
girl. findFengSaoTeacher(); } }
从上面的例子中可以看出,Architect只和IMoocGirl打交道,而和Teacher已经完全没有关联了,避 免了类与类之间的耦合
interface segregation principle 接口隔离原则
接口隔离原则代码示例 ( 反面示例 )
package interfacesegregation;
/**
- 动物行为接口
- 该接口中声明的方法过多 , 方法分属于不同的类型
- 该接口可以进一步细化
*/
public interface IAnimationAction {
void eat();
void fly();
void walk();
void swim();
}
package interfacesegregation;
/**
- 定义 Dog 类 , 实现 IAnimationAction 接口
- 需要实现该接口下的所有方法
- 很明显狗不能飞 , fly 方法只能空着 , 没有实际意义
*/
public class Dog implements IAnimationAction {
@Override
public void eat() {
}
@Override
public void fly() {
}
@Override
public void walk() {
}
@Override
public void swim() {
}
}
package interfacesegregation;
/**
- 定义 Bird 类 , 实现 IAnimationAction 接口
- 需要实现该接口下的所有方法
- 很明显鸟不能游泳 , swim 方法只能空着 , 没有实际意义
*/
public class Bird implements IAnimationAction {
@Override
public void eat() {
}
@Override
public void fly() {
}
@Override
public void walk() {
}
@Override
public void swim() {
}
}
接口隔离原则代码示例 ( 推荐用法 )
package interfacesegregation;
public interface IEatAnimalAction {
void eat();
}
package interfacesegregation;
public interface IFlyAnimalAction {
void fly();
}
package interfacesegregation;
public interface ISwimAnimalAction {
void swim();
}
package interfacesegregation;
public interface IWalkAnimalAction {
void walk();
}
package interfacesegregation;
/**
- 狗可以 吃 / 走路 / 游泳
- 这里直接继承 3 个对应的接口
- 并实现接口中的方法
- 细粒度接口可以组装 , 粗粒度接口无法拆分
*/
public class Dog implements IEatAnimalAction, IWalkAnimalAction, ISwimAnimalAction {
@Override
public void eat() {
}
@Override
public void swim() {
}
@Override
public void walk() {
}
}
dependence inversion principle 依赖倒置原则
依赖倒置原则有两个核心甩锅思想:上层模块不依赖底层模块的实现,而应该对底层模块做抽象。
抽象不应该依赖于底层细节,而细节应该依赖于抽象
架构分层后,上层只做接口定义,不做实现,实现有第三方按照接口定义的实现。这样竞争就会出现一代比一代好的产品。比如主板,上
层之定义接口,怎么实现由第三方实现,这样第三方竞争压力下产品一代比一代好
public class Architect {
IGirl girl;
public void play() {
girl.talk();
}
}
public interface IGirl {
void talk();
}
这里我定义了一个架构师类,作为上层模块,架构师要相亲,我们假设这是一个蚂蚁金服的架构
师,借着蚂蚁上市身价已经达到了一个小目标,各种各样的女嘉宾都来求包养。但是架构师并不迁
就底层对象,他定义了一个抽象层叫IGirl
public class YuJie implements IGirl {
public void talk() {
System.out.println(“大王,鞭挞我吧!”);
}
}
public class LuoLi implements IGirl {
public void talk() {
System.out.println(“小哥哥,打架吗?”);
}
}
来了两位女嘉宾,分别是御姐和萝莉,她们都依赖于抽象接口实现各自特殊的对话,对于架构师来
说并不需要关注底层的女嘉宾是什么来历,统统来者不拒全盘接收,底层的改变并不会影响到上层
应用。