理论篇:面向对象程序设计指导

》 本文来自看过的相关知识的摘录整理,太久了,忘了主要出自哪儿里了。

软件架构

架构(Architecture)是指一个系统或软件的总体设计和组织结构,包括其各个组件、模块、接口和数据流等。架构设计的目的是确保系统或软件具有可扩展性、可维护性、可靠性和安全性等特性,并且能够满足业务需求和技术要求。

在软件开发中,架构通常包括以下几个方面:

  1. 组件和模块:系统或软件由多个组件和模块组成,每个组件和模块都有特定的功能和职责。架构需要定义这些组件和模块之间的关系和接口,以确保它们能够协同工作。
  2. 接口和协议:系统或软件需要与其他系统或软件进行通信,因此需要定义各种接口和协议,包括输入输出接口、数据格式、传输协议等。
  3. 数据流和数据存储:系统或软件需要处理大量的数据,因此需要定义数据流和数据存储的方式,包括数据的采集、处理、存储和检索等
  4. 可扩展性和可维护性:架构需要考虑系统的可扩展性和可维护性,以便在未来的需求变化时能够方便地进行修改和升级
  5. 可靠性和安全性:架构需要考虑系统的可靠性和安全性,以确保系统能够在高负载和恶意攻击的情况下保持稳定运行

一个好的架构设计可以提高系统的性能、可靠性和安全性,同时也可以提高开发效率和降低开发成本。

架构通常是关于难以更改的决定,需要有人做出这些决定。架构设计基于需求分析,需求分析确定系统要做什么,架构决定如何去做,需要有人了解这个什么来确定这个如何

架构师的主要职责是:确认需求、把系统分解成更小的子系统、识别和评估技术、以及制定规范

事实上,没有确认清楚需求是直接导致软件项目失败的常见原因之一,通常也是主要原因。

一个好的需求只针对一个东西、表达上没有歧义、可以轻易追溯到业务或者利益相关者的需求、不会作废等。

不过,实际的情况是,业务人员描述的是他们认为自己想要的东西,开发人员构建的是他们认为业务人员想要的东西。不管你在搜集需求上投入多少努力,总会出现隐瞒、忽略、忘记、或者被描述的东西只有一些人清楚,而另外一些人并不清楚。这种沟通问题的根源是业务人员和开发人员使用不同的词汇。我们坚信架构师和开发者应该和业务人员使用相同的词汇
不管代金券实际上如何编码才能完整实现,你都必须理解它是什么。更重要的是,你还需要理解业务人员如何看待它。作为一名架构师,你不应该期望业务人员理解你的语言,例如数据库表、服务和协议之类的东西。相反,是你应该付出必要的努力去理解构成业务领域的实体含义。

软件开发方法学:敏捷开发

今天对架构流程的看法是:任何团队都应该尽快开始开发,然后获取早期反馈。在真实代码上改进软件,这意味着快速前进、接受甚至拥抱变化,尽早交付一些有价值的东西,以及欢迎反馈。

敏捷开发是一个统称,有好多种,但都与迭代这个词密切相关。XP(极限编程)、Scrum都是比较流行的敏捷开发。

在敏捷项目启动时,可能只有一些需求完全定义出来,但你知道在项目结束之前,会有更多需求呈现出来或者要被澄清。凭借敏捷思维,这不是一个问题。开发过程会在迭代中变得清晰。在迭代开始时,你会和客户商谈现有需求应该实现的部分。在迭代过程里,你每次只会关注和实现单个需求,在迭代结束时,你交付一份可工作的软件。他可能是不完整的,但他可以工作。接着你进入另一个迭代。关注另一组需求。如果在此期间某些东西发生改变或者被证明错误的,就会进行重构。这个过程会持续到没有更多东西要添加为止。迭代的长度以周为单位,通常是两周。总之,敏捷流程非常敏捷,足以应对变化。而变化在业务里是常态,不是例外。

内聚和耦合

内聚表示软件模块承担的众多职责的关联性很强。与内聚密切相关的是单一职责原则。

耦合衡量两个软件模块(如类)之间存在的依赖程度,耦合度量范围从低到高,越低越好。假设有a和b两个类,如果每次改变a都不得不改变b,那么就说他们耦合了。低耦合并不意味着你的模块与另一个完全隔离。他们肯定允许通讯,但他们应该通过一组定义明确和稳定的接口来做。每个模块都应该可以在没有了解另一个模块的内部实现的情况下工作。

高内聚低耦合是软件设计的追求。系统的设计符合低耦合与高内聚,通常都具备高可读性、可维护性、易于测试、以及良好重用。

一个高耦合的示例:

public class SomeComponent
{
    public void DoWork()
    {
        var logger = new Logger();//与Logger类高耦合
        logger.Log("test");
    }
}

SomeComponent与Logger类紧密耦合,如果后者坏掉或者不可用,那么前者也会坏掉。更重要的是,你不能使用另一种日志记录器。

实现高内聚、低耦合,通常会面向接口编程,以及使用依赖注入、面相切面编程(AOP)

面向对象设计

面向对象设计(OOD)原则包含在这句话里:

你必须找到相关对象,把他们划分成合适粒度的类,定义类的接口和继承体系,然后在他们之间建立关键关系。——GoF

相关类

