开闭原则——举例说明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());
    }
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
举例说明沟通升级原则可以参考以下内容:在职场上,沟通升级原则是指在与他人进行沟通时,不仅要简洁明了地表达自己的观点和意见,还要通过总结规律、思维升华、认知迭代和行为升级等方法对沟通过程进行进一步提升和改进。 例如,假设我在写一篇文章时,我首先有感而发,遇到了一些职场问题,然后我提出解决这些问题的方法,并列出要点。接下来,我运用头脑风暴式的发散思维,将我能想到的所有解决方法都罗列出来。然后,我收集了各种理论和案例的素材,以丰富和完善我的观点。在整个过程,我根据沟通升级原则进行了思维的总结和反思,以及对下一步工作的规划和方法的思考。通过这种方式,我在沟通不断地提升自己的认知和行为,达到了沟通升级的目的。 另外,沟通升级原则还包括唯一性原则。在系统,代码应当尽量精简,避免重复编写相同或类似功能的代码。举例来说,假设我们在开发一个导出Excel文档的功能时,如果每一次都重复编写转换的规则,不仅增加了编写的工作量,而且还增加了后续维护的困难度。为了遵循唯一性原则,我们可以抽取方法来避免重复编写转换的代码,从而减少了重复带来的危害和维护工作的负担。因此,唯一性原则也是沟通升级原则的一部分,可以帮助我们在沟通提高效率和质量。 综上所述,沟通升级原则通过总结规律、思维升华、认知迭代和行为升级等方法来提升沟通的效果和质量。同时,唯一性原则也是沟通升级原则的一部分,通过避免重复编写相同或类似功能的代码来提高工作效率和降低维护成本。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [举例说明层次分析的三大原则_应对信息时代,自我赋能的7个原则](https://blog.csdn.net/weixin_39604092/article/details/109920796)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [高级程序员必会的程序设计原则 ——唯一性原则](https://blog.csdn.net/yry0304/article/details/125095562)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@素素~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值