【知场景,识用法】面向对象设计原则-单一职责、开闭原则、里氏替换、依赖倒置、迪米特(最少知道原则)、接口隔离

前言

设计模式简述
六种面向对象设计原则说明、场景示例:单一职责原则、开闭原则、里氏替换原则、依赖倒置原则、迪米特(最少知道原则)、接口隔离原则
根据在线课程学习的记录,有些例子有所调整,如有错误或不准确的地方,欢迎指正

一、设计模式

1. 概念

  • 一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结
  • 解决特定问题的通用模板
  • 一套针对特定的场景总结出来的解决方案

2. 解决什么问题

  • 创建对象:针对对象创建过程中遇到问题的解决方案
  • 继承、组合类:针对使用类的继承,组合过程中遇到问题的解决方案
  • 交互:针对对象之间交互过程程中遇到问题的解决方案

3. 三大类型

  • 创建类型
    • 更好、更优地创建类或对象
  • 结构型
    • 将类和对象组合,构建更好的结构
  • 行为型
    • 更好地实现类与类、对象与对象之间的通信(方法调用)

4. 设计模式和设计原则的关系

  • 理论——设计原则,实践——设计模式
  • 设计模式开始时,以原则为指导
  • 设计模式结束时,以原则来衡量

二、设计原则

设计思想:高内聚、低耦合

高内聚:一个模块或类的内部功能和职责是高度一致的

低耦合:模块或类之间的关系和联系的强度是低的

示例理解:企业划分多个部门,分工协作

1. 单一职责

1)定义

  • 一个类或者模块应当有且仅有一个引起它变化的原因
  • 单一:作用的类或模块
  • 职责:引起变化的原因

2)场景示例

支付中处理多种支付方式,如微信支付,支付宝支付,如果在同一个类中处理多种支付方式,当其中一种支付方式需要调整,可能会影响到其他支付方式的调用

  • 一个支付类中处理两种支付方式,不符合单一职责

    /**
         * 支付类
         */
        class Pay{
            /**
             * 付钱
             * @param type 支付类型
             */
            public void payMoney(String type) {
                if (Objects.equals(type, "wechat")) {
                    System.out.println("使用微信支付...");
                } else if (Objects.equals(type, "ali")) {
                    System.out.println("使用支付宝支付...");
                }
            }
        }
    
  • 优化

    /**
         * 支付接口
         */
        interface IPay {
            void payMoney();
        }
    
        /**
         * 微信支付
         */
        static class WechatPay implements IPay {
            @Override
            public void payMoney() {
                System.out.println("微信支付...");
            }
        }
        
        /**
         * 支付宝支付
         */
        static class AliPay implements IPay {
            @Override
            public void payMoney() {
                System.out.println("支付宝支付...");
            }
        }
    
  • 调用

    IPay pay = new WechatPay();
            pay.payMoney();
            pay = new AliPay();
            pay.payMoney();
    

3)优点

  • 降低类的复杂度
  • 提高代码的可读性
  • 提高代码的维护性
  • 降低变更引起的风险

2. 开闭原则

1)定义

  • 一个软件实体应当对扩展开放,对修改关闭
  • 开:应对变化
  • 闭:保持稳定

2)场景示例

汽车价格不会固定不变,比如当有促销时,则会进行打折,直接修改原获取价格方法,则可能影响到原本在用的功能

  • 初始获取价格

    /**
         * 汽车
         */
        class Car {
    
            double price;
    
            public Car(double price) {
                this.price = price;
            }
            
            /**
             * 获取价格
             */
            double getPrice() {
                // 打5折
                return this.price * 0.5;
            }
        }
    
  • 优化

    /**
         * 打折汽车
         */
        class DiscountCar extends Car {
            
            public DiscountCar(double price) {
                super(price);
            }
            
            @Override
            double getPrice() {
                return super.getPrice() * 0.5;
            }
        }
    
  • 调用

    Car car = new DiscountCar(100000);
    System.out.println("打折后价格:" + car.getPrice());
    

3)优点

  • 提高代码的可测性

  • 提高代码的可维护性

3. 里式替换

子类替换父类

1)定义

  • 派生类(子类)对象可以在程式中代替其基类(超类)对象
  • 替换:所有引用父类的地方都可以替换为子类
  • 一致:子类替换父类的程序逻辑保持一致

