java 7大设计原则
一、设计模式七大原则
设计模式的目的
- 代码重用性 (即:相同功能的代码,不用多次编写)
- 可读性 (即:编程规范性, 便于其他程序员的阅读和理解)
- 可扩展性 (即:当需要增加新的功能时,非常的方便,称为可维护)
- 可靠性 (即:当我们增加新的功能后,对原来的功能没有影响)
- 高内聚低耦合:使程序呈现高内聚,低耦合的特性
有点官方,反正就是牛逼!
七大原则:
1.单一职责原则
每个类只负责一个职责
2.接口隔离原则
将接口细分为多个接口,保证实现接口的类不重写自己不需要的方法
3.依赖倒转原则
用 抽象类 或者 接口,然后由具体的类去继承、实现它,重写其方法,实现依赖倒转 类似 多态
注意:变量的声明类型尽量是抽象类或接口!!!
4.里氏替换原则
子类中尽量不要重写父类的方法
5.开闭原则
一个软件实体 如类、模块、函数 应该对 扩展新功能 开放,对修改旧功能关闭。
接口或者抽象类 内置 方法,让其实现类 重写方法满足其需要
6.迪米特原则
简单来说: 一个类中 只与 [ 直接的朋友 ] 产生依赖 如果是 陌生类,就违背 迪米特法则
什么是直接朋友:
1、成员变量: A类中的 全局变量 有 private B b; B是A的直接朋友
2、方法参数:A类中 M1方法的 请求参数 为 B b -> m1(B b){} A与B是直接朋友
3、方法返回值的类: A类中的方法 M2 的返回值为B -> public B M2(){} A与B是直接朋友
7.合成复用原则
类和类之间 尽量使用 合成 和聚合的方式 而不是使用 继承
1.1、单一职责原则
介绍:
一个类应该只负责一项职责。如类 A 负责两个不同职责:职责 1,职责 2。当职责 1 需求变更 而改变 A 时,可能造成职责 2 执行错误
以 交通工具为 案例
不使用 单一职责原则 Demo:
public class A_SingleResponsibilityPrinciple {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.run("汽车");vehicle.run("飞机");vehicle.run("鲨鱼");}static class Vehicle{public void run(String vehicle){System.out.println(vehicle + "在公路上跑");}}
}
理解:Vehicle 类的 run 方法 职责是 在 公路上跑 的职责,并不负责在 天上飞、水里游的职责。
使用 单一职责原则 Demo:
public class C_SingleResponsibilityPrinciple {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.run("汽车");vehicle.runAir("飞机");vehicle.runWater("鲨鱼");}static class Vehicle{public void run(String vehicle){System.out.println(vehicle + "在公路上跑");}public void runAir(String vehicle){System.out.println(vehicle + "在天上跑");}public void runWater(String vehicle){System.out.println(vehicle + "在水里跑");}}}
理解:Vehicle 类的
run方法 只负责在 公路上跑 ;
runAir 负责在天上跑
runWater负责在水里跑
每个方法都只对应 一个职责,是为 单一职责原则。
单一职责原则注意事项和细节
- 降低类的复杂度,一个类只负责一项职责。
- 提高类的可读性,可维护性
- 降低变更引起的风险
- 通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以
在代码级违反单一职责原则;只有类中 方法数量足够少,可以在方法级别保持单一职责原则
1.2、接口隔离原则
接口隔离原则:一个类不需要实现他不需要的接口。即:一个类对另一个类的依赖应该建立在最小的接口上。
理解:
我们一个类A 通过 接口去依赖另一个类B 我们希望这个接口是最小的(不包含A不需要的方法)
就是 原本接口 I1有很多方法,A只想用其中 几个 就把其中几个单独拿出来做个接口I2 ,B去继承这来接口
不使用接口隔离原则的Demo
/* 接口隔离原则:一个类不需要实现他不需要的接口。即:一个类对另一个类的依赖应该建立在最小的接口上* 翻译一下就是:我们一个类A 通过 接口去依赖另一个类B 我门希望这个接口是最小的(不包含A不需要的方法)* 就是 原本接口I1 有很多方法,A只想用其中 几个 就把其中几个单独拿出来做个接口I22 ,B去继承这来接口 不使用 接口隔离原则*/
public class A_InterfaceLsolationPrinciple {public static void main(String[] args) {// A 通过 接口 去依赖B类 A只用 1 2 3 但 B 实现了接口的所有方法【12345】 不符合 接口的 隔离原则A a = new A();a.do1(new B());a.do2(new B());a.do3(new B());C c = new C();c.do1(new D());c.do4(new D());c.do5(new D());}// 接口interface Interface1 {void run1();void run2();void run3();void run4();void run5();}// 接口interface Interface3 extends Interface1{void run6();}static class B implements Interface1 {@Overridepublic void run1() {System.out.println("B实现 run1");}@Overridepublic void run2() {System.out.println("B实现 run2");}@Overridepublic void run3() {System.out.println("B实现 run3");}@Overridepublic void run4() {System.out.println("B实现 run4");}@Overridepublic void run5() {System.out.println("B实现 run5");}}static class D implements Interface1{@Overridepublic void run1() {System.out.println("D实现 run1");}@Overridepublic void run2() {System.out.println("D实现 run2");}@Overridepublic void run3() {System.out.println("D实现 run3");}@Overridepublic void run4() {System.out.println("D实现 run4");}@Overridepublic void run5() {System.out.println("D实现 run5");}}/* A 通过接口 Interface1 依赖(使用)B类 ,但 只用 1 2 3 方法*/static class A{public void do1(Interface1 i){i.run1();}public void do2(Interface1 i){i.run2();}public void do3(Interface1 i){i.run3();}}/* C 通过接口 Interface1 依赖(使用)D类 ,但 只用 1 4 5 方法*/static class C{public void do1(Interface1 i){i.run1();}public void do4(Interface1 i){i.run4();}public void do5(Interface1 i){i.run5();}}}
代码解释:
一个接口 Interface1 有5个方法
// 接口interface Interface1 {void run1();void run2();void run3();void run4();void run5();}
B、D两个类实现 接口 Interface1 .并重写了 接口的五个方法
static class B implements Interface1 {@Overridepublic void run1() {System.out.println("B实现 run1");}@Overridepublic void run2() {System.out.println("B实现 run2");}@Overridepublic void run3() {System.out.println("B实现 run3");}@Overridepublic void run4() {System.out.println("B实现 run4");}@Overridepublic void run5() {System.out.println("B实现 run5");}}static class D implements Interface1{@Overridepublic void run1() {System.out.println("D实现 run1");}@Overridepublic void run2() {System.out.println("D实现 run2");}@Overridepublic void run3() {System.out.println("D实现 run3");}@Overridepublic void run4() {System.out.println("D实现 run4");}@Overridepublic void run5() {System.out.println("D实现 run5");}}
重点来了:
A类 通过接口 Interface1 依赖(使用)B类,但 只用 1 2 3 方法
A 通过 接口 去依赖B类 A只用 1 2 3 但 B 实现了接口的所有方法【12345】 不符合 接口的 隔离原则
C 通过接口 Interface1 依赖(使用)D类 ,但 只用 1 4 5 方法
C 通过 接口 去依赖D类 C只用 1 4 5 但 D 实现了接口的所有方法【12345】 不符合 接口的 隔离原则
static class A{public void do1(Interface1 i){i.run1();}public void do2(Interface1 i){i.run2();}public void do3(Interface1 i){i.run3();}}/* C 通过接口 Interface1 依赖(使用)D类 ,但 只用 1 4 5 方法*/static class C{public void do1(Interface1 i){i.run1();}public void do4(Interface1 i){i.run4();}public void do5(Interface1 i){i.run5();}}
main 方法
public static void main(String[] args) {// A 通过 接口 去依赖B类 A只用 1 2 3 但 B 实现了接口的所有方法【12345】 不符合 接口的 隔离原则A a = new A();a.do1(new B());a.do2(new B());a.do3(new B());C c = new C();c.do1(new D());c.do4(new D());c.do5(new D());}
改进 使用接口隔离原则
public class B_InterfaceLsolationPrinciple {public static void main(String[] args) {A a = new A();a.do1(new B());a.do2(new B());a.do3(new B());C c = new C();c.do1(new D());c.do4(new D());c.do5(new D());}// 接口interface Interface1 {void run1();}// 接口interface Interface2 {void run2();void run3();}// 接口interface Interface3 {void run4();void run5();}static class B implements Interface1 ,Interface2{Interface1 i1 =new B();@Overridepublic void run1() {System.out.println("B实现 run1");}@Overridepublic void run2() {System.out.println("B实现 run2");}@Overridepublic void run3() {System.out.println("B实现 run3");}}static class D implements Interface1,Interface3{@Overridepublic void run1() {System.out.println("D实现 run1");}@Overridepublic void run4() {System.out.println("D实现 run4");}@Overridepublic void run5() {System.out.println("D实现 run5");}}/* A 通过接口 Interface1 依赖(使用)B类 ,但 只用 1 2 3 方法*/static class A{public void do1(Interface1 i){i.run1();}public void do2(Interface2 i){i.run2();}public void do3(Interface2 i){i.run3();}}/* C 通过接口 Interface1 依赖(使用)D类 ,但 只用 1 4 5 方法*/static class C{public void do1(Interface1 i){i.run1();}public void do4(Interface3 i){i.run4();}public void do5(Interface3 i){i.run5();}}
}
核心代码解释
将 原本的 接口一拆分成三个接口,分别为123
因为A 类只用 1 2 3 方法 ;D 只用 1 4 5 方法
// 接口interface Interface1 {void run1();}// 接口interface Interface2 {void run2();void run3();}// 接口interface Interface3 {void run4();void run5();}
B 类实现 接口 1、2 并重写其方法 A 类只用 1 2 3 方法
D 类实现 接口 1、3并重写其方法 D 只用 1 4 5 方法
static class B implements Interface1 ,Interface2{Interface1 i1 =new B();@Overridepublic void run1() {System.out.println("B实现 run1");}@Overridepublic void run2() {System.out.println("B实现 run2");}@Overridepublic void run3() {System.out.println("B实现 run3");}}static class D implements Interface1,Interface3{@Overridepublic void run1() {System.out.println("D实现 run1");}@Overridepublic void run4() {System.out.println("D实现 run4");}@Overridepublic void run5() {System.out.println("D实现 run5");}}
通过拆分接口、实现接口 隔离原则
1.3、依赖倒置原则
说点 字都认识 但放在一起就不认识的吧
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 依赖倒转(倒置)的中心思想是面向接口编程
- 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架 构比以细节为基础的架构要稳定的多。在 java 中,抽象指的是接口或抽象类,细节就是具体的实现类
- 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完 成
应该 、大概、也许就是 用 抽象类 或者 接口,然后由具体的类去继承、实现它,重写其方法,实现依赖倒转 类似 多态
注意:变量的声明类型尽量是抽象类或接口!!!
Person 接收消息的功能
不用 依赖倒转原则
public class A_RelyOnTheInversionPrinciple {public static void main(String[] args) {new Person().receive(new Email());}static class Email{public String getInfo(){return "电子邮件信息:hello";}}/* 完成Person接收消息的功能*/static class Person{public void receive(Email email){System.out.println(email.getInfo());}}
}
理解:
1、简单比较容易想到
2、如果我们获取的对象是 微信、短信等,而不是 电子邮件,那么就要增加 新类 person 也要增加对应的接收方法
改进:
引入一个 抽象接口:IReceive,表示接收者, 这样Person类 与IReceive发生依赖
Email \\微信 等属于接收的范畴,可以实现 IReceive接口
这就是 依赖倒转原则 类似 多态
public class B_RelyOnTheInversionPrinciple {public static void main(String[] args) {new Person().receive(new Email());new Person().receive(new QQ());}// 收到消息的 接口interface IReceive{String getInfo();}// 邮件收到消息static class Email implements IReceive{@Overridepublic String getInfo() {return "电子邮件信息:hello";}}// QQ收到消息static class QQ implements IReceive{@Overridepublic String getInfo() {return "QQ信息:hello";}}/* 完成Person接收消息的功能* 依赖倒转原则 实现: 引入一个 抽象接口:IReceive,表示接收者, 这样Person类 与IReceive发生依赖* Email 、微信 等属于接收的范畴,可以实现 IReceive接口 类似 多态/static class Person{public void receive(IReceive receive){System.out.println(receive.getInfo());}}
}
代码解释:
上面说到:抽象不应该依赖细节,细节应该依赖抽象
所以 先定义个抽象(接口),然后让细节(接口的实现类)去展示具体细节
1、首先定义 一个获取消息的接口
// 收到消息的 接口interface IReceive{String getInfo();}
2、然后让 qq 、微信…去实现接口
// 邮件收到消息static class Email implements IReceive{@Overridepublic String getInfo() {return "电子邮件信息:hello";}}// QQ收到消息static class QQ implements IReceive{@Overridepublic String getInfo() {return "QQ信息:hello";}}
实现了 细节依赖抽象啦。
人获取消息的方法:
static class Person{public void receive(IReceive receive){System.out.println(receive.getInfo());}}
main:
public static void main(String[] args) {new Person().receive(new Email());new Person().receive(new QQ());}
1.3.1、依赖传递的方式
多说几句。。。。。。
依赖关系的传递三种方式
1、接口传递
2、构造方法传递
3、setter方法传递
1、接口传递
interface IOpenAndClose {void open(ITV tv);}interface ITV {void play();}static class hand implements ITV {@Overridepublic void play() {System.out.println("用手关");}}// 实现接口static class OpenAndClose implements IOpenAndClose {@Overridepublic void open(ITV tv) {tv.play();}}
解释:
OpenAndClose 方法 实现了 IOpenAndClose 接口 ,但是呢,IOpenAndClose 的方法使用了
ITV接口 所以 OpenAndClose 就 通过 IOpenAndClose (依赖)使用了 ITV 是为 : 接口传递
2、构造方法传递
public class D_DependOnTheTransfer {public static void main(String[] args) {new OpenAndClose(new hand()).open();}/* 方式 2、构造方法传递* <p>* 开关接口*/interface IOpenAndClose {void open();}interface ITV {void play();}static class hand implements ITV {@Overridepublic void play() {System.out.println("用手关");}}// 实现接口static class OpenAndClose implements IOpenAndClose {public ITV tv;public OpenAndClose(ITV tv){ // 构造器this.tv = tv;}@Overridepublic void open() {this.tv.play();}}
}
解释:
static class OpenAndClose implements IOpenAndClose {public ITV tv;public OpenAndClose(ITV tv){ // 构造器this.tv = tv;}@Overridepublic void open() {this.tv.play();}}
OpenAndClose 类的构造方法 参数为 ITV接口,so 通过 构造方法和 ITV产生了依赖
3、setter 方法传递
public class E_DependOnTheTransfer {public static void main(String[] args) {OpenAndClose openAndClose = new OpenAndClose();openAndClose.setTv(new hand());openAndClose.open();}/* 方式 3、setter方法传递* <p>* 开关接口*/interface IOpenAndClose {void open();void setTv(ITV tv);}interface ITV {void play();}static class hand implements ITV {@Overridepublic void play() {System.out.println("用手关");}}// 实现接口static class OpenAndClose implements IOpenAndClose {public ITV tv;@Overridepublic void open() {this.tv.play();}@Overridepublic void setTv(ITV tv) {this.tv = tv;}}
}
解释:
static class OpenAndClose implements IOpenAndClose {public ITV tv;@Overridepublic void open() {this.tv.play();}@Overridepublic void setTv(ITV tv) {this.tv = tv;}}
此处 通过 set方法的参数 ITV ,OpenAndClose 和 ITV 产生了依赖
依赖倒转原则的注意事项和细节:
- 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好.
- 变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展 和优化
- 继承时遵循里氏替换原则
1.4、里氏替换原则
里氏替换原则的必要性:
继承包含这样一层含义:
1、父类中凡是已经实现好的方法,虽然他不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
2、如果一个类被其他类所继承,则当这个类需要任意修改,就必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都可能产生故障
废话不说,就一句话:
子类中尽量不要重写父类的方法
里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖 来 解决问题。.
案例:
不使用里氏替换原则
static class A {public int func1(int num1, int num2) {return num1 - num2;}}static class B extends A {// 重写了A 的方法public int func1(int a, int b) {return a + b;}public int func2(int a,int b){return func1(a,b) + 9;}}public static void main(String[] args) {A a = new A();System.out.println("11-3=" + a.func1(11,3));System.out.println("1-8=" + a.func1(1,8));System.out.println("====================");B b = new B();System.out.println("11-3=" + b.func1(11,3));System.out.println("1-8=" + b.func1(1,8));System.out.println("11+3+9=" + b.func2(11,3));}
解释:B无意中重写的父类的func1方法, 原本func1 是 num1 - num2,重写后 变成 相加, 这样 如果是无意识的话,程序员本来要做 func1的相减功能,但是结果却是相加。造成BUG
改进:
public class B_RichterSubstitutionPrinciple {/* 创建一个更加 基础的基类/static class Base{//更加基础的方法和成员写到Base}static class A extends Base{public int func1(int num1, int num2) {return num1 - num2;}}static class B extends Base {// 如果B需要使用A类的方法,使用组合的关系private A a = new A();// 仍然想用A 的方法public int func3(int a,int b){return this.a.func1(a,b);}// 重写了A 的方法public int func1(int a, int b) {return a + b;}public int func2(int a,int b){return func1(a,b) + 9;}}public static void main(String[] args) {A a = new A();System.out.println("11-3=" + a.func1(11,3));System.out.println("1-8=" + a.func1(1,8));System.out.println("====================");// 因为B类不再继承A 类,因此调用者不会在func1是求减法B b = new B();System.out.println("11-3=" + b.func3(11,3));System.out.println("1-8=" + b.func3(1,8));System.out.println("1+8=" + b.func1(1,8));System.out.println("11+3+9=" + b.func2(11,3));}}
代码解释:
创建一个更为基础的 类
static class Base{//更加基础的方法和成员写到Base}
A、B 类 继承的是 base B类不再继承 A 类 就不存在重写的情况
B类中使用A类的 func1方法是 通过 new A 的方法(组合依赖解决问题)
static class B extends Base {// 如果B需要使用A类的方法,使用组合的关系private A a = new A();// 仍然想用A 的方法public int func3(int a,int b){return this.a.func1(a,b);}// 重写了A 的方法public int func1(int a, int b) {return a + b;}public int func2(int a,int b){return func1(a,b) + 9;}}
1.5、开闭原则
最重要 最基础的原则 对扩展开放【提供者】 对修改关闭【使用方】
一个软件实体 如类、模块、函数 应该对 扩展新功能 开放,对修改旧功能关闭。
用抽象 构建 框架、用实体 扩展细节
案例 绘图
不使用开闭原则:
public class A_OpenClosePrinciple {public static void main(String[] args) {GraphicEditor graphicEditor = new GraphicEditor();// 矩形graphicEditor.drawShape(new GraphicEditor.Rectangle());// 圆形graphicEditor.drawShape(new GraphicEditor.Circle());// 三角形// 1graphicEditor.drawShape(new GraphicEditor.Triangle());}/* 这是一个用于绘图的类*/static class GraphicEditor{// 接收Shape对象,然后 根据type,来绘制不同的图形 【使用方】public void drawShape(Shape s){if (s.m_type == 1){drawRectangle(s);}else if (s.m_type == 2){drawCircle(s);}else if (s.m_type == 3){// 2drawTriangle(s);}}// 绘制矩形public void drawRectangle(Shape s){System.out.println("绘制矩形");}// 绘制圆public void drawCircle(Shape s){System.out.println("绘制圆");}// 绘制三角形// 3public void drawTriangle(Shape s){System.out.println("绘制三角形");}// Shape 类static class Shape{int m_type;}// 矩形static class Rectangle extends Shape{Rectangle(){super.m_type = 1;}}// 圆static class Circle extends Shape{Circle(){super.m_type = 2;}}// 新增三角形// 4static class Triangle extends Shape{Triangle(){super.m_type = 3;}}}
}
解释:
- 优点: 好理解,简单易操作
- 缺点:违反了设计模式的开闭原则,对扩展开放【提供者】 对修改关闭【使用方】
即:当我们给类增加功能时,尽量不要修改代码或少修改代码
如下:新增三角形 修改 4处
四处:
1、
// 三角形
// 1
graphicEditor.drawShape(new GraphicEditor.Triangle());
2、
else if (s.m_type == 3){// 2drawTriangle(s);
}
3、
// 绘制三角形// 3public void drawTriangle(Shape s){System.out.println("绘制三角形");}
4、
// 新增三角形// 4static class Triangle extends Shape{Triangle(){super.m_type = 3;}}
改进:
使用开闭原则:
将基类 Shape类 做成 抽象类,并提供一个抽象的draw方法,让子类去实现其需要
public class B_OpenClosePrinciple {public static void main(String[] args) {GraphicEditor graphicEditor = new GraphicEditor();// 矩形graphicEditor.drawShape(new GraphicEditor.Rectangle());// 圆形graphicEditor.drawShape(new GraphicEditor.Circle());// 三角形graphicEditor.drawShape(new GraphicEditor.Triangle());graphicEditor.drawShape(new GraphicEditor.pentagon());}/* 这是一个用于绘图的类*/static class GraphicEditor{// 接收Shape对象,然后 根据type,来绘制不同的图形 【使用方】public void drawShape(Shape s){s.draw();}// Shape 类static abstract class Shape{public abstract void draw();}// 矩形static class Rectangle extends Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}}// 圆static class Circle extends Shape {@Overridepublic void draw() {System.out.println("绘制圆");}}// 新增三角形static class Triangle extends Shape {@Overridepublic void draw() {System.out.println("绘制三角形");}}// 新增五角形static class pentagon extends Shape {@Overridepublic void draw() {System.out.println("绘制五角形");}}}
}
解释:
创建一个 抽象绘图类
// Shape 类
static abstract class Shape{public abstract void draw();
}
各个图形继承这个歌类 重写其绘图方法
// 矩形static class Rectangle extends Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}}
这样 每次增加一个图形 只需要 加一个类 继承 Shape接口即可
1.6、迪米特原则
看不懂的官方:
一个类 对自己依赖的类知道的越少越好。也就是说:对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供public方法,不对外泄露任何信息
简单来说: 一个类中 只与 [ 直接的朋友 ] 产生依赖 如果是 陌生类,就违背 迪米特法则
什么是直接朋友:
1、成员变量: A类中的 全局变量 有 private B b; B是A的直接朋友
2、方法参数:A类中 M1方法的 请求参数 为 B b -> m1(B b){} A与B是直接朋友
3、方法返回值的类: A类中的方法 M2 的返回值为B -> public B M2(){} A与B是直接朋友
之外就是 陌生的类。
目的:
1、迪米特原则:降低类之间的耦合
2、只要求降低 耦合度,而不是完全没有
案例:
不使用 迪米特原则
public class A_DemeterPrinciple {public static void main(String[] args) {//创建了一个 SchoolManager 对象SchoolManager schoolManager = new SchoolManager();//输出学院的员工 id 和 学校总部的员工信息schoolManager.printAllEmployee(new CollegeManager());}//学校总部员工类static class Employee {private String id;public void setId(String id) {this.id = id;}public String getId() {return id;}}//学院的员工类static class CollegeEmployee {private String id;public void setId(String id) {this.id = id;}public String getId() {return id;}}// 管理学院员工的管理类static class CollegeManager {// 返回学院的所有员工public List<CollegeEmployee> getAllEmployee() {List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();for (int i = 0; i < 10; i++) { // 这里我们增加了 10 个员工到 listCollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工 id= " + i);list.add(emp);}return list;}}// 学校管理类
// 分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
// CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则static class SchoolManager {// 返回学校总部的员工public List<Employee> getAllEmployee() {List<Employee> list = new ArrayList<Employee>();for (int i = 0; i < 5; i++) { //这里我们增加了 5 个员工到 listEmployee emp = new Employee();emp.setId("学校总部员工 id= " + i);list.add(emp);}return list;}//该方法完成输出学校总部和学院员工信息(id)void printAllEmployee(CollegeManager sub) {/* 分析问题* 1. 这里的 CollegeEmployee 不是 SchoolManager 的直接朋友* 2. CollegeEmployee 是以局部变量方式出现在 SchoolManager* 3. 违反了 迪米特法则*///获取到学院员工List<CollegeEmployee> list1 = sub.getAllEmployee();System.out.println("----------------学院员工--------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}//获取到学校总部员工List<Employee> list2 = this.getAllEmployee();System.out.println("------------学校总部员工-----------");for (Employee e : list2) {System.out.println(e.getId());}}}
}
其中:
void printAllEmployee(CollegeManager sub) {//获取到学院员工List<CollegeEmployee> list1 = sub.getAllEmployee();System.out.println("----------------学院员工--------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}
}
这里的 CollegeEmployee 不是 SchoolManager 的直接朋友
CollegeEmployee 是以局部变量方式出现在 SchoolManager
违反了 迪米特法则
改进:
public class B_DemeterPrinciple {public static void main(String[] args) {//创建了一个 SchoolManager 对象SchoolManager schoolManager = new SchoolManager();//输出学院的员工 id 和 学校总部的员工信息schoolManager.printAllEmployee(new CollegeManager());}//学校总部员工类static class Employee {private String id;public void setId(String id) {this.id = id;}public String getId() {return id;}}//学院的员工类static class CollegeEmployee {private String id;public void setId(String id) {this.id = id;}public String getId() {return id;}}// 管理学院员工的管理类static class CollegeManager {// 返回学院的所有员工public List<CollegeEmployee> getAllEmployee() {List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();for (int i = 0; i < 10; i++) { // 这里我们增加了 10 个员工到 listCollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工 id= " + i);list.add(emp);}return list;}// 输出学院员工的信息public void printEmployee(){//获取到学院员工List<CollegeEmployee> list1 = getAllEmployee();System.out.println("----------------学院员工--------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}}}// 学校管理类
// 分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
// CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则static class SchoolManager {// 返回学校总部的员工public List<Employee> getAllEmployee() {List<Employee> list = new ArrayList<Employee>();for (int i = 0; i < 5; i++) { //这里我们增加了 5 个员工到 listEmployee emp = new Employee();emp.setId("学校总部员工 id= " + i);list.add(emp);}return list;}//该方法完成输出学校总部和学院员工信息(id)void printAllEmployee(CollegeManager sub) {/* 1. 这里的 CollegeEmployee 不是 SchoolManager 的直接朋友* 2. CollegeEmployee 是以局部变量方式出现在 SchoolManager* 3. 违反了 迪米特法则 改进:* 1、将输出学院的员工方法,封装到 CollegeManager 对应到 被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部///获取到学院员工sub.printEmployee();//获取到学校总部员工List<Employee> list2 = this.getAllEmployee();System.out.println("------------学校总部员工-----------");for (Employee e : list2) {System.out.println(e.getId());}}}
}
重点:
void printAllEmployee(CollegeManager sub) {//获取到学院员工sub.printEmployee();//获取到学校总部员工List<Employee> list2 = this.getAllEmployee();System.out.println("------------学校总部员工-----------");for (Employee e : list2) {System.out.println(e.getId());}}
将输出学院的员工方法,封装到 CollegeManager 对应到 被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部
// 输出学院员工的信息public void printEmployee(){//获取到学院员工List<CollegeEmployee> list1 = getAllEmployee();System.out.println("----------------学院员工--------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}}