loong - 设计模式 - 七种设计原则

loong - 设计模式 - 七种设计原则

分类

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒置原则
  • 里氏替换原则
  • 开闭原则
  • 迪米特法则
  • 合成复用原则

单一职责原则

定义:

​ 一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。即,每个类只负责自己的事情,而不是变成万能

注意事项

  • 降低类的复杂度,一个类只负责一项职责
  • 提高类的可读性,可维护性
  • 降低变更引起的风险
  • 通常情况下,**我们应当遵守单一职责原则,**只有逻辑足够简单,才可以在代码级违反单一职责;只有在类中方法数量足够少,可以在方法上保持单一职责

示例

  • 方案一

    package com.learning.principle.singleresponsibility;
    
    /**
     * 方案一
     * 1.违背了 单一职责 飞机不应该在陆地上行驶
     *
     * @author nieshenglei
     */
    public class SingleResponsibility1 {
      public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("摩托车");
        vehicle.run("汽车");
        vehicle.run("飞机");
    
      }
    
    }
    
    
    /**
     * 交通工具类
     */
    class Vehicle {
    
      public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上行驶");
      }
    
    }
    
  • 方案二

    package com.learning.principle.singleresponsibility;
    
    /**
     * 方案二 分析
     * 1. 遵守了单一职责
     * 2.但是 改动大 原类Vehicle被修改 客户端也要跟着修改  这时候可以考虑 方案三 在方法层面遵守单一职责
     *
     * @author nieshenglei
     */
    public class SingleResponsibility2 {
    
      //客户端
      public static void main(String[] args) {
        RoadVehicle roadVehicle = new RoadVehicle();
        roadVehicle.run("摩托车");
        roadVehicle.run("汽车");
    
        AirVehicle airVehicle = new AirVehicle();
        airVehicle.run("飞机");
    
      }
    
    }
    
    
    /**
     * 公路上跑的交通工具类
     */
    class RoadVehicle {
    
      public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上行驶");
      }
    
    }
    
    /**
     * 空中的交通工具类
     */
    class AirVehicle {
    
      public void run(String vehicle) {
        System.out.println(vehicle + " 在天空飞行");
      }
    
    }
    
    /**
     * 水中的交通工具类
     */
    class WaterVehicle {
    
      public void run(String vehicle) {
        System.out.println(vehicle + " 在水中行驶");
      }
    
    }
    
  • 方案三

    package com.learning.principle.singleresponsibility;
    
    /**
     * 方案三
     * 1. 在类的层面上 没有完全遵守单一职责
     * 2. 在方法级别上遵守了 单一职责
     *
     *  对比 方案二 类中方法少 其实可以使用 方案三 在方法层面遵守单一职责 但是如果后期的交通工具类不断扩大 建议使用方案二 拆分
     *
     * @author nieshenglei
     */
    public class SingleResponsibility3 {
    
      //客户端
      public static void main(String[] args) {
        CommentVehicle vehicle = new CommentVehicle();
        vehicle.runRoad("摩托车");
        vehicle.runRoad("汽车");
        vehicle.runAir("飞机");
        vehicle.runWater("轮船");
      }
    
    }
    
    
    /**
     * 交通工具类
     */
    class CommentVehicle {
    
      /**
       *  陆地交通工具
       *
       * @param vehicle 交通工具
       */
      public void runRoad(String vehicle) {
        System.out.println(vehicle + " 在公路上行驶");
      }
    
      /**
       *  空中交通工具
       *
       * @param vehicle 交通工具
       */
      public void runAir(String vehicle) {
        System.out.println(vehicle + " 在空中行驶");
      }
    
      /**
       *  水中交通工具
       *
       * @param vehicle 交通工具
       */
      public void runWater(String vehicle) {
        System.out.println(vehicle + " 在水上行驶");
      }
    
    }
    

接口隔离原则

定义:

  • 客户端不应该依赖它不需要的接口;
  • 一个类对另一个类的依赖应该建立在最小的接口上。
    概括的说就是:建立单一接口,不要建立臃肿庞大的接口。(接口尽量细化,同时接口中的方法尽量少。)