2)场景示例

四则运算类中包含加减乘除,父类中加法,而子类实现却覆盖成减法

  • 错误示例

    /**
         * 四则运算
         */
        class FourArithmeticOperations {
    
            /**
             * 加法
             *
             * @param a
             * @param b
             * @return
             */
            int add(int a, int b) {
                return a + b;
            }
    
            int minus(int a, int b) {
                return a - b;
            }
        }
    
        class Son extends FourArithmeticOperations {
            @Override
            int add(int a, int b) {
                return a - b;
            }
        }
    
  • 修正

    class Son extends FourArithmeticOperations {
        
            @Override
            int add(int a, int b) {
                return a + b;
            }
        }
    

3)优点

  • 保证行为的正确性
  • 提升代码的健壮性

4. 依赖倒置

细节依赖于抽象,抽象不依赖于细节

1)定义

  • 高层模块不应该依赖底层模块,两者都应该依赖其抽象
  • 抽象不依赖细节
  • 细节应该依赖于抽象
  • 面向接口编程

2)场景示例

拿到C1驾照后,可以开宝马轿车、奔驰轿车。司机和具体的某一品牌车不绑定,而是和准驾车绑定

  • 初始代码

    class Driver {
    
            void drivingBmw() {
                System.out.println("驾驶宝马汽车...");
            }
            void drivingBenz() {
                System.out.println("驾驶奔驰汽车...");
            }
        }
    
  • 优化

    interface ICar {
            /**
             * 开车
             */
            void drive();
        }
    
        static class BmwCar implements ICar {
            @Override
            public void drive() {
                System.out.println("驾驶宝马车...");
            }
        }
    
        static class BenzCar implements ICar {
            @Override
            public void drive() {
                System.out.println("驾驶奔驰车...");
            }
        }
    
  • 调用

    Driver driver = new Driver();
            driver.drive(new BmwCar());
    

3)优点

  • 降低耦合性
  • 提高稳定性
  • 减少并行开发带来的风险

5. 迪米特

最少知道原则

1)定义

  • 一个对象应当对其他对象尽可能少的了解
  • 不和陌生人说话
  • 只与直接的朋友通信

2)场景示例

租客和房东不直接交流,而是和中介交流;同理房东也是和中介交流

  • 有的租客和房东交流,有的租客和中介交流,若是同一套房子和中介、房东成交了,将出现问题

      /**
         * 房东
         */
        class HouseOwner {
    
            void bargain() {
                System.out.println("谈价格:1000元/月");
                System.out.println("花费时间:1周");
            }
        }
    
        /**
         * 中介
         */
        class Intermediary {
            void bargain() {
                System.out.println("谈价格:1200元/月");
                System.out.println("花费时间:1天");
            }
        }
    
        /**
         * 租客A
         */
        class TenantA {
            void bargain(){
                System.out.println("找房东...");
                System.out.println("找中介...");
            }
        }
    
        /**
         * 租客A
         */
        class TenantB {
            void bargain(){
                System.out.println("找中介...");
            }
        }
    
    

3)优点

  • 降低耦合性
  • 提高复用性

6. 接口隔离

建立单一接口

1)定义

  • 类之间的依赖关系应该建立在最小的接口
  • 不强迫使用不同的方法
  • 识别使用者的角色,设计小接口

2)场景示例

士兵中有开坦克攻击、开飞机轰炸,还有用枪突进,但是在进攻中每个士兵各司其职,并非又会开飞机又开坦克攻击

  • 初始

    interface ISoldier {
            /**
             * 开飞机轰炸
             */
            void bombingByPlane();
    
            /**
             * 开坦克碾压
             */
            void rollingWithTanks();
    
            /**
             * 开枪进攻
             */
            void shootWithGun();
        }
    
  • 优化:不同兵种抽象

     /**
         * 航空兵
         */
        interface AirArm {
            void bombingByPlane();
        }
    
        /**
         * 坦克兵
         */
        interface TankForce {
            void rollingWithTanks();
        }
    
        /**
         * 步兵
         */
        interface infantry {
            void shootWithGun();
        }
    

3)优点

  • 提高内聚,降低耦合
  • 提高系统的灵活性和维护性
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

芒果-橙

谢谢啦!

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

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

打赏作者

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

抵扣说明:

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

余额充值