《设计模式》——开闭原则

一、什么是开闭原则

对修改关闭,对扩展开放。比如有一个书城,售卖书籍有原价,现在要新增一个打折价。那么,一定要保证已有功能不被修改破坏,而是把新功能扩展出来,不要影响原有功能,而是把新功能扩展出来,不要动源代码,可以自己写一个类,继承原来的类。也就是能实现原价功能,又能扩展新增的打折价格功能。

二、为什么使用开闭原则

第一:开闭原则非常有名,只要是面向对象编程,在开发时都会强调开闭原则

第二:开闭原则是最基础的设计原则,其它的五个设计原则都是开闭原则的具体形态,也就是说其它的五个设计原则是指导设计的工具和方法,而开闭原则才是其精神领袖。依照java语言的称谓,开闭原则是抽象类,而其它的五个原则是具体的实现类。

第三:开闭原则可以提高复用性
在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来,不是在一个类中独立实现一个业务逻辑。只有这样的代码才可以复用,粒度越小,被复用的可能性越大。那为什么要复用呢?减少代码的重复,避免相同的逻辑分散在多个角落,减少维护人员的工作量。那怎么才能提高复用率呢?缩小逻辑粒度,直到一个逻辑不可以分为止。

第四:开闭原则可以提高维护性
一款软件量产后,维护人员的工作不仅仅对数据进行维护,还可能要对程序进行扩展,维护人员最乐意的事是扩展一个类,而不是修改一个类。让维护人员读懂原有代码,再进行修改,是一件非常痛苦的事情,不要让他在原有的代码海洋中游荡后再修改,那是对维护人员的折磨和摧残。
第五:面向对象开发的要求
万物皆对象,我们要把所有的事物抽象成对象,然后针对对象进行操作,但是万物皆发展变化,有变化就要有策略去应对,怎么快速应对呢?这就需要在设计之初考虑到所有可能变化的因素,然后留下接口,等待“可能”转变为“现实”。

三、如何使用开闭原则

第一:抽象约束
抽象是对一组事物的通用描述,没有具体的实现,也就表示它可以有非常多的可能性,可以跟随需求的变化而变化。因此,通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:

通过接口或抽象类约束扩散,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。
参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求
抽象层尽量保持稳定,一旦确定就不要修改
第二:元数据(metadata)控件模块行为
编程是一个很苦很累的活,那怎么才能减轻压力呢?答案是尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗的说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

第三:制定项目章程
在一个团队中,建立项目章程是非常重要的,因为章程是所有人员都必须遵守的约定,对项目来说,约定优于配置。这比通过接口或抽象类进行约束效率更高,而扩展性一点也没有减少。
第四:封装变化
对变化封装包含两层含义:
(1)将相同的变化封装到一个接口或抽象类中
(2)将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。
封装变化,也就是受保护的变化,找出预计有变化或不稳定的点,我们为这些变化点创建稳定的接口。

四、简单事例

以一个简单的书籍售卖为例,书籍有价格,名字。
书籍类:

/**
 * 项目名称:OpenCloseRole
 * 类 名 称:Book
 * 类 描 述:TODO
 * 创建时间:2021/1/4 上午10:27
 * 创 建 人:wteng
 */
public class Book {
    private String name;
    private float price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }
}

测试类为:

/**
 * 项目名称:OpenCloseRole
 * 类 名 称:Main
 * 类 描 述:TODO
 * 创建时间:2021/1/4 上午10:29
 * 创 建 人:wteng
 */

public class Main {
    public static void main(String[] args) {
        Book book = new Book();
        book.setName("水浒传");
        book.setPrice(100);

        System.out.println(book.getName()+"的价格为:"+book.getPrice());
    }
}

但是现在想要拿到一个打折的价格,打折价格是原价的8折,此时我们如果直接对Book类的getPrice方法进行修改,那么就不符合开闭原则,也不应该在源码中新增方法。那么我们按照上边说的,应该新增一个类,来继承Book类,扩展一个方法。

扩展类:

/**
 * 项目名称:OpenCloseRole
 * 类 名 称:DiscountPrice
 * 类 描 述:TODO
 * 创建时间:2021/1/4 上午10:34
 * 创 建 人:wteng
 */

public class DiscountPrice extends Book{
    @Override
    public double getPrice() {
        return super.getPrice() * 0.8;
    }
}

测试类:

/**
 * 项目名称:OpenCloseRole
 * 类 名 称:Main
 * 类 描 述:TODO
 * 创建时间:2021/1/4 上午10:29
 * 创 建 人:wangteng
 */

public class Main {
    public static void main(String[] args) {
        Book book = new Book();
        book.setName("水浒传");
        book.setPrice(100);

        DiscountPrice discountPrice = new DiscountPrice();
        discountPrice.setPrice(book.getPrice());

        System.out.println(book.getName()+"的价格为:"+book.getPrice());
        System.out.println(book.getName()+"的打折价格为:"+discountPrice.getPrice());
    }
}

结果为:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值