实例一(不符合原则)

UML类图

接口隔离错误示例

代码

package com.learning.principle.segregation;

/**
 * @author nieshenglei
 */
public class Segregation1 {

  /**
   * 客户端
   * @param args 入参
   */
  public static void main(String[] args) {

    A a = new A();
    B b = new B();
    a.depend1(b);
    a.depend2(b);
    a.depend3(b);

    C c = new C();
    D d = new D();
    c.depend1(d);
    c.depend4(d);
    c.depend5(d);

  }

}

interface Interface1 {
  /**
   * 方法1
   */
  void opreation1();
  /**
   * 方法2
   */
  void opreation2();


  /**
   * 方法3
   */
  void opreation3();
  /**
   * 方法4
   */
  void opreation4();
  /**
   * 方法5
   */
  void opreation5();

}

/**
 * B 类
 */
class B implements Interface1{
  /**
   * 方法1
   */
  @Override
  public void opreation1() {
    System.out.println("B 实现了 Interface1接口 的 opreation1 方法");
  }

  /**
   * 方法2
   */
  @Override
  public void opreation2() {
    System.out.println("B 实现了 Interface1接口 的 opreation2 方法");
  }

  /**
   * 方法3
   */
  @Override
  public void opreation3() {
    System.out.println("B 实现了 Interface1接口 的 opreation3 方法");
  }

  /**
   * 方法4
   */
  @Override
  public void opreation4() {
    System.out.println("B 实现了 Interface1接口 的 opreation4 方法");
  }

  /**
   * 方法5
   */
  @Override
  public void opreation5() {
    System.out.println("B 实现了 Interface1接口 的 opreation5 方法");
  }
}

/**
 * D 类
 */
class D implements Interface1{
  /**
   * 方法1
   */
  @Override
  public void opreation1() {
    System.out.println("D 实现了 Interface1接口 的 opreation1 方法");
  }

  /**
   * 方法2
   */
  @Override
  public void opreation2() {
    System.out.println("D 实现了 Interface1接口 的 opreation2 方法");
  }

  /**
   * 方法3
   */
  @Override
  public void opreation3() {
    System.out.println("D 实现了 Interface1接口 的 opreation3 方法");
  }

  /**
   * 方法4
   */
  @Override
  public void opreation4() {
    System.out.println("D 实现了 Interface1接口 的 opreation4 方法");
  }

  /**
   * 方法5
   */
  @Override
  public void opreation5() {
    System.out.println("D 实现了 Interface1接口 的 opreation5 方法");
  }
}

/**
 * A类 通过接口 Interface1 依赖使用B类,但是只会用到 1 2 3 方法
 */
class A{

  public void depend1(Interface1 interface1){
    interface1.opreation1();
  }

  public void depend2(Interface1 interface1){
    interface1.opreation3();
  }

  public void depend3(Interface1 interface1){
    interface1.opreation3();
  }

}

/**
 * C 类 通过接口 Interface1 依赖使用B类,但是只会用到 1 4 5 方法
 */
class C{

  public void depend1(Interface1 interface1){
    interface1.opreation1();
  }

  public void depend4(Interface1 interface1){
    interface1.opreation4();
  }

  public void depend5(Interface1 interface1){
    interface1.opreation5();
  }

}

实例二(符合隔离原则)

UML

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9jejseuj-1680739281760)(…/Z-md_image/%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99%E5%AE%9E%E4%BE%8B%E4%BA%8C%E5%9B%BE%E5%83%8F.png)]

代码

package com.learning.principle.segregation;

/**
 * 接口隔离原则 正确示例
 * <p/>
 * 将 原有的 Interface1 接口 拆分成 Interface11(方法一) Interface22(方法二,方法三) Interface33(方法四,方法五)
 * <p/>
 * B 类实现了 接口 Interface11 Interface22 <br>
 * A 类通过 接口 Interface11 Interface22 接口 依赖 B 类(方法一 二 三)<br>
 *
 * D类实现了 接口 Interface11 Interface22 <br>
 * C类通过  接口 Interface11 Interface33 接口 依赖 D类(方法 一 四 五)<br>
 *
 * @author nieshenglei
 */
