设计模式-七大原则

本文详细探讨了面向对象设计的三大原则:单一职责原则强调每个类应有单一职责;接口隔离原则提倡最小接口依赖;依赖倒转原则倡导依赖抽象而非具体实现。通过实例代码解释了这些原则的应用及其好处,帮助开发者提高代码的可维护性和可扩展性。
摘要由CSDN通过智能技术生成

七大原则

  1. 单一职责原则
  2. 接口隔离原则
  3. 依赖倒转原则(DI)
  4. 里氏替换原则
  5. 开闭原则
  6. 迪米特法则
  7. 合成复用原则

单一职责

一轮上一个类只应该负责一个职责, 但可以有多个方法.
好处:

  1. 降低复杂度
  2. 降低变更引起的风险
  3. 提高可读性, 可维护性
  4. 通常在代码足够简单时在类级别遵循单一职责, 复杂的情况下为较少代码, 在方法级别上遵循单一职责原则.
/**
 * 单一职责原则1
 * 不遵循单一职责原则
 */
public class SingleResponsibility_1 {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();
        vehicle.run("摩托车");
        vehicle.run("汽车");

        // 轮船和飞机不能在公路上跑, 违反了单一职责原则
        // 解决办法: 分解成不同的交通工具
        vehicle.run("轮船");
        vehicle.run("飞机");
    }
}

// 交通工具类
class Vehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上运行...");
    }
}
/**
 * 单一职责原则2
 * 1. 遵循单一职责原则
 * 2. 花销很大, 有一种交通工具就要创建一个类, 同时要修改客户端
 */
public class SingleResponsibility_2 {
    public static void main(String[] args) {
        RoadVehicle roadVehicle = new RoadVehicle();
        roadVehicle.run("摩托车");
        roadVehicle.run("汽车");

        AirVehicle airVehicle = new AirVehicle();
        airVehicle.run("飞机");

        SeaVehicle seaVehicle = new SeaVehicle();
        seaVehicle.run("轮船");
    }
}

// 路上跑的交通工具
class RoadVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在公路上跑...");
    }
}

// 天上飞的交通工具
class AirVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在天空上飞...");
    }
}

// 海里的交通工具
class SeaVehicle {
    public void run(String vehicle) {
        System.out.println(vehicle + " 在海里游...");
    }
}
/**
 * 单一职责原则3
 * 1. 修改较小
 *  2. 虽然没有在类级别上遵循单一职责原则, 但是在方法级别上遵循单一职责原则
 */
public class SingleResponsibility_3 {
    public static void main(String[] args) {
        Vehicle3 vehicle = new Vehicle3();
        vehicle.runRoad("摩托车");
        vehicle.runRoad("汽车");

        vehicle.runAir("飞机");

        vehicle.runSea("轮船");
    }
}

// 交通工具
class Vehicle3 {
    public void runRoad(String vehicle) {
        System.out.println(vehicle + " 在公路上跑...");
    }

    public void runAir(String vehicle) {
        System.out.println(vehicle + " 在天上飞...");
    }

    public void runSea(String vehicle) {
        System.out.println(vehicle + " 在海里游泳...");
    }
}

接口隔离原则

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

package com.mine.segregation;

/**
 * 接口隔离原则1
 * A类通过Interface1接口实现类B, 只会用到1,2,3三个方法
 * C类通过Interface1接口实现类D, 只会用到1,4,5三个方法
 * 1. 违反接口隔离原则
 */
public class InterfaceSegregation_1 {

}

interface Interface1 {
    void operation1();
    void operation2();
    void operation3();
    void operation4();
    void operation5();
}

/**
 * 通过接口Inteface1依赖B, 但是只会用到1,2,3三个方法
 */
class A {
    public void depend1(Interface1 interface1) {
        interface1.operation1();
    }
    public void depend2(Interface1 interface1) {
        interface1.operation2();
    }
    public void depend3(Interface1 interface1) {
        interface1.operation3();
    }
}
class B implements Interface1 {

