IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 开闭原则——举例说明Java设计模式中的开闭原则 -> 正文阅读

[Java知识库]开闭原则——举例说明Java设计模式中的开闭原则

1.前言

1.1 官方定义

  • 开闭原则(Open Close Principle),俗称OCP原则,是Java世界里最基础的设计原则, 它指导我们如何建立一个稳定的、 灵活的系统。
  • 怎么定义开闭原则呢?
    定义:一个软件实体类、 模块和函数应该对扩展开放、对修改关闭,用抽象构建框架,用实现扩展细节!
  • 怎么理解定义?
    意思就是说,当软件需要变化时,一个软件实体应该尽量通过扩展来实现变化, 而不是通过修改已有的代码来实现变化。
  • 软实体是?
    项目或软件产品中按照一定的逻辑规则划分的模块、类、函数(方法)。

1.2 本文案例的业务场景

2.举例说明

2.1 正例(正在使用的业务场景)

  • 如果看了上面的依赖倒置原则,这个例子可以跳过了,就是用抽象类优化后的正例。

(1)类图

在这里插入图片描述

(2)代码说明

在这里插入图片描述
在这里插入图片描述

(3)测试

在这里插入图片描述

(4)简单分析

  • 可以看到目前代码如果新增饲养小羊或者小猪的话,直接新增一个猪成长过程的实体类即可,不用修改 FamilyFarm 类,这是我们上篇说的抽象不应该依赖细节,细节应该依赖抽象的依赖倒置原则,不明白的小伙伴可以先看上篇案例的讲解!

2.2 反例(在2.1上新增需求后的反例代码)

2.2.1 新增需求内容

  • 但是我们现在需求升级了,不再新增饲养小羊或者🐖🐖了,请看下面需求:
  • 我们想对根据宠物的年龄进行判断要不要饲养,以下是两种情况的需求
    需求1:宠物年龄不超过2岁的可以饲养员会领养
    需求2:狗狗的年龄不超过1岁,小猫的年龄不超过2岁

2.2.2 针对两个需求的反例代码

(1)针对需求1的

  • 类图:—>到这种程度了,其实看不看都可以,代码也是一目了然的,我还是放上吧
    在这里插入图片描述
  • 代码如下:
    在这里插入图片描述
    在这里插入图片描述
  • 测试:
    在这里插入图片描述
  • 好了,改为之后感觉代码动的也没什么问题,功能也实现了,别急,我们看完完需求2拿来一起分析

(2)针对需求2的

  • 代码如下:
    在这里插入图片描述
    在这里插入图片描述
  • 测试:
    在这里插入图片描述
  • 好了,改为之后感觉代码动的也是没什么问题,功能也实现了,我们接下来来说一说

2.2.3 代码说明

  • 看完之后如果你觉得两个需求完成的感觉都还可以,朋友请加油!
  • 看着不错,挺好呀,没啥问题呀,代码也不多,那问题是?先来分析:
    **需求1:**我们是针对所有宠物的年龄都是1的控制,而现实是业务很少这么提需求,因为每种宠物不一样,像狗狗大家肯定喜欢从小养起,像羊呀牛呀,肯定大了好呀,为啥,所以年龄很大可能不一样,即便一样,也是前期需求,后续改动的可能性很大;
    需求2:你可以理解需求2就是在需求1的基础上,业务优化了需求,而你根据需求1直接改动了代码,如果需求2不是你开发的,后续假如是一个盲从的码农,也是你的思路带着他像上面的代码那样开发,不动脑子的面向业务实现功能开发!
  • 问题现在是什么你看出来吗?
    ① 如果现在有饲养了羊呀,猪呀,牛呀,需求1实现的代码被否定了,因为前期上线的只有狗和猫,猪羊牛的需求可能没有年龄限制!你还得改动 FamilyFarm 类的代码,你看新增需求还要改动和需求没关系的已经上线的代码,我就问你烦不烦,关键是你这个改动的需求点(关于年龄的)后续可能会经常维护,这种很可能会变动的,这是重点!!!
    ② 如果后期猪呀羊呀牛呀兔呀……都有不同的年龄现在,你的 if else 判断打算写多长,耦合性考虑了没有,等你自己看不下去代码又不想优化的时候,你辞职拍屁股走人了,你屎一样的代码还得别人给你刷屁股!!!
  • 那怎么改?原则是什么?
    如果你理解依赖倒置原则的话,其实是一样的道理,新增功能尽量避免动已经实现的代码,所以说是对扩展开发,对修改关闭
    你也可以这么理解,FamilyFarm 类的 raisePet方法好不容易是别人优化好的,你用了之后不满足你小小的需求而已,你就又干掉了规范,你就想想别人看你这么干什么心情吧!我是给你用的,不是给你改的,不满足你你扩展呀,修改的权力是我,NO You!!
  • 好了,我练习一下打字,废话说了这么多应该理解了吧!怎么改呢?往下看,其实很简单!