public class Segregation2 {

  /**
   * 客户端
   * @param args 入参
   */
  public static void main(String[] args) {

    A1 a1 = new A1();
    B1 b1 = new B1();
    a1.depend1(b1);
    a1.depend2(b1);
    a1.depend3(b1);

    C1 c1 = new C1();
    D1 d1 = new D1();
    c1.depend1(d1);
    c1.depend4(d1);
    c1.depend5(d1);

  }

}

interface Interface11 {
  /**
   * 方法1
   */
  void opreation1();

}

interface Interface22 {

  /**
   * 方法2
   */
  void opreation2();
  /**
   * 方法3
   */
  void opreation3();


}

interface Interface33 {

  /**
   * 方法4
   */
  void opreation4();
  /**
   * 方法5
   */
  void opreation5();

}

/**
 * B1 类 Interface11  * B1 类
 */
class B1 implements Interface11, Interface22{
  /**
   * 方法1
   */
  @Override
  public void opreation1() {
    System.out.println("B1 实现了 Interface11接口 的 opreation1 方法");
  }

  /**
   * 方法2
   */
  @Override
  public void opreation2() {
    System.out.println("B1 实现了 Interface22接口 的 opreation2 方法");
  }

  /**
   * 方法3
   */
  @Override
  public void opreation3() {
    System.out.println("B1 实现了 Interface22接口 的 opreation3 方法");
  }
}

/**
 * D1 类 实现了 Interface11 Interface33
 */
class D1 implements Interface11,Interface33{
  /**
   * 方法1
   */
  @Override
  public void opreation1() {
    System.out.println("D1 实现了 Interface11接口 的 opreation1 方法");
  }

  /**
   * 方法4
   */
  @Override
  public void opreation4() {
    System.out.println("D1 实现了 Interface33接口 的 opreation4 方法");
  }

  /**
   * 方法5
   */
  @Override
  public void opreation5() {
    System.out.println("D1 实现了 Interface33接口 的 opreation5 方法");
  }
}

/**
 * A1类 通过接口 Interface11 Interface22 依赖使用B类,但是只会用到 1 2 3 方法
 */
class A1{

  public void depend1(Interface11 interface11){
    interface11.opreation1();
  }

  public void depend2(Interface22 interface22){
    interface22.opreation3();
  }

  public void depend3(Interface22 interface22){
    interface22.opreation3();
  }

}

/**
 * C1 类 通过接口 Interface11 Interface33 依赖使用B类,但是只会用到 1 4 5 方法
 */
class C1{

  public void depend1(Interface11 interface11){
    interface11.opreation1();
  }

  public void depend4(Interface33 interface33){
    interface33.opreation4();
  }

  public void depend5(Interface33 interface33){
    interface33.opreation5();
  }

}

依赖倒置原则

定义

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象**(抽象是指接口或抽象类)**
  • 抽象不应该依赖细节**(细节是指实现类)**
  • 细节应该依赖抽象
  • 核心思想:面向接口编程

实例一(不符合原则)

package com.learning.principle.inversion;

/**
 * 依赖倒置原则 示例
 *
 * @author nieshenglei
 */
public class DependencyInversion1 {

  //客户端
  public static void main(String[] args) {
    Person1 person1 = new Person1();
    person1.receive(new Email1());
  }

}

/**
 * 邮件类
 */
class Email1{
  public String getInfo(){
    return "电子邮件信息: hello,world";
  }
}

/**
 * 方式一
 *  完成Person接收邮件
 *  <br>
 *  分析
 *    1.实现简单
 *    2.如果我们获取的消息类型是其他类型 如 微信 短息 QQ 则需要新增类,同时Person也要
 *      增加相应的接受方法
 *  <p>
 *   解决思路:引入一个抽象的接口IReceiver,表示接收者,让Person类与接口IReceiver发生依赖
 *   因为 Email,微信,QQ属于接收的范围,他们各自实现IReceiver接口就可以,使此案例符合依赖倒置原则
 *  </p>
 *
 *
 */