    @Override
    public void operation1() {
        System.out.println("B 实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("B 实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("B 实现了operation3");
    }

    @Override
    public void operation4() {
        System.out.println("B 实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("B 实现了operation5");
    }
}

/**
 * 通过接口Inteface1依赖D, 但是只会用到1,4,5三个方法
 */
class C {
    public void depend1(Interface1 interface1) {
        interface1.operation1();
    }
    public void depend4(Interface1 interface1) {
        interface1.operation4();
    }
    public void depend5(Interface1 interface1) {
        interface1.operation5();
    }
}
class D implements Interface1 {
    @Override
    public void operation1() {
        System.out.println("D 实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("D 实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("D 实现了operation3");
    }

    @Override
    public void operation4() {
        System.out.println("D 实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("D 实现了operation5");
    }
}

package com.mine.segregation;

/**
 * 接口隔离原则2
 * AA类通过InterfaceB接口实现类BB, 只会用到1,2,3三个方法
 * CC类通过InterfaceD接口实现类DD, 只会用到1,4,5三个方法
 */
public class InterfaceSegregation_2 {

    public static void main(String[] args) {
        AA aa = new AA();
        final BB bb = new BB();
        aa.depend1(bb);
        aa.depend2(bb);
        aa.depend3(bb);

        CC cc = new CC();
        final DD dd = new DD();
        cc.depend1(dd);
        cc.depend4(dd);
        cc.depend5(dd);
    }
}

interface Interface11 {
    void operation1();
}

interface InterfaceB extends Interface11 {
    void operation1();
    void operation2();
    void operation3();
}

interface InterfaceD extends Interface11 {
    void operation1();
    void operation4();
    void operation5();
}

/**
 * 通过接口IntefaceB依赖BB, 但是只会用到1,2,3三个方法
 */
class AA {
    public void depend1(InterfaceB interfaceB) {
        interfaceB.operation1();
    }
    public void depend2(InterfaceB interfaceB) {
        interfaceB.operation2();
    }
    public void depend3(InterfaceB interfaceB) {
        interfaceB.operation3();
    }
}
class BB implements InterfaceB {

    @Override
    public void operation1() {
        System.out.println("BB 实现了operation1");
    }

    @Override
    public void operation2() {
        System.out.println("BB 实现了operation2");
    }

    @Override
    public void operation3() {
        System.out.println("BB 实现了operation3");
    }
}

/**
 * 通过接口IntefaceD依赖DD, 但是只会用到1,4,5三个方法
 */
class CC {
    public void depend1(InterfaceD interfaceD) {
        interfaceD.operation1();
    }
    public void depend4(InterfaceD interfaceD) {
        interfaceD.operation4();
    }
    public void depend5(InterfaceD interfaceD) {
        interfaceD.operation5();
    }
}
class DD implements InterfaceD {
    @Override
    public void operation1() {
        System.out.println("DD 实现了operation1");
    }

    @Override
    public void operation4() {
        System.out.println("DD 实现了operation4");
    }

    @Override
    public void operation5() {
        System.out.println("DD 实现了operation5");
    }
}

依赖倒转原则(DI)

  1. 高层模块不应该依赖低层模块. 二者都应该依赖其抽象
  2. 抽象不应该依赖细节, 细节应该依赖抽象
  3. 依赖倒转的中心思想是面向接口编程

java中抽象指的是接口或者抽象类, 细节指的是具体的实现类, 依赖倒转的目的是制定好规范, 提高稳定性

依赖的三种方式:

通过接口依赖
通过构造器依赖
通过setter方法依赖

package com.mine.principle.dependencyInversion;

/**
 * 依赖倒转原则1
 * 需求: 用户接收消息
 * 1. 不遵循依赖倒转原则
 * 2. 如果要接收短信或者微信等消息, 要新增加类, 同时person也要新增加方法
 *
 * 解决方案: 创建一个接口, email, 微信, 短信等依赖这个接口
 */
public class DependencyInversion_1 {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
    }
}

class Person {
    public void receive(Email email) {
        System.out.println(email.getInfo());
    }
}

class Email {
    public String getInfo() {
        return "电子邮件信息: hello world!";
    }
}

package com.mine.principle.dependencyInversion;

/**
 * 依赖倒转原则1
 * 需求: 用户接收消息
 */
public class DependencyInversion_2 {
    public static void main(String[] args) {
        Person2 person2 = new Person2();
        person2.receive(new Email2());
        person2.receive(new Weixin2());
    }
}

class Person2 {
    public void receive(Message message) {
        System.out.println(message.getInfo());
    }
}

abstract class Message {
    abstract String getInfo();
}

class Email2 extends Message {
    @Override
    public String getInfo() {
        return "电子邮件信息: hello world!";
    }
}

class Weixin2 extends Message {
    @Override
    public String getInfo() {
        return "微信信息: hello weixin!";
    }
}

里氏替换原则

继承带来便利的同时也带来了很多弊端, 类之间的耦合, 父类做修改, 必须考虑所有子类是否有问题. 如何正确的使用继承=>里氏替换原则

  1. 子类尽量不去重写父类的方法.
  2. 继承实际上增加了两个类的耦合, 可以通过聚合, 组合, 依赖来解决问题.
package com.mine.principle.liskov;

/**
 * 里氏替换原则
 * 1. 不遵循历史替换原则
 */
public class Liskov_1 {
    public static void main(String[] args) {
        B b = new B();
        System.out.println(b.func1(2, 1));
        System.out.println(b.func2(2, 1));
    }
}

class A {
    public int func1(int a, int b) {
        return a - b;
    }
}

class B extends A {
    public int func1(int a, int b) {
        return a + b;
    }

    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
}

package com.mine.principle.liskov;

/**
 * 里氏替换原则
 * 1. 不遵循历史替换原则
 */
public class Liskov_2 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb.func1(2, 1));
        System.out.println(bb.func2(2, 1));
    }
}