2.2.4 简单分析

2.3 正例(解决2.2的问题)

(1)类图

在这里插入图片描述

  • 看完类图,你可能有点懵逼,怎么 FamilyFarm 类的方法变成 isCanBeRaised 了,先看看代码吧,估计看完代码你还笑呢,我说的是呵呵

(2)代码说明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 再来看最后一处改动
    在这里插入图片描述
  • 你改不会想讽刺说不是不修改这个 FamilyFarm 类吗,还修改这么多?灵活什么是灵活,是尽量不修改,就拿这个需求来说,具体实现类里,有3个方法,我总不能一个一个来判断吧,所以就合了,再说了 写个FamilyFarm 的人只让你用不让你修改,你可以找他协商呀,总比你一个方法一个方法判断年龄好,那后续再有这个点上的需求变动是不是就不修改FamilyFarm 了!
  • 这也可以说前期如果这么设计会更好,既然是饲养,直接考虑到饲养条件,给一个方法即可!
  • 而且,公司项目框架为啥总是重构,从ssh到dubbo再到cloud,这是架构上的一个优化,能说以前的代码不好?不全是,只是不适用了而已,所以不得不动,而不是随意乱动!!

(3)测试

在这里插入图片描述

3.总结

  • 好了,我上面说的便于理解但过于啰嗦,咱来看看官方语言的总结!

3.1 作用

  • 对软件测试的影响软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。
  • 可以提高代码的可复用性粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。
  • 可以提高软件的可维护性遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。

3.2 怎么使用?

  • 可以通过“抽象约束”来实现开闭原则
  • “封装变化”来实现开闭原则
    对变化的封装包含两层含义: 第一, 将相同的变化封装到一个接口或抽象类中; 第二,将不同的变化封装到不同的接口或抽象类中, 不应该有两个不同的变化出现在同一个接口或抽象类中。 封装变化, 也就是受保护的变化(protected variations) , 找出预计有变化或不稳定的点, 我们为这些变化点创建稳定的接口, 准确地讲是封装可能发生的变化, 一旦预测到或“第六感”发觉有变化, 就可以进行封装。
  • 一句话就是,通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
  • 当然,编程规范很重要,约束自己约束团队,制定项目章程

3.3 总结

  • 通过接口或者抽象的方式将功能拓展出去,达到程序适应多样性的运行
  • 避免修改内部代码,导致引用的部分代码功能无法使用实在运行奔溃等灾难性问题
  • 编程中,ocp原则是核心,所有原则都是为了实现ocp原则!
  • 好了,总结就到这里吧,最近本来很是郁闷,写起文章感觉哪有时间郁闷,看来忙起来也是一副治心病的良药,所以遛完麦兜就回来分享来了!

4.附代码

第一个例子

package com.liu.susu.principle.ocp.example1;

/**
 * @FileName FamilyFarm
 * @Description 使用 依赖倒置原则 优化后的代码--->将作为开闭原则的一个正在使用的业务场景
 * @Author susu
 * @date 2022-02-13
 **/
public class FamilyFarm {

    public void raisePet(petGrowthProcess petGrowthProcess){
        petGrowthProcess.petBorn();
        petGrowthProcess.petGrowUp();
        petGrowthProcess.petBeRaised();
    }
}

abstract class petGrowthProcess{
    abstract void petBorn();
    abstract void petGrowUp();
    abstract void petBeRaised();
}

class DogGrowthProcess extends petGrowthProcess{
    public void petBorn(){
        System.out.println("狗狗-->麦兜出生了……");
    }
    public void petGrowUp(){
        System.out.println("狗狗-->麦兜长大了……");
    }
    public void petBeRaised(){
        System.out.println("狗狗-->麦兜被饲养员带走了……");
    }
}

class CatGrowthProcess extends petGrowthProcess{
    public void petBorn(){
        System.out.println("小猫-->阿苔出生了……");
    }
    public void petGrowUp(){
        System.out.println("小猫-->阿苔长大了……");
    }
    public void petBeRaised(){
        System.out.println("小猫-->阿苔被饲养员带走了……");
    }
}