class Person1{

  /**
   * 接收消息
   * @param email 邮件消息
   */
  public void receive(Email1 email){
    System.out.println(email.getInfo());
  }
}

实例二

package com.learning.principle.inversion;

/**
 * 依赖倒置原则 示例
 *
 * @author nieshenglei
 */
public class DependencyInversion2 {

  //客户端
  public static void main(String[] args) {

    //相比 方式一 客户端不需要改动
    Person2 person = new Person2();
    person.receive(new Email2());

    //增加微信接受
    person.receive(new WeiXin());
  }

}

/**
 * 接受消息接口
 */
interface IReceiver{
  /**
   * 接受消息
   * @return 返回消息内容
   */
  public String getInfo();
}

/**
 * 邮件类 实现了 IReceiver 接口
 */
class Email2 implements IReceiver{

  @Override
  public String getInfo(){
    return "电子邮件信息: hello,world";
  }
}

class WeiXin implements IReceiver{

  /**
   * 接受消息
   *
   * @return 返回消息内容
   */
  @Override
  public String getInfo() {
    return "微信消息内容: 叮咚,有人发消息给你啦!";
  }
}

/**
 * 方式二
 *  完成Person接收邮件
 *  <br>
 *  和IReceiver接口耦合,不和具体的消息发生耦合,使其能接收各种消息 例如 微信
 *
 */
class Person2{

  /**
   * 接收消息
   * @param iReceiver 邮件消息
   */
  public void receive(IReceiver iReceiver){
    System.out.println(iReceiver.getInfo());
  }

}

扩展:依赖传递三种方式

  • 通过接口传递
  • 通过构造器传递
  • 通过setter方法传递

里氏替换原则

定义

  1. 子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
  2. 提高代码的重用性;

实例一(不符合规则)

package com.learning.principle.liskov;

/**
 * 里氏替换原则 示例一
 *
 * 示例弊端:B1类重写的父类A1类的func1()方法,造成原有功能出现错误
 *
 * @author nieshenglei
 */
public class Liskov1 {

  //客户端
  public static void main(String[] args) {
    A1 a1 = new A1();
    System.out.println("11-3 = "+a1.func1(11, 3));
    System.out.println("1-8 = "+a1.func1(1, 8));

    System.out.println("----------------------------------");

    B1 b1 = new B1();
    //重写了父类的方法,导致计算减法失败,真正使用的是子类重写后的方法
    System.out.println("11-3 = "+b1.func1(11, 3));
    System.out.println("1-8 = "+b1.func1(1, 8));
    System.out.println("11+3+9 = "+b1.func2(11, 3));
  }

}

/**
 * A 类
 */
class A1{

  /**
   * 返回两个数的差
   * @param num1 入参1
   * @param num2 入参2
   * @return  返回一个int类型
   */
  public int func1(int num1,int num2){
    return num1-num2;
  }

}

/**
 * B 类 继承 A 类
 *
 */
class B1 extends A1{

  /**
   * 此方法 重写 A1的方法
   *
   * 返回两个整型的和
   * @param a 入参1
   * @param b 入参2
   * @return 返回一个int类型
   */
  public int func1(int a,int b){
    return a+b;
  }

  /**
   * 两个整型的求和,并+9
   * @param a 入参1
   * @param b 入参2
   * @return 返回一个int类型
   */
  public int func2(int a,int b){
    return func1(a, b)+9;
  }

}

示例二(符合规则)

package com.learning.principle.liskov;

/**
 * 里氏替换原则 示例二
 *
 * 类 A2 B2 都继承 Base 使 基础方法func1() 不受影响
 *
 * @author nieshenglei
 */
public class Liskov2 {