class Base {

}

class AA extends Base {
    public int func1(int a, int b) {
        return a - b;
    }
}

class BB extends Base {
    // 组合方式
    AA aa = new AA();

    public int func1(int a, int b) {
        return a + b;
    }

    // 这里使用AA的func1方法
    public int func2(int a, int b) {
        return func3(a, b) + 9;
    }


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

开闭原则

  1. 一个软件实体如类, 模块, 方法应该对拓展开放(提供方), 修改关闭(使用方). 用抽象构建框架, 用实现拓展细节.
  2. 一个软件功能变化时, 应该用拓展类来实现变化, 而不是修改原有代码.
  3. 编程中遵循其他原则或者使用设计模式, 最终都是为了实现开闭原则.
package com.mine.principle.openClose;

/**
 * 开闭原则
 * 1. 不遵循开闭原则
 * 2. 比如现在增加一个画三角形的方法, 修改的地方比较多
 */
public class OpenClose_1 {
    public static void main(String[] args) {
        final GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());

        graphicEditor.drawShape(new Circle());

        graphicEditor.drawTriangle(new Triangle());
    }
}

// 画图工具类(使用方)
class GraphicEditor {
    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) {
            // 3
            drawTriangle(s);
        }
    }

    public void drawRectangle(Shape s) {
        System.out.println("矩形");
    }

    public void drawCircle(Shape s) {
        System.out.println("圆形");
    }

    // 2
    public void drawTriangle(Shape s) {
        System.out.println("三角形");
    }
}

// 一个基类
class Shape {
    int m_type;
}

class Rectangle extends Shape {
    Rectangle() {
        super.m_type = 1;
    }
}

class Circle extends Shape {
    Circle() {
        super.m_type = 2;
    }
}

// 1 新增画三角形
class Triangle extends Shape {
    Triangle() {
        super.m_type = 3;
    }
}

package com.mine.principle.openClose;

/**
 * 开闭原则
 * 遵循开闭原则
 */
public class OpenClose_2 {
    public static void main(String[] args) {
        final GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());

        graphicEditor.drawShape(new Circle());

        graphicEditor.drawShape(new Triangle());
    }
}

// 画图工具类(使用方)
class GraphicEditor {
    public void drawShape(Shape s) {
        s.draw();
    }
}

// 一个基类 改成抽象类
abstract class Shape {

    abstract void draw();
}