class ClientTest{
    public static void main(String[] args) {
        FamilyFarm familyFarm = new FamilyFarm();
        //饲养狗狗
        familyFarm.raisePet(new DogGrowthProcess());
        //饲养小猫
        familyFarm.raisePet(new CatGrowthProcess());
    }
}

第二例子

package com.liu.susu.principle.ocp.example2;

/**
 * @FileName FamilyFarm
 * @Description 在案例1的情况下新增需求后的反例
 *              需求1:被领养宠物的条件是,年龄不超过1岁
 * @Author susu
 * @date 2022-02-13
 **/
public class FamilyFarm {

    public void raisePet(petGrowthProcess petGrowthProcess){
        petGrowthProcess.petBorn();
        petGrowthProcess.petGrowUp();
        petGrowthProcess.petBeRaised();
    }

    //新增方法,根据宠物的年龄 判断要不要被饲养
    public void isCanBeRaised(petGrowthProcess petGrowthProcess){
        if (petGrowthProcess.age<=2){
            System.out.println("小猫-->"+petGrowthProcess.name+"的年龄是"+petGrowthProcess.age
                    +",是饲养员最喜欢的年龄段……");
            raisePet(petGrowthProcess);
        }else {
            System.out.println("小猫-->"+petGrowthProcess.name+"的年龄是"+petGrowthProcess.age
                    +",饲养员想考虑一下年龄小点的、顽皮的宠物");
        }
    }
}

abstract class petGrowthProcess{
    String name;
    int age ;
    abstract void petBorn();
    abstract void petGrowUp();
    abstract void petBeRaised();
}
class DogGrowthProcess extends petGrowthProcess{
    DogGrowthProcess(){
        super.name="麦兜";
        super.age=3;
    }
    public void petBorn(){
        System.out.println("狗狗-->麦兜出生了……");
    }
    public void petGrowUp(){
        System.out.println("狗狗-->麦兜长大了……");
    }
    public void petBeRaised(){
        System.out.println("狗狗-->麦兜被饲养员带走了……");
    }
}
class CatGrowthProcess extends petGrowthProcess{
    CatGrowthProcess(){
        super.name="阿苔";
        super.age=1;
    }
    public void petBorn(){
        System.out.println("小猫-->阿苔出生了……");
    }
    public void petGrowUp(){
        System.out.println("小猫-->阿苔长大了……");
    }
    public void petBeRaised(){
        System.out.println("小猫-->阿苔被饲养员带走了……");
    }
}

class ClientTest{
    public static void main(String[] args) {
        FamilyFarm familyFarm = new FamilyFarm();
        //饲养狗狗
        familyFarm.isCanBeRaised(new DogGrowthProcess());
        //饲养小猫
        familyFarm.isCanBeRaised(new CatGrowthProcess());
    }
}

第三个例子

package com.liu.susu.principle.ocp.example3;

/**
 * @FileName FamilyFarm
 * @Description 在案例1的情况下新增需求后的反例
 *              需求2:被领养宠物的条件是,狗狗年龄不超过1岁,小猫年龄不超过2岁
 * @Author susu
 * @date 2022-02-13
 **/
public class FamilyFarm {
    public void raisePet(petGrowthProcess petGrowthProcess){
        petGrowthProcess.petBorn();
        petGrowthProcess.petGrowUp();
        petGrowthProcess.petBeRaised();
    }
    //新增方法,根据宠物的年龄 判断要不要被饲养
    public void isCanBeRaised(petGrowthProcess petGrowthProcess){
        if(petGrowthProcess instanceof DogGrowthProcess){
            if (petGrowthProcess.age<=1){
                System.out.println("狗狗-->"+petGrowthProcess.name+"的年龄是"+petGrowthProcess.age+",是饲养员最喜欢的年龄段……");
                raisePet(petGrowthProcess);
            }else {
                System.out.println("狗狗-->"+petGrowthProcess.name+"-->的年龄是"+petGrowthProcess.age+",饲养员想考虑一下年龄小点的、顽皮的宠物");
            }
        }else if (petGrowthProcess instanceof CatGrowthProcess){
            if (petGrowthProcess.age<=2){
                System.out.println("小猫-->"+petGrowthProcess.name+"的年龄是"+petGrowthProcess.age+",是饲养员最喜欢的年龄段……");
                raisePet(petGrowthProcess);
            }else {
                System.out.println("小猫-->"+petGrowthProcess.name+"的年龄是"+petGrowthProcess.age+",饲养员想考虑一下年龄小点的、顽皮的宠物");
            }
        }
    }

}