  //客户端
  public static void main(String[] args) {
    A2 a2 = new A2();
    System.out.println("11-3 = "+a2.func1(11, 3));
    System.out.println("1-8 = "+a2.func1(1, 8));

    System.out.println("----------------------------------");

    B2 b2 = new B2();
    System.out.println("11+3 = "+b2.func1(11, 3));
    System.out.println("1-8 = "+b2.func1(1, 8));
    System.out.println("11+3+9 = "+b2.func2(11, 3));

    //使用组合,仍然可以使用到A1的func1()方法
    System.out.println("8-1 = "+b2.func3(8, 1));
  }

}

/**
 * 定义 一个 基类 将公共的属性和方法放在基类中
 */
class Base{

}

/**
 * A 类
 */
class A2 extends Base{

  /**
   * 返回两个数的差
   * @param num1 入参1
   * @param num2 入参2
   * @return  返回一个int类型
   */
  public int func1(int num1,int num2){
    return num1-num2;
  }

}

/**
 * B 类 继承 A 类
 *
 */
class B2 extends Base{

  //加入B2 仍然需要A2类的方法,可以使用组合关系

  private A2 a2 = new A2();

  /**
   *
   * 返回两个整型的和
   * @param a 入参1
   * @param b 入参2
   * @return 返回一个int类型
   */
  public int func1(int a,int b){
    return a+b;
  }

  /**
   * 两个整型的求和,并+9
   * @param a 入参1
   * @param b 入参2
   * @return 返回一个int类型
   */
  public int func2(int a,int b){
    return func1(a, b)+9;
  }

  public int func3(int a,int b){
    return a2.func1(a, b);
  }

}

开闭原则

定义

  • 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
  • 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
  • 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。

示例一(不符合原则)

package com.learning.principle.ocp;



/**
 * 开闭原则 实例一
 * 优点:好理解,容易操作
 * 缺点:违反了开闭原则(对扩展开放(提供方),对修改关闭(使用方)),即当我们给类
 *      新增功能时,尽量不要修改代码,或者尽可能少修改代码
 *      比如我们新增的图形类 三角形
 *
 *
 * @author nieshenglei
 */
public class Ocp1 {

  //客户端
  public static void main(String[] args) {

    GraphicEditor graphicEditor = new GraphicEditor();
    graphicEditor.drawShape(new Rectangle());
    graphicEditor.drawShape(new Circle());

    //绘制三角形
    graphicEditor.drawShape(new Triangle());

  }

}

/**
 * 图形绘制类 服务使用方
 */
class GraphicEditor{

  /**
   * 根据传入的类型 绘制不同图形
   * @param shape 传入的图形类型
   */
  public void drawShape(Shape shape){
    if(shape.mType == 1){
      drawRectangle(shape);
    } else if (shape.mType==2) {
      drawCircle(shape);
    } else if (shape.mType==3) {
      //新增绘制图形判断
      drawTriangle(shape);
    }


  }

  /**
   * 绘制 矩形的方法
   * @param shape 图形类
   */
  public void drawRectangle(Shape shape){
    System.out.println("绘制矩形 类型值:"+shape.mType);
  }

  /**
   * 绘制 圆形的方法
   * @param shape 图形类
   */
  public void drawCircle(Shape shape){
    System.out.println("绘制圆形 类型值:"+shape.mType);
  }

  /**
   * 新增 绘制三角形 绘制方法
   */
  public void drawTriangle(Shape shape){
    System.out.println("绘制三角形 类型值:"+shape.mType);
  }



}

/**
 * 图形基类  服务提供方
 */
class Shape{
  int mType;
}

/**
 * 矩形类 服务提供方
 */
class Rectangle extends Shape{
  public Rectangle() {
    super.mType=1;
  }
}

/**
 * 圆形类 服务提供方
 */
class Circle extends Shape{
  public Circle() {
    super.mType=2;
  }
}

/**
 * 新增图形 三角形 服务提供方
 */
class Triangle extends Shape{
  public Triangle() {
    super.mType=3;
  }
}

示例二

package com.learning.principle.ocp;



/**
 * 开闭原则 实例二
 * 将 Shape(服务提供方) 修改为 抽象类 并定义抽象方法 是其子类实现其方法
 * GraphicEditor2 (服务使用方) 只需要传入想绘制的图形,并调用图形的绘制方法,就可以实现功能的拓展
 *
 * 做到了 对扩展开放 对修改关闭
 *
 * @author nieshenglei
 */
