首页 > 其他分享 >解析设计模式与设计原则:构建可维护性和可扩展性代码的重要性

解析设计模式与设计原则:构建可维护性和可扩展性代码的重要性

时间:2023-10-17 11:24:44浏览次数:44  
标签:函数 可扩展性 多态 可维护性 Base 接口 设计模式 Subject

本文分享自华为云社区《深入解析设计模式与设计原则:构建可维护性和可扩展性代码的重要性》,作者: Lion Long。

一、为什么需要设计模式?

1.1、设计模式的定义

设计模式大概有23种。

设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案。

从定义可以看出,设计模式的使用有很多的局限性。一定要明确它解决什么问题,再使用它。当不清楚设计模式解决什么问题时不要轻易使用。

通俗的讲,设计模式是解决软件开发过程中一些问题的固定套路。不要过度的封装或使用设计模式,除非明确了需求的具体变化方向,而且变化方向的点是反复的出现,才会使用设计模式;即慎用设计模式。

设计模式要到达一定的工程代码量才能精通。但是,了解设计模式是需要的。

1.2、设计模式由来

设计模式的由来可以追溯到20世纪80年代,由计算机科学家埃里希·伽玛(Erich Gamma)等人首次提出。他们将设计模式定义为可重复利用的解决方案,用于常见问题和设计挑战。

设计模式的出现是为了解决软件开发中的一些常见问题,帮助开发人员更高效地编写可维护和可扩展的代码。通过使用设计模式,开发人员可以借鉴先前的成功经验,避免重复发明轮子,同时提高代码的可读性和可理解性。

设计模式的目标是提供经过验证和经过时间考验的解决方案,以解决特定情境中的常见问题。设计模式不是一种具体的算法或代码片段,而是一种在特定情境下的解决方案模板。它们可以应用于各种编程语言和开发环境中。

设计模式通常分为三种类型:创建型模式、结构型模式和行为型模式。

  • 创建型模式关注对象的创建机制;
  • 结构型模式关注对象之间的关系和组织方式;
  • 行为型模式关注对象之间的交互和通信。

一些常见的设计模式包括单例模式、工厂模式、观察者模式、策略模式等。

一句话来说,就是:满足设计原则后,慢慢迭代出来的。

1.3、 设计模式解决的问题

使用设计模式的前提条件:具体的需求既有稳定点又有变化点。

(1)稳定点,即不会变的东西。如果全是稳定点,不需要设计模式。

(2)变化点,即经常发生变化。如果全是变化点,发生的改变没有具体的方向,这也不需要设计模式。比如游戏开发,使用脚本语言解决全是变化的点,因为脚本不需要重新编译,热更新就可以。

设计模式具体解决问题的场景:希望修改少量的代码,就可以适应需求的变化。比如,整洁的房间有一个好动的猫,如何保证房间的整洁?把猫关到笼子中,使猫在有限范围内活动。

也就是使用设计模式,让变化点在有限范围内变化。

二、设计模式基础

设计模式和开发语言相关的,利用语言的特性实现设计模式。

对于C++而言,设计模式的基础是:

(1)面向对象的思想。面向对象的三个特征,封装(目的是隐藏实现细节,实现模块化)、继承(目的是希望无需修改原有类的基础上,通过继承来实现功能的扩展;C++可以多继承)、多态(静态多态是函数重载,同一个函数名但参数不同来同时表现出不同的形态;动态的多态是继承中虚函数的重写)。设计函数很多依赖于动态的多态

(2)设计原则。

2.1、C++多态之虚函数重写

假设一个基类,有两个虚函数:

class Base{
    public:
        virtual void func1(){}
        virtual void func2(){}
        int a;
};

其虚函数表和内存布局为:

此时有一个子类继承Base:

class Subject : public Base{
    public:
        virtual void func2(){}
        virtual void func3(){}
        int b;
};

其虚函数表和内存布局为:

从内存布局可以看到,有虚函数就会为该类生成虚函数表指针,虚函数表是编译的时候编译器自动帮我们自动生成的。虚函数表其实是一个一维数组,数组的元素保存的虚函数地址,通过偏移就可以调用到相对应的函数。

对于Base类而言,虚函数表有func1和func2;Subject继承Base,它的虚函数表中也会有Base的虚函数,而且虚函数表中Base的虚函数在Subject的虚函数前面。

如果Subject没有重写Base虚函数,那么虚函数表中保存的虚函数地址是一样的(如示例中的func1)。

如果Subject重写Base虚函数,那么虚函数表中会发生替换,将Subject重新的虚函数地址替换掉Base中相应虚函数的地址(如示例中的func2)。

如果Subject自己有新的虚函数,则也要加入虚函数表中。

2.2、多态的体现

(1)早绑定。假如有Base *p=new Subject;如果Subject没有重写Base虚函数,那么会将Subject类型转换为Base类型,这就是早绑定。

(2)晚绑定。假如有Base *p=new Subject;如果Subject重写了Base虚函数,那么p实际指向的是Subject对象,这就是晚绑定。

2.3、扩展方式

(1)继承。

(2)组合。

2.4、多态组合

// 继承
class Subject : public Base{
};

// 组合
class Subject{
private:
    Base base;
};

设计模式中的组合通常是指组合基类指针。好处是可以扩展Base的功能,通过多态方式让组合解耦合。