abstract class petGrowthProcess{
    String name;
    int age ;
    abstract void petBorn();
    abstract void petGrowUp();
    abstract void petBeRaised();
}
class DogGrowthProcess extends petGrowthProcess{
    DogGrowthProcess(){
        super.name="麦兜";
        super.age=3;
    }
    public void petBorn(){
        System.out.println("狗狗-->麦兜出生了……");
    }
    public void petGrowUp(){
        System.out.println("狗狗-->麦兜长大了……");
    }
    public void petBeRaised(){
        System.out.println("狗狗-->麦兜被饲养员带走了……");
    }
}
class CatGrowthProcess extends petGrowthProcess{
    CatGrowthProcess(){
        super.name="阿苔";
        super.age=1;
    }
    public void petBorn(){
        System.out.println("小猫-->阿苔出生了……");
    }
    public void petGrowUp(){
        System.out.println("小猫-->阿苔长大了……");
    }
    public void petBeRaised(){
        System.out.println("小猫-->阿苔被饲养员带走了……");
    }
}

class ClientTest{
    public static void main(String[] args) {
        FamilyFarm familyFarm = new FamilyFarm();
        //饲养狗狗
        familyFarm.isCanBeRaised(new DogGrowthProcess());
        //饲养小猫
        familyFarm.isCanBeRaised(new CatGrowthProcess());
    }
}

第四个例子

package com.liu.susu.principle.ocp.example4;

/**
 * @FileName FamilyFarm
 * @Description 正例——————opc原则优化
 *              需求2:被领养宠物的条件是,狗狗年龄不超过1岁,小猫年龄不超过2岁
 * @Author susu
 * @date 2022-02-13
 **/
public class FamilyFarm {
//    public void raisePet(petGrowthProcess petGrowthProcess){
//        petGrowthProcess.petBorn();
//        petGrowthProcess.petGrowUp();
//        petGrowthProcess.petBeRaised();
//    }
    public void isCanBeRaised (petGrowthProcess petGrowthProcess){
        petGrowthProcess.isCanBeRaised();
    }

}

abstract class petGrowthProcess{
    String name;
    int age ;
    abstract void petBorn();
    abstract void petGrowUp();
    abstract void petBeRaised();
    abstract void isCanBeRaised();
}

class DogGrowthProcess extends petGrowthProcess{
    DogGrowthProcess(){
        super.name="麦兜";
        super.age=3;
    }
    public void isCanBeRaised(){
        if (this.age<=1){
            System.out.println("狗狗-->"+this.name+"的年龄是"+this.age+",是饲养员最喜欢的年龄段……");
            petBorn();
            petGrowUp();
            petBeRaised();
        }else {
            System.out.println("狗狗-->"+this.name+"-->的年龄是"+this.age+",饲养员想考虑一下年龄小点的、顽皮的宠物");
        }
    }
    public void petBorn(){
        System.out.println("狗狗-->麦兜出生了……");
    }
    public void petGrowUp(){
        System.out.println("狗狗-->麦兜长大了……");
    }
    public void petBeRaised(){
        System.out.println("狗狗-->麦兜被饲养员带走了……");
    }
}

class CatGrowthProcess extends petGrowthProcess{
    CatGrowthProcess(){
        super.name="阿苔";
        super.age=1;
    }
    public void isCanBeRaised(){
        if (this.age<=1){
            System.out.println("小猫-->"+this.name+"的年龄是"+this.age+",是饲养员最喜欢的年龄段……");
            petBorn();
            petGrowUp();
            petBeRaised();
        }else {
            System.out.println("小猫-->"+this.name+"-->的年龄是"+this.age+",饲养员想考虑一下年龄小点的、顽皮的宠物");
        }
    }
    public void petBorn(){
        System.out.println("小猫-->阿苔出生了……");
    }
    public void petGrowUp(){
        System.out.println("小猫-->阿苔长大了……");
    }
    public void petBeRaised(){
        System.out.println("小猫-->阿苔被饲养员带走了……");
    }
}

class ClientTest{
    public static void main(String[] args) {
        FamilyFarm familyFarm = new FamilyFarm();
        //饲养狗狗
        familyFarm.isCanBeRaised(new DogGrowthProcess());
        //饲养小猫
        familyFarm.isCanBeRaised(new CatGrowthProcess());
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 20:59:25  更:2022-02-14 21:00:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:31:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码