public class Ocp2 {

  //客户端
  public static void main(String[] args) {

    GraphicEditor2 graphicEditor = new GraphicEditor2();
    graphicEditor.drawShape(new Rectangle2());
    graphicEditor.drawShape(new Circle2());

    //绘制三角形
    graphicEditor.drawShape(new Triangle2());

  }

}

/**
 * 图形绘制类 服务使用方
 */
class GraphicEditor2{

  /**
   * 根据传入的类型 绘制不同图形
   * @param shape 传入的图形类型
   */
  public void drawShape(Shape2 shape){
    shape.draw();
  }

}

/**
 * 图形基类  服务提供方
 */
abstract class Shape2{
  int mType;

  /**
   * 定义抽象方法
   */
  public abstract void draw();

}

/**
 * 矩形类 服务提供方
 */
class Rectangle2 extends Shape2{
  public Rectangle2() {
    super.mType=1;
  }

  /**
   * 定义抽象方法
   */
  @Override
  public void draw() {
    System.out.println("绘制 矩形 类型值:"+mType);
  }
}

/**
 * 圆形类 服务提供方
 */
class Circle2 extends Shape2{
  public Circle2() {
    super.mType=2;
  }

  /**
   * 定义抽象方法
   */
  @Override
  public void draw() {
    System.out.println("绘制 圆形 类型值:"+mType);
  }
}

/**
 * 新增图形 三角形 服务提供方
 */
class Triangle2 extends Shape2{
  public Triangle2() {
    super.mType=3;
  }

  /**
   * 定义抽象方法
   */
  @Override
  public void draw() {
    System.out.println("绘制三角形 类型值:"+mType);
  }
}

迪米特法则

定义:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

  • 通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。

  • 迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

  • 我们应该尽量降低与非直接朋友通信,而不是绝对不通信

示例一(不遵守规则)

package com.learning.principle.demeter;

import java.util.ArrayList;
import java.util.List;

/**
 * 迪米特原则 示例一
 *  违反了 迪米特原则 原因 以 SchoolManager类 分析 存在 非直接朋友 CollegeEmployee,Employee
 *
 * @author nieshenglei
 */
public class Demeter1 {

  /**
   * 客户端
   * @param args
   */
  public static void main(String[] args) {

    SchoolManager schoolManager = new SchoolManager();
    schoolManager.printAllEmployee(new CollegeManager());

  }

}


/**
 * 学校总部员工类
 */
class Employee {
  private String id;

  public void setId(String id) {
    this.id = id;
  }

  public String getId() {
    return id;
  }
}


/**
 * 学院员工类
 */
class CollegeEmployee {
  private String id;

  public void setId(String id) {
    this.id = id;
  }

  public String getId() {
    return id;
  }
}


/**
 * 学院管理者
 */
class CollegeManager {
  public List<CollegeEmployee> getAllEmployee() {
    List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
    for (int i = 0; i < 10; i++) {
      CollegeEmployee emp = new CollegeEmployee();
      emp.setId("学院员工id= " + i);
      list.add(emp);
    }
    return list;
  }
}


/**
 * 学校管理者
 *
 * 直接朋友
 *  方法参数   Employee,
 *  方法返回值 CollegeManager
 *
 * 非直接朋友
 *  局部变更 CollegeEmployee
 *
 *
 */
class SchoolManager {
  public List<Employee> getAllEmployee() {
    List<Employee> list = new ArrayList<Employee>();

    for (int i = 0; i < 5; i++) {
      Employee emp = new Employee();
      emp.setId("学校总部员工id= " + i);
      list.add(emp);
    }
    return list;
  }

  /**
   * 输出所有 人员信息
    * @param sub 学院管理者
   */
  void printAllEmployee(CollegeManager sub) {

    //输出学院员工信息
    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());
    }
  }
}

示例二(遵守规则)

package com.learning.principle.demeter;

import java.util.ArrayList;
import java.util.List;