// 组合基类指针
class Subject{
private:
    Base *base;
};

三、设计原则

设计原则是设计模式还没产生它就存在了。设计原则是多代程序员总结的开发原则。

3.1、依赖倒置

实现要依赖接口,接口又可以转换为抽象,即具体实现的代码需要依赖这个抽象。具体使用接口(客户)也要依赖这个抽象。

高层模块不应该依赖低层模块,两者都应该依赖抽象;

抽象不应该依赖具体实现,具体实现应该依赖于抽象;

自动驾驶系统公司是高层,汽车生产厂商为低层,它们不应该互相依赖,一方变动另一方也会跟着变动;而应该抽象一个自动驾驶行业标准,高层和低层都依赖它;这样以来就解耦了两方的变动;自动驾驶系统、汽车生产厂商都是具体实现,它们应该都依赖自动驾驶行业标准(抽象)。

3.2、开放封闭

一个类应该对扩展(组合和继承)开放,对修改关闭。针对封装和多态。

3.3、面向接口

不将变量类型声明为某个特定的具体类,而是声明为某个接口;客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案;主要针对封装。

3.4、封装变化点

将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离。主要针对封装和多态。

3.5、单一职责

一个类应该仅有一个引起它变化的原因。主要针对封装。

3.6、里氏替换

子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责。

主要针对多态中的虚函数重写。

3.7、接口隔离

(1)不应该强迫客户依赖于它们不用的方法;

(2)一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责;

(3)客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。

通过限定词隔离。类与类之间依赖接口,通过接口隔离类。

3.8、组合优于继承

继承耦合度高,组合耦合度低。

3.9、最小知道原则

让用户尽量不选择它不需要的接口。

总结

通过介绍设计模式的定义、分类和应用场景,以及设计原则的作用,强调了它们在软件开发中的重要性。设计模式提供了可重复利用的解决方案,帮助开发人员解决常见问题和设计挑战,并提高代码的可读性、可理解性和可维护性。设计原则则为设计模式提供了指导,如单一职责原则、开放封闭原则等。通过应用设计模式和设计原则,开发人员可以构建高质量、可维护和可扩展的软件系统,避免重复劳动,提高代码的可重用性和灵活性。

点击关注,第一时间了解华为云新鲜技术~

 

标签:函数,可扩展性,多态,可维护性,Base,接口,设计模式,Subject
From: https://www.cnblogs.com/huaweiyun/p/17769250.html

相关文章

  • 设计模式之策略模式:让你的代码灵活应对不同的算法
    作为一个程序员,我们经常会面临着在不同的情况下选择不同的算法来解决问题的需求。这种情况下,策略模式是一个非常有用的设计模式。在本文中,我将向你介绍策略模式的概念、结构以及如何应用这个模式来使你的代码更灵活。1.什么是策略模式?策略模式是一种行为型设计模式,它允许在运行......
  • c#设计模式-行为型模式 之 访问者模式
    ......
  • 设计模式02 —— UML
    设计模式02——UML本教程参考:菜鸟教程-学的不仅是技术,更是梦想!(runoob.com)参考书:《图解设计模式》本系列为本人学习笔记,和课程学习笔记,资料和参考均源自互联网,希望各位大佬多多指点!UML的概念UML的全称是UndefinedModelingLanguage(统一建模语言)是让系统可视化,让规格......
  • Java设计模式
    七大设计原则开闭原则:是指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭依赖倒置原则:是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象而不依赖于具体。单一职责原则:是指一个Class/Interface/Method只负责一项职责。接口隔离原则:是指用多个专......
  • 设计模式01 —— 设计模式简介
    设计模式01——设计模式简介本教程参考:菜鸟教程-学的不仅是技术,更是梦想!(runoob.com)为本人学习笔记,和课程学习笔记,希望各位大佬多多指点!设计模式的简介设计模式可以看作一套被人反复使用的,多人知晓的代码设计的经验总结。设计模式是软件工程的基石。以下是完全版:设......
  • 对设计模式的理解
    一切设计,都围绕着抽象与具体展开!大道至简!抽象:一般指接口。里面没有方法细节,只有方法签名。方法签名告诉你它能干什么,但不提供怎么干具体:所有具体类都应该是单一职责的。具体可以依赖抽象,程序运行过程中,会有该抽象的具体实现替代抽象。且具体类要符合最少知道原则,只开放必要的方......
  • 设计模式 (2):8 种结构性模式
    回顾上节:随着对象种类、属性容量的扩大,创建具体对象、管理属性装配、快速复制等,都面临难题,这时产生了工厂、建造者、原型等设计模式;单例模式也保护了全局变量,提高了全局访问、使用全局对象和接口的安全性、规范性、可用性等等目录1适配器模式(Adapter)方法依赖别的接......
  • 线程之间的通信&线程池&设计模式
    day19_线程之间的通信&线程池&设计模式课程目标1.【理解】线程通信概念2.【理解】等待唤醒机制3.【理解】线程池运行原理4.【理解】voliate关键字5.【掌握】单例设计模式线程之间通信什么是线程之间的通信**概念:**多个线程在处理同一个资源,但是处理的动作(线程的任......
  • 设计模式总和
            ......
  • 【愚公系列】2023年10月 二十三种设计模式(十二)-代理模式(Proxy Pattern)
    ......