• 尚硅谷设计模式学习(一)设计模式七大原则


    感谢尚硅谷

    视频地址:尚硅谷Java设计模式(图解+框架源码剖析)_哔哩哔哩_bilibili

    编写软件过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式就是对软件设计中普遍存在(反复出现)的问题提出的解决方案。

    设计模式是为了让程序具有更好

    1. 代码重用性(即:相同功能的代码,不用多次编写)
    2. 可读性(即:编程规范性,便于其他程序员的阅读和理解)
    3. 可扩展性(即:当需要增加新的功能时,非常的方便,称为可维护)
    4. 可靠性 (即:当我们增加新的功能后,对原来的功能没有影响)
    5. 使程序呈现高内聚,低耦合的特性

    设计模式常用的七大原则

    1)单一职责原则

    2)接口隔离原则

    3)依赖倒转原则

    4)里氏替换原则

    5)开闭原则

    6)迪米特法则

    7)合成复用原则

    设计模式分为三种类型,共  23  种

    1)创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。 

    2)结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
    3)行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、 解释器模式(Interpreter  模式)、状态模式、策略模式、职责链模式(责任链模式)。

    分享金句:

    设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要”

    一、单一职责原则

    对类来说,即一个类只能负责一项职责。如类 A 负责两个不同职责:职责 1,职责 2。当职责 1 需求变更而改变 A 时,可能造成职责 2 执行错误,所以需要将类 A 的粒度分解为 A1,A2。

    应用实例

    方式一

    1. public class SingleResponsibility1 {
    2. public static void main(String[] args) {
    3. Vehicle vehicle = new Vehicle();
    4. vehicle.run("摩托车");
    5. vehicle.run("汽车");
    6. vehicle.run("飞机");
    7. }
    8. }
    9. class Vehicle{
    10. public void run(String vehicle){
    11. System.out.println(vehicle+"在公路上跑");
    12. }
    13. }

    问题分析

    1)运行结果中不管是摩托车,飞机还是汽车,都是在公路上运行,违反了单一职责原则

    2)解决办法,我们应该将Vehicle 分解成不同的类

    方式二

    1. public class SingleResponsibility2 {
    2. public static void main(String[] args) {
    3. RoadVehicle roadVehicle = new RoadVehicle();
    4. roadVehicle.run("汽车");
    5. AirVehicle airVehicle = new AirVehicle();
    6. airVehicle.run("飞机");
    7. WaterVehicle waterVehicle = new WaterVehicle();
    8. waterVehicle.run("轮船");
    9. }
    10. }
    11. class RoadVehicle {
    12. public void run(String verhicle) {
    13. System.out.println(verhicle + "公路上");
    14. }
    15. }
    16. class AirVehicle{
    17. public void run(String verhicle) {
    18. System.out.println(verhicle + "在天空");
    19. }
    20. }
    21. class WaterVehicle{
    22. public void run(String verhicle){
    23. System.out.println(verhicle + "在水里");
    24. }
    25. }

    问题分析

    1) 遵守单一职责原则,但是这样做的改动很大,即将类分解,同时修改客户端

    2)改进:直接修改 Vehicle 类,改动的代码会比较少=>方案 3

    方式三

    1. public class SingleResponsibility3 {
    2. public static void main(String[] args) {
    3. Vehicle2 vehicle2 = new Vehicle2();
    4. vehicle2.run("摩托");
    5. vehicle2.runAir("船");
    6. vehicle2.runWater("飞机");
    7. }
    8. }
    9. class Vehicle2{
    10. public void run(String vehicle){
    11. System.out.println(vehicle + "在公路上运行");
    12. }
    13. public void runAir(String vehicle){
    14. System.out.println(vehicle + "在天空运行");
    15. }
    16. public void runWater(String verhicle){
    17. System.out.println(verhicle + "在水里");
    18. }
    19. }

    分析

    1)这种修改方法没有对原来的类做大的修改,只是增加方法 

    2)这里虽然没有在类这个级别上遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责

    注意事项和细节 

    1)降低类的复杂度,一个类只负责一个职责

    2)提高类的可读性,可维护性

    3)降低变更引起的风险

    4)通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则

    二、接口隔离原则

    客户端不应该依赖它不需要的接口,即一个类对另一个的依赖应该建立在最小接口上。

    先看一张图 

    类 A 通过接口 Interface1 依赖类 B,类 C 通过接口 Interface1 依赖类 D,如果接口 Interface1 对于类 A 和类 C来说不是最小接口,那么类 B 和类 D 必须去实现他们不需要的方法。

    按隔离原则应当这样处理:

    将接口 Interface1 拆分为独立的几个接口(这里我们拆分成 3 个接口),类 A 和类 C 分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则

    应用实例

    方式一

    1. public class Segreation1 {
    2. }
    3. interface Interface1{
    4. void operation1();
    5. void operation2();
    6. void operation3();
    7. void operation4();
    8. void operation5();
    9. }
    10. class B implements Interface1 {
    11. public void operation1() {
    12. System.out.println("B实现了operation1");
    13. }
    14. public void operation2() {
    15. System.out.println("B实现了operation2");
    16. }
    17. public void operation3() {
    18. System.out.println("B实现了operation3");
    19. }
    20. public void operation4() {
    21. System.out.println("B实现了operation4");
    22. }
    23. public void operation5() {
    24. System.out.println("B实现了operation5");
    25. }
    26. }
    27. class D implements Interface1 {
    28. public void operation1() {
    29. System.out.println("D实现了operation1");
    30. }
    31. public void operation2() {
    32. System.out.println("D实现了operation2");
    33. }
    34. public void operation3() {
    35. System.out.println("D实现了operation3");
    36. }
    37. public void operation4() {
    38. System.out.println("D实现了operation4");
    39. }
    40. public void operation5() {
    41. System.out.println("D实现了operation5");
    42. }
    43. }
    44. class A{
    45. //A类通过依赖接口Interface1依赖使用B类,但只会使用1,2,3方法
    46. public void depend1(Interface1 i){
    47. i.operation1();
    48. }
    49. public void depend2(Interface1 i){
    50. i.operation2();
    51. }
    52. public void depend3(Interface1 i){
    53. i.operation3();
    54. }
    55. }
    56. class C {
    57. //C类通过依赖接口Interface1依赖使用B类,但只会使用1,4,5方法
    58. public void depend1(Interface1 i){
    59. i.operation1();
    60. }
    61. public void depend4(Interface1 i){
    62. i.operation4();
    63. }
    64. public void depend5(Interface1 i){
    65. i.operation5();
    66. }
    67. }

     改进

    1. public class Segreation2 {
    2. }
    3. interface Interface2{
    4. void operation1();
    5. }
    6. interface Interface3{
    7. void operation2();
    8. void operation3();
    9. }
    10. interface Interface4{
    11. void operation4();
    12. void operation5();
    13. }
    14. class E implements Interface2, Interface3 {
    15. public void operation1() {
    16. System.out.println("B实现了operation1");
    17. }
    18. public void operation2() {
    19. System.out.println("B实现了operation2");
    20. }
    21. public void operation3() {
    22. System.out.println("B实现了operation3");
    23. }
    24. }
    25. class F implements Interface2, Interface4 {
    26. public void operation1() {
    27. System.out.println("D实现了operation1");
    28. }
    29. public void operation4() {
    30. System.out.println("D实现了operation4");
    31. }
    32. public void operation5() {
    33. System.out.println("D实现了operation5");
    34. }
    35. }
    36. class G{
    37. //A类通过依赖接口Interface1依赖使用B类,但只会使用1,2,3方法
    38. public void depend1(Interface2 i){
    39. i.operation1();
    40. }
    41. public void depend2(Interface3 i){
    42. i.operation2();
    43. }
    44. public void depend3(Interface3 i){
    45. i.operation3();
    46. }
    47. }
    48. class H {
    49. //C类通过依赖接口Interface1依赖使用B类,但只会使用1,4,5方法
    50. public void depend1(Interface2 i){
    51. i.operation1();
    52. }
    53. public void depend4(Interface4 i){
    54. i.operation4();
    55. }
    56. public void depend5(Interface4 i){
    57. i.operation5();
    58. }
    59. }

     三、依赖倒转(倒置)原则

    依赖倒转原则是指:

    1)高层模块不应依赖低层模块,二者都应该依赖其抽象(比如抽象类,接口)

    2)抽象不应该依赖细节,细节应该依赖抽象

    3)依赖倒转(倒置)中心思想就是面向接口编程

    4)依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在 java 中,抽象指的是接口或抽象类,细节就是具体的实现类

    5) 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

    应用实例

    请编程完成 Person 接收消息的功能

    1. public class DependecyInversion {
    2. public static void main(String[] args) {
    3. person person = new person();
    4. person.receive(new Email());
    5. }
    6. }
    7. class Email{
    8. public String getInfo(){
    9. return "邮箱:hello,world";
    10. }
    11. }
    12. class person{
    13. public void receive(Email email){
    14. System.out.println("收到:"+email.getInfo());
    15. }
    16. }

    问题分析

    1)如果我们获取的对象是微信,短信等等,则新增类,同时Perons也要增加相应的接收方法

    2)解决思路:引入一个抽象的接口IReceiver,表示接收者,这样Person类与IReceiver发生依赖,因为Email, WeiXin等等属于接收的范围,他们各自实现IReceiver接口就ok,这样我们就符号依赖倒转原则

    改进

    1. public class DependecyInversion {
    2. public static void main(String[] args) {
    3. person person = new person();
    4. person.receive(new Email());
    5. person.receive(new weixin());
    6. }
    7. }
    8. interface IReceive{
    9. String getInfo();
    10. }
    11. class Email implements IReceive {
    12. public String getInfo(){
    13. return "邮箱:hello,world";
    14. }
    15. }
    16. class weixin implements IReceive {
    17. public String getInfo() {
    18. return "微信:hello,world";
    19. }
    20. }
    21. class person{
    22. //对接口的依赖
    23. public void receive(IReceive iReceive){
    24. System.out.println("收到:" + iReceive.getInfo());
    25. }
    26. }

    依赖传递的三种方式

    1)接口传递

    1. public class DependecyPass {
    2. public static void main(String[] args) {
    3. OpenAndClose openAndClose = new OpenAndClose();
    4. openAndClose.open(new changhong());
    5. openAndClose.open(new xiaomi());
    6. }
    7. }
    8. interface Itv{
    9. public void play();
    10. }
    11. class changhong implements Itv{
    12. public void play() {
    13. System.out.println("长虹电视机打开");
    14. }
    15. }
    16. class xiaomi implements Itv{
    17. public void play() {
    18. System.out.println("小米电视机打开");
    19. }
    20. }
    21. class OpenAndClose{
    22. public void open(Itv itv) {
    23. itv.play();
    24. }
    25. }

    2)构造方法传递

    1. public class DependecyPass {
    2. public static void main(String[] args) {
    3. OpenAndClose openAndClose1 = new OpenAndClose(new changhong());
    4. openAndClose1.open();
    5. OpenAndClose openAndClose2 = new OpenAndClose(new xiaomi());
    6. openAndClose2.open();
    7. }
    8. }
    9. interface Itv{
    10. public void play();
    11. }
    12. class changhong implements Itv{
    13. public void play() {
    14. System.out.println("长虹电视机打开");
    15. }
    16. }
    17. class xiaomi implements Itv{
    18. public void play() {
    19. System.out.println("小米电视机打开");
    20. }
    21. }
    22. class OpenAndClose{
    23. private Itv itv;
    24. public OpenAndClose(Itv itv){
    25. this.itv=itv;
    26. }
    27. public void open() {
    28. this.itv.play();
    29. }
    30. }

    3)setter方式传递 

    1. public class DependecyPass {
    2. public static void main(String[] args) {
    3. OpenAndClose openAndClose = new OpenAndClose();
    4. openAndClose.settle(new changhong());
    5. openAndClose.open();
    6. openAndClose.settle(new xiaomi());
    7. openAndClose.open();
    8. }
    9. }
    10. interface Itv{
    11. public void play();
    12. }
    13. class changhong implements Itv{
    14. public void play() {
    15. System.out.println("长虹电视机打开");
    16. }
    17. }
    18. class xiaomi implements Itv{
    19. public void play() {
    20. System.out.println("小米电视机打开");
    21. }
    22. }
    23. class OpenAndClose{
    24. private Itv itv;
    25. public void settle(Itv itv){
    26. this.itv=itv;
    27. }
    28. public void open() {
    29. this.itv.play();
    30. }
    31. }

    依赖倒转原则的注意事项和细节

    1)低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好.

    2)变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化

    3)继承时遵循里氏替换原则

    四、里氏替换原则

    OO(面向对象)中的继承性的思考和说明

    1)继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。

    2)继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低, 增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障

    3)问题提出:在编程中,如何正确的使用继承? => 里氏替换原则

    基本介绍

    1)里氏替换原则(Liskov Substitution Principle)在 1988 年,由麻省理工学院的以为姓里的女士提出的。

    2)如果对每个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象

    3)在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法

    4)里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题

    应用实例

    看个程序,思考下问题和解决思路

    方式一

    1. public class Liskov {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. System.out.println("1 - 2 = " + a.func1(1, 2));
    5. System.out.println("---------------------");
    6. B b = new B();
    7. System.out.println("1 - 2 = " + b.func1(1,2));//这里本意是求出 1-2
    8. System.out.println("1 - 2 + 9 = " + b.func2(1,2));
    9. }
    10. }
    11. class A{
    12. //返回两个数的差
    13. public int func1(int a, int b){
    14. return a - b;
    15. }
    16. }
    17. class B extends A {
    18. @Override
    19. //这里重写了A类的方法,可能是无意识
    20. public int func1(int a, int b){
    21. return a + b;
    22. }
    23. //增加了一个新功能,完成两个数相加,然后和9求和
    24. public int func2(int a, int b){
    25. return func1(a,b) + 9;
    26. }
    27. }

     问题分析

    1)我们发现原来运行正常的相减功能发生了错误。原因就是类 B 无意中重写了父类的方法,造成原有功能出现错误。在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的尚硅谷  Java  设计模式复用性会比较差。特别是运行多态比较频繁的时候

    2)通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。

    3)改进方案 

    改进

    1. public class Liskov {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. System.out.println("1 - 2 = " + a.func1(1, 2));
    5. System.out.println("---------------------");
    6. B b = new B();
    7. System.out.println("1 + 2 = " + b.func1(1,2));
    8. System.out.println("1 + 2 + 9 = " + b.func2(1,2));
    9. System.out.println("1 - 2 = " + b.func3(1,2));
    10. }
    11. }
    12. //创建一个更加基础的基类
    13. class Base{
    14. //把更加基础的方法和成员写到 Base 类
    15. }
    16. class A extends Base {
    17. //返回两个数的差
    18. public int func1(int a, int b){
    19. return a - b;
    20. }
    21. }
    22. class B extends Base {
    23. //如果 B 需要使用 A 类的方法,使用组合关系
    24. private A a = new A();
    25. //这里,重写了 A 类的方法,可能是无意识
    26. public int func1(int a, int b){
    27. return a + b;
    28. }
    29. public int func2(int a, int b){
    30. return func1(a,b) + 9;
    31. }
    32. //我们仍然想使用 A 的方法
    33. public int func3(int a, int b){
    34. return this.a.func1(a,b);
    35. }
    36. }

    五、开闭原则

    1)开闭原则是编程中最基础、最重要的设计原则

    2) 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。

    3)当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

    4)编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。 

    应用实例

    看一个画图形的功能

    1. public class OCP {
    2. public static void main(String[] args) {
    3. //使用看看存在的问题
    4. GraphicEditor graphicEditor = new GraphicEditor();
    5. graphicEditor.drawShape(new Rectangle());
    6. }
    7. }
    8. //这是一个用于绘图的类 【使用方】
    9. class GraphicEditor{
    10. public void drawShape(Shape shape){
    11. if(shape.my_tape == 1){
    12. drawRectangle(shape);
    13. }else if(shape.my_tape == 2){
    14. drawCircle(shape);
    15. }else if(shape.my_tape == 3){
    16. drawTriangle(shape);
    17. }
    18. }
    19. //绘制矩形
    20. public void drawRectangle(Shape r){
    21. System.out.println("矩形");
    22. }
    23. //绘制圆
    24. public void drawCircle(Shape r){
    25. System.out.println("圆");
    26. }
    27. //绘制三角形
    28. public void drawTriangle(Shape r){
    29. System.out.println("三角形");
    30. }
    31. }
    32. class Shape{
    33. int my_tape;
    34. }
    35. class Rectangle extends Shape {
    36. Rectangle(){
    37. super.my_tape = 1;
    38. }
    39. }
    40. class Circle extends Shape {
    41. Circle(){
    42. super.my_tape = 2;
    43. }
    44. }
    45. //新增画三角形
    46. class Triangle extends Shape {
    47. Triangle(){
    48. super.my_tape = 3;
    49. }
    50. }

    问题分析

    1)优点是比较好理解,简单易操作。

    2)缺点是违反了设计模式的 ocp  原则,即对扩展开放(提供方),对修改关闭(使用方)。即当我们给类增加新功能的 时候,尽量不修改代码,或者尽可能少修改代码。

    3)比如我们这时要新增加一个图形种类三角形,我们需要修改的地方较多

    改进 

    思路:把创建  Shape  类做成抽象类,并提供一个抽象的 draw  方法,让子类去实现即可,这样我们有新的图形种类时,只需要让新的图形类继承  Shape,并实现  draw  方法即可,使用方的代码就不需要修改  --->  满足了开闭原则 

    1. public class OCP {
    2. public static void main(String[] args) {
    3. GraphicEditor graphicEditor = new GraphicEditor();
    4. graphicEditor.drawShape(new Rectangle());
    5. graphicEditor.drawShape(new Circle());
    6. }
    7. }
    8. class GraphicEditor{
    9. public void drawShape(Shape shape){
    10. shape.show();
    11. }
    12. }
    13. //Shape 类,基类
    14. abstract class Shape{
    15. int my_tape;
    16. public abstract void show();
    17. }
    18. class Rectangle extends Shape {
    19. Rectangle(){
    20. super.my_tape = 1;
    21. }
    22. @Override
    23. public void show() {
    24. System.out.println("矩形");
    25. }
    26. }
    27. class Circle extends Shape {
    28. Circle(){
    29. super.my_tape = 2;
    30. }
    31. @Override
    32. public void show() {
    33. System.out.println("圆");
    34. }
    35. }
    36. //新增三角形
    37. class Triangle extends Shape {
    38. Triangle(){
    39. super.my_tape = 3;
    40. }
    41. @Override
    42. public void show() {
    43. System.out.println("三角形");
    44. }
    45. }

    六、迪米特法则

    1)一个对象应该对其他对象保持最少的了解

    2)类与类关系越密切,耦合度越大

    3)迪米特法则(Demeter  Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于 被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的  public 方法,不对外泄露任何信息

    4)迪米特法则还有个更简单的定义:只与直接的朋友通信

    5)直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部

    应用实例

    有一个学校,下属有各个学院和总部,现要求打印出学校总部员工 ID  和学院员工的 id

    1. public class Demeter1 {
    2. public static void main(String[] args) {
    3. //创建了一个 SchoolManager 对象
    4. SchoolManager schoolManager = new SchoolManager();
    5. //输出学院的员工id 和 学校总部的员工信息
    6. schoolManager.printAllEmployee(new CollegeManager());
    7. }
    8. }
    9. //学校总部员工类
    10. class Employee {
    11. private String id;
    12. public void setId(String id) {
    13. this.id = id;
    14. }
    15. public String getId() {
    16. return id;
    17. }
    18. }
    19. //学院员工类
    20. class CollegeEmployee {
    21. private String id;
    22. public void setId(String id) {
    23. this.id = id;
    24. }
    25. public String getId() {
    26. return id;
    27. }
    28. }
    29. //学院员工的管理类
    30. class CollegeManager {
    31. //返回学院的所有员工
    32. public List getAllEmployee() {
    33. List list = new ArrayList();
    34. for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
    35. CollegeEmployee emp = new CollegeEmployee();
    36. emp.setId("学院员工id = " + i);
    37. list.add(emp);
    38. }
    39. return list;
    40. }
    41. }
    42. //学校员工管理类,包括学院员工和学校总部员工
    43. //分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
    44. //CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
    45. class SchoolManager {
    46. //返回学校总部的员工
    47. public List getAllEmployee() {
    48. List list = new ArrayList();
    49. for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
    50. Employee emp = new Employee();
    51. emp.setId("学校总部员工id = " + i);
    52. list.add(emp);
    53. }
    54. return list;
    55. }
    56. //该方法完成输出学校总部和学院员工信息(id)
    57. void printAllEmployee(CollegeManager sub) {
    58. //获取到学院员工
    59. List list1 = sub.getAllEmployee();
    60. System.out.println("------------学院员工------------");
    61. for (CollegeEmployee e : list1) {
    62. System.out.println(e.getId());
    63. }
    64. //获取到学校总部员工
    65. List list2 = this.getAllEmployee();
    66. System.out.println("------------学校总部员工------------");
    67. for (Employee e : list2) {
    68. System.out.println(e.getId());
    69. }
    70. }
    71. }

    问题分析

    这里的 CollegeEmployee 不是  SchoolManager的直接朋友,CollegeEmployee 以局部变量方式出现在 SchoolManager中,违反了 迪米特法则。

    改进

    1. //管理学院员工的管理类
    2. class CollegeManager {
    3. //返回学院的所有员工
    4. public List getAllEmployee() {
    5. List list = new ArrayList();
    6. for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
    7. CollegeEmployee emp = new CollegeEmployee();
    8. emp.setId("学院员工id= " + i);
    9. list.add(emp);
    10. }
    11. return list;
    12. }
    13. public void print(){
    14. List list1 = getAllEmployee();
    15. System.out.println("------------学院员工------------");
    16. for (CollegeEmployee e : list1) {
    17. System.out.println(e.getId());
    18. }
    19. }
    20. }
    21. //学校员工管理类,包括学院员工和学校总部员工
    22. class SchoolManager {
    23. //返回学校总部的员工
    24. public List getAllEmployee() {
    25. List list = new ArrayList();
    26. for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
    27. Employee emp = new Employee();
    28. emp.setId("学校总部员工id= " + i);
    29. list.add(emp);
    30. }
    31. return list;
    32. }
    33. //该方法完成输出学校总部和学院员工信息(id)
    34. void printAllEmployee(CollegeManager sub) {
    35. //打印学院员工
    36. sub.print();
    37. //获取到学校总部员工
    38. List list2 = this.getAllEmployee();
    39. System.out.println("------------学校总部员工------------");
    40. for (Employee e : list2) {
    41. System.out.println(e.getId());
    42. }
    43. }

    七、合成复用原则

    原则是尽量使用合成/聚合的方式,而不是使用继承。

    设计原则核心思想

    1)找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

    2)针对接口编程,而不是针对实现编程。

    3)为了交互对象之间的松耦合设计而努力 

  • 相关阅读:
    [计算机提升] Windows系统软件:娱乐类
    CSS 文字特效运用目录
    【AIGC调研系列】Gitlab的Duo Chat与其他辅助编程助手相比的优缺点
    docker 搭建 redis 集群
    一篇文章,带你了解CodeTour与入门指导
    LeetCode 第 307 场周赛 复盘
    模块化Common JS 和 ES Module
    一文带你读懂云原生、微服务与高可用
    前端面试题46(vue路由如何根据权限动态控制路由的显示?)
    中文稀疏GPT大模型落地 — 通往低成本&高性能多任务通用自然语言理解的关键里程碑
  • 原文地址:https://blog.csdn.net/qq_51409098/article/details/126820569