/**
 * 迪米特原则 示例二
 *
 * 改进思路:
 * 以 SchoolManager1 类 为例,将其方法printAllEmployee() 关于 CollegeEmployee1
 * 输出 员工信息的代码 封装成 单独的方法 放入 CollegeEmployee1类中,在SchoolManager1 中直接调用
 *
 *
 * @author nieshenglei
 */
public class Demeter2 {

  /**
   * 客户端
   * @param args
   */
  public static void main(String[] args) {

    SchoolManager1 schoolManager = new SchoolManager1();
    schoolManager.printAllEmployee(new CollegeManager1());

  }

}


/**
 * 学校总部员工类
 */
class Employee1 {
  private String id;

  public void setId(String id) {
    this.id = id;
  }

  public String getId() {
    return id;
  }
}


/**
 * 学院员工类
 */
class CollegeEmployee1 {
  private String id;

  public void setId(String id) {
    this.id = id;
  }

  public String getId() {
    return id;
  }
}


/**
 * 学院管理者
 */
class CollegeManager1 {

  /**
   * 创建 员工
   * @return
   */
  public List<CollegeEmployee1> getAllEmployee() {
    List<CollegeEmployee1> list = new ArrayList<CollegeEmployee1>();
    for (int i = 0; i < 10; i++) {
      CollegeEmployee1 emp = new CollegeEmployee1();
      emp.setId("学院员工id= " + i);
      list.add(emp);
    }
    return list;
  }


    public void printEmployee(){
      //输出学院员工信息
      List<CollegeEmployee1> list1 = this.getAllEmployee();
      System.out.println("------------学院员工信息------------");
      for (CollegeEmployee1 e : list1) {
        System.out.println(e.getId());
      }
    }

}


/**
 * 学校管理者
 *
 * 直接朋友
 *  方法参数   Employee1
 *  方法返回值 CollegeManager1
 *
 */
class SchoolManager1 {
  public List<Employee1> getAllEmployee() {
    List<Employee1> list = new ArrayList<Employee1>();

    for (int i = 0; i < 5; i++) {
      Employee1 emp = new Employee1();
      emp.setId("学校总部员工id= " + i);
      list.add(emp);
    }
    return list;
  }

  /**
   * 输出所有 人员信息
    * @param sub 学院管理者
   */
  void printAllEmployee(CollegeManager1 sub) {

    sub.printEmployee();

    //输出学校总部信息
    List<Employee1> list2 = this.getAllEmployee();
    System.out.println("------------学校总部员工信息------------");
    for (Employee1 e : list2) {
      System.out.println(e.getId());
    }
  }
}

合成复用原则

定义

  • 尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。

  • 聚合has-A和组合contains-A。

  • 优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
    ollegeEmployee1> getAllEmployee() {
    List list = new ArrayList();
    for (int i = 0; i < 10; i++) {
    CollegeEmployee1 emp = new CollegeEmployee1();
    emp.setId("学院员工id= " + i);
    list.add(emp);
    }
    return list;
    }

    public void printEmployee(){
    //输出学院员工信息
    List list1 = this.getAllEmployee();
    System.out.println(“------------学院员工信息------------”);
    for (CollegeEmployee1 e : list1) {
    System.out.println(e.getId());
    }
    }

}

/**

  • 学校管理者
  • 直接朋友
  • 方法参数 Employee1
  • 方法返回值 CollegeManager1

*/
class SchoolManager1 {
public List getAllEmployee() {
List list = new ArrayList();

for (int i = 0; i < 5; i++) {
  Employee1 emp = new Employee1();
  emp.setId("学校总部员工id= " + i);
  list.add(emp);
}
return list;

}

/**

  • 输出所有 人员信息
    * @param sub 学院管理者
    */
    void printAllEmployee(CollegeManager1 sub) {
sub.printEmployee();

//输出学校总部信息
List<Employee1> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工信息------------");
for (Employee1 e : list2) {
  System.out.println(e.getId());
}

}
}




## 合成复用原则

**定义**

- 尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
- 聚合has-A和组合contains-A。
- 优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7-Moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值