需求和用例提供了原始材料,必须弄懂他们,然后创建相关类的层次结构。找出相关对象的常见做法是:标记各个用例里的名词和动词,名词引出类或属性,而动词引出类上的方法。

对接口编程

横切关注点是你需要放在类里的却又与类的需求没有太大关系的功能。日志记录是横切关注点的一个典型示例。

完全分离横切关注点需要使用依赖注入(DI)或服务定位器(SL)等模式,在这种情况下,类依赖的是某种抽象而不是实际编译的模块。一般而言,分离横切关注点意味着类是对接口而不是实现编程的。如上述两个模式都是提供一种方式,向对接口编程的类传递接口实例的某个实际引用。

OOD的基础可以总结成以下三点:找出相关对象,减少接口、对象之间的耦合,以及善用代码重用。


面向对象设计原则参考:

面向对象设计模式参考:

重构

重构就是重新调整现有代码的结构,但要确保外部行为不受影响。促使代码从当前状态向更好状态转变是重构的目标。

你重构代码不是因为它不能工作了,而是为了更好地实现某些非功能性需求,如可读性、可维护性、可测试性和可扩展性,甚至是为了提高性能。以下是一些常见的重构操作。

  • 提取方法:把几行代码移到一个新建的方法使原来的方法变得更短。从而促进了可读性和代码重用。
  • 提取接口:把现有的类里的公共方法,变成一个新建的接口。这样的话,你促进了接口编程和低耦合模块。
  • 封装字段:使用一对get和set方法包装类里的一个字段。

重构可以总结成两点,一个是持续的代码编辑,改善可读性和设计;另一个是执行更加进取的结构调整,使现有代码符合特定设计模式。

编写优质软件

代码的质量通过三个参数来衡量:可测试性、可扩展性、和可读性

编写可测试性代码的艺术

就软件架构而言,可测试性一个普遍接受的定义是,能够轻松地在代码上执行测试。测试代码只是检查软件,并确保它按照期望运行没有错误、已经满足需求的过程。

测试是一个流程,目的是验证代码是否满足预期。

测试意味着有更多代码编写和维护,这是额外的代价。

软件测试会出现在各个层次:

  • 单元测试。可以检测软件的单个组件是否满足功能性需求。//开发阶段可编写单元测试代码,并运行测试。
  • 集成测试,可以检测软件是否兼容环境和基础设施,以及两个或多个组件是否协同工作。//虽然一些模块能够单独地工作,但并不能保证连接起来也能正常的工作,一些在局部反映不出来的问题,在全局上很可能暴露出来。
  • 验收测试,可以检查完成的系统是否满足客户的需求。//部署到测试环境,点点看看,模拟用户操作。

你如何在测试一个方法时抵消依赖?

你使用测试替身。测试替身主要有两种类型,仿冒对象(fake)和虚拟对象(mock)。仿冒对象是一个对象相对简单的克隆,提供和原来对象相同的接口,但返回硬编码或通过编程决定的值,总之是通过自己“造数据”来忽略依赖。当你需要在测试期间与依赖对象交互时,你使用虚拟对象。你可能需要专门的虚拟框架。流行的比如:MoqNMock2Typemock

单元测试是开发者为他们自己而写的,帮助团队保证软件的当前质量。单元测试基本上回答这样的问题,我们做的好吗?或者我们走对了路吗?或者他破坏其他组件了吗?单元测试的范围覆盖系统的单个功能性单元。这个单元通常是一个类。如何做,参考:使用测试资源管理器运行单元测试 - Visual Studio (Windows) | Microsoft Learn

集成测试的目标是获得单个组件在性能和可靠性方面的反馈。通常集成测试跨越整个系统的逻辑层和物理层,牵涉数据库和服务。

验收测试是契约测试,你运行他们来检查完整部署的系统是否满足你的需求。一般认为利益相关者和QA人员一起编写验收测试。从用户故事开始,挑选重要的场景进行测试。每个用户故事都可能有一个或多个验收。怎么测试视情况而定,利益相关者负责正面情况。QA负责编辑情况,最后开发者检查测试,确保实际操作在部署系统里有意义。

测试驱动开发(TDD)是一个引导开发者从测试开始写代码的开发模式。结束之时,你很有希望得到设计良好的代码,还附带一堆高代码覆盖率的测试作为奖励。我们认为,如果你想极大的改善代码质量和个人开发者的技能,TDD可能是最好的选择。因为它给你循序渐进的流程:编写一个失败的测试、添加代码、使测试通过、重构、重复这个过程。因为你的代码必须通过测试你就需要使用松耦合设计、小心处理依赖、避免静态和全局方法、使类保持精简、总是选择最简单的方案,所有这些都是为了使代码变得更好。

代码可扩展性的实践

尽量面向接口编程

尽量使用依赖注入

多使用设计模式

写出别人看得懂的代码

软件可维护性受到多种因素的影响,其中一个就是可读性。你不应该忘记最终维护你的代码的开发者,有一天可能恰恰是你。

禁止明显的注释是改善可读性的另一个基本点。注释解释了你在代码里所做的本身不明显的决定

如果你在寻找一些代码风格的启发,你可以看一下开源项目。开源软件写给很多人阅读和理解,它可能是真实的启发之源。


更新于:2024-01-25

posted @ 2024-01-25 15:12  AI大胜  阅读(12)  评论(0编辑  收藏  举报