class Rectangle extends Shape {

    @Override
    void draw() {
        System.out.println("矩形");
    }
}

class Circle extends Shape {

    @Override
    void draw() {
        System.out.println("圆形");
    }
}

// 1 新增画三角形
class Triangle extends Shape {

    @Override
    void draw() {
        System.out.println("三角形");
    }
}

迪米特法则

  1. 一个对象应该对另外一个对象保持最少的了解.
  2. 类与类之间越密切, 耦合度就越高
  3. 迪米特法则又叫最少知道法则, 即一个类对自己依赖的类知道的越少越好.
  4. 只与直接朋友通讯, 直接朋友包括方法参数, 返回值, 成员变量, 方法中的局部变量不是直接朋友.
package com.mine.principle.demeter;

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

/**
 * 迪米特法则
 * 1. 不遵循迪米特法则
 */
public class Demeter_1 {
    public static void main(String[] args) {
        SchoolManager manager = new SchoolManager();
        CollegeManager collegeManager = new CollegeManager();
        manager.printAllEmployee(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 String getId() {
        return id;
    }

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

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

        return list;
    }
}

// 学校管理类
class SchoolManager {
    // 学校总部的员工
    public List<Employee> getAllEmployee() {
        List<Employee> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Employee employee = new Employee();
            employee.setId("学校员工id=> " + i);
            list.add(employee);
        }

        return list;
    }

    // 打印总部和学院的所有员工
    void printAllEmployee(CollegeManager collegeManager) {
        System.out.println("============分公司员工============");
        // CollegeEmployee是局部变量, 不是CollegeManager的直接朋友, 不遵循迪米特法则
        List<CollegeEmployee> list1 = collegeManager.getAllEmployee();
        list1.forEach(System.out::println);

        System.out.println("============总部员工============");
        List<Employee> list2 = getAllEmployee();
        list2.forEach(System.out::println);
    }
}

package com.mine.principle.demeter;

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

/**
 * 迪米特法则
 * 1. 遵循迪米特法则
 */
public class Demeter_2 {
    public static void main(String[] args) {
        SchoolManager2 manager = new SchoolManager2();
        CollegeManager2 collegeManager = new CollegeManager2();
        manager.printAllEmployee(collegeManager);
    }
}

// 学校总部员工
class Employee2 {
    private String id;

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

    public String getId() {
        return id;
    }
}

// 学院员工
class CollegeEmployee2 {
    private String id;

    public String getId() {
        return id;
    }

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

// 管理学院员工的类
class CollegeManager2 {
    public List<CollegeEmployee2> getAllEmployee() {
        List<CollegeEmployee2> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            CollegeEmployee2 employee = new CollegeEmployee2();
            employee.setId("学院员工id=> " + i);
            list.add(employee);
        }

        return list;
    }

    void printCollegeEmployee() {
        System.out.println("============分公司员工============");
        // CollegeEmployee是局部变量, 不是CollegeManager的直接朋友, 不遵循迪米特法则
        List<CollegeEmployee2> list = getAllEmployee();
        list.forEach(System.out::println);
    }
}

// 学校管理类
class SchoolManager2 {
    // 学校总部的员工
    public List<Employee2> getAllEmployee() {
        List<Employee2> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Employee2 employee = new Employee2();
            employee.setId("学校员工id=> " + i);
            list.add(employee);
        }

        return list;
    }

    // 打印总部和学院的所有员工
    void printAllEmployee(CollegeManager2 collegeManager) {
        System.out.println("============分公司员工============");
        // CollegeEmployee是局部变量, 不是CollegeManager的直接朋友, 不遵循迪米特法则
        collegeManager.printCollegeEmployee();

        System.out.println("============总部员工============");
        List<Employee2> list2 = getAllEmployee();
        list2.forEach(System.out::println);
    }
}

合成复用原则

  1. 尽量使用合成/聚合的方式, 而不是继承
  2. 依赖: 方法参数引入依赖的对象
  3. 组合: 成员变量移入依赖的对象, 构造器引入依赖
  4. 聚合: 成员变量移入依赖的对象, setter方法引入依赖
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值