站长信息
jeffery.xu
jeffery.xu

软件工程师

欢迎访问我的个人笔记网站!我是一名热爱技术的开发者,专注于Web开发和技术分享。

811495111@qq.com
18521510875
筛选

个人笔记

能力成熟度模型(CMMI)
软考

CL0(未完成的):过程域未执行或未得到CL1中定义的所有目标。

CL1(已执行的):其共性目标是过程将可标识的输入工作产品转换成可标识的输出工作产品,以实现支持过程域

的特定目标。

CL2(已管理的):其共性目标是集中于已管理的过程的制度化。根据组织级政策规定过程的运作将使用哪个过

程,项目遵循已文档化的计划和过程描述,所有正在工作的人都有权使用足够的资源,所有工作任务和工作产品都

被监控、控制和评审。

CL3(已定义级的):其共性目标集中于已定义的过程的制度化。过程是按照组织的裁剪指南从组织的标准过程中

裁剪得到的,还必须收集过程资产和过程的度量,并用于将来对过程的改进。

CL4(定量管理的):其共性目标集中于可定量管理的过程的制度化。使用测量和质量保证来控制和改进过程域

建立和使用关于质量和过程执行的质量目标作为管理准则。

CL5(优化的):使用量化(统计学)手段改变和优化过程域,以满足客户的改变和持续改进计划中的过程域的功

效。

 

8.29练习题
软考

第1题(单选题)

信息系统的文档是开发人员与用户交流的工具。在系统规划和系统分析阶段,用户与系统分析人员交流所使用的文档不包括(

A.可行性研究报告

B.总体规划报告

C.项目开发计划

D.用户使用手册

第2题(单选题)

以下关于系统原型的叙述中,不正确的是()。

A.可以帮助导出系统需求并验证需求的有效性

B.可以用来探索特殊的软件解决方案

C.可以用来指导代码优化

D.可以用来支持用户界面设计

第3题(单选题)

流水线的吞吐率是指单位时间流水线处理的任务数,如果各段流水的操作时间不同,则流水线的吞吐率是( )的倒数。

A.最短流水段操作时间

B.各段流水的操作时间总和

C.最长流水段操作时间

D.流水段数乘以最长流水段操作时间

第4题(单选题)

常用的函数参数传递方式有传值与传引用两种,()。

A.在传值方式下,形参与实参之间互相传值

B.在传值方式下,实参不能是变量

C.在传引用方式下,修改形参实质上改变了实参的值

D.在传引用方式下,实参可以是任意的变量和表达式

第5题(单选题)

()的保护期限是可以延长的。

A.专利权

B.商标权

C.著作权

D.商业秘密权

第6题(单选题)

移进-归约分析法是编译程序(或解释程序)对高级语言源程序进行语法分析的一种方法,属于()的语法分析方法.。

A.自顶向下(或自上而下)

B.自底向上(或自下而上)

C.自左向右

D.自右向左

第7题(单选题)

Cloud computing is a phrase used to describe a variety of computing concepts that involve a large number of computers (1)

through a realtime communication network such as the lntemet. in science, cloud computing is a (2) for distributed computing

over a network, and means the (3) to run a program or application on many connected computers at the same time.

The architecture of a cloud is developed at three lavers: infrastructure, platform, and application, The infrastructure laver is buil

with virtualized computer, storage, and network resources. The platform laver is for general-purpose and repeated usage of the

collection of soflware resources. The application laver is formed with a collection of all needed software modules for SaaS

applications. The infrastructure layer serves as the (4) for building the platform layer of the cloud. in tum, the platform layer is a

foundation for implementing the (5)layer for SaaS applications.

问题1

A.connected

B.imlemented

C .optimized

D.Virtualized

问题2

A.replacement

B.switch

C.substitute

D.synonym(同义词)

问题3

A.ability

B.applroach

C.function

D.method

问题4

A.network

B.foundation

C software

D.hardware

问题5

A.resoruce

B.service

C.application

D.software

第8题(单选题)

()不能用来描述项目开发的进度安排。在其他三种图中,可用()动态地反映项目开发进展情况。

在软件开发中,

问题1

A.甘特图

B.PERT图

C.PERTICPM图

D.鱼骨图

问题2

A.甘特图

B.PERT图

C.PERTICPM图

D.鱼骨图

第9题(单选题)

现有16枚外形相同的硬币,其中有一枚比真币的重量轻的假币,若采用分治法找出这枚假币,至少比较()次才能够找出该假

币。

A3

B.4

C5

D.6

第10题(单选题)

UNIX系统采用直接、一级、二级和三级间接索引技术访问文件,其索引结点有13个地址项(iaddr{0]~i add{12)。如果每个盘

块的大小为1KB,每个盘块号占48,则进程A访问文件F中第11264字节处的数据时,()

A.可直接寻址

B.需要-次间接寻址

C.需要二次间接寻址

D.需要三次间接寻址

 

 

8.28练习题
软考

第1题(单选题):

页面的标记对中()用于表示网页代码的起始和终止。



A.<html></html>



B.<head></head>



C.<body></body>



D.<meta> </meta>

第2题(单选题):

SQL是一种数据库结构化查询语言,SQL注入攻击的首要目标是()。



A.破坏Web服务



B.窃取用户口令等机密信息


C.攻击用户浏览器,以获得访问权限



D.获得数据库的权限


第3题(单选题)

下列命令中,不能用于诊断DNS故障的是()。

A.netstat

B.nslookup

C.ping

D.tracert

第4题(单选题):

王某是某公司的软件设计师,完成某项软件开发后按公司规定进行软件归档。以下有关该软件的著作权的叙述中,正确的是(

A.著作权应由公司和王某共同享有

8.著作权应由公司享有

C.著作权应由王某享有

D.除署名权以外,著作权的其他权利由王某享有

第5题(单选题):

()不属于软件配置管理的活动。

A.变更标识

B.变更控制

C.质量控制

D.版本控制

第6题(单选题):

两个小组独立地测试同一个程序,第一组发现25个错误,第二组发现30个错误,在两个小组发现的错误中有15个是共同的,那么

可以估计程序中的错误总数是()个。

A.25

B.30

C.50

D.60

第7题(单选题):

函数t0、10的定义如下所示,若调用函数t时传递给x的值为3,并且调用函数f0时,第一个参数采用传值(call by value)方式,第

二个参数采用传引用(call by reference)方式,则函数t的返回值为()。

A.35

B.24

C.22

D.11

第8题(单选题):

()是指在运行时把过程调用和响应调用所需要执行的代码加以结合。

A.绑定

B.静态绑定

C.动态绑定

D.继承

第9题(单选题):

在面向对象系统中,用()关系表示一个较大的“整体”类包含一个或多个较小的“部分”类。

A.泛化

B.聚合

C.概化

D.合成

第10题(单选题):

一个 B类网络的子网掩码为 255.255.224.0,则这个网络被划分成了( )个子网。

A.2

B.4

C.6

D.8

 

 

码值范围
软考

练习
软考

第1章 计算机系统知识
软考

1.1 计算机系统基础知识

1.1.1 计算机系统硬件基本组成

计算机系统是由硬件软件组成的,它们协同工作来运行程序。计算机的基本硬件系统由运算器、控制器、存储器、输入设备和输出设备5大部件组成。运算器、控制器等部件被集成在一起统称为中央处理单元(Central Processing Unit,CPU)。CPU 是硬件系统的核心,用于数据的加工处理,能完成各种算术、逻辑运算及控制功能。存储器是计算机系统中的记忆设备,分为内部存储器和外部存储器。前者速度高、容量小,一般用于临时存放程序、数据及中间结果。而后者容量大、速度慢,可以长期保存程序和数据。输入设备和输出设备合称为外部设备(简称外设),输入设备用于输入原始数据及各种命令,而输出设备则用于输出计算机运行的结果。

Note: CPU包含运算器和控制器,存储器分为内存和外存,输入输出顾名思义。

1.1.2 中央处理单元

中央处理单元(CPU)是计算机系统的核心部件,它负责获取程序指令、对指令进行译码

并加以执行。



  1. CPU 的功能



    (1)程序控制。CPU 通过执行指令来控制程序的执行顺序,这是 CPU 的重要功能。


    (2)操作控制。一条指令功能的实现需要若干操作信号配合来完成,CPU产生每条指令的

操作信号并将操作信号送往对应的部件,控制相应的部件按指令的功能要求进行操作。



    (3)时间控制。CPU对各种操作进行时间上的控制,即指令执行过程中操作信号的出现时

间、持续时间及出现的时间顺序都需要进行严格控制。



    (4)数据处理。CPU 通过对数据进行算术运算及逻辑运算等方式进行加工处理,数据加工

处理的结果被人们所利用。所以,对数据的加工处理也是 CPU 最根本的任务。



    此外,CPU还需要对系统内部和外部的中断(异常)做出响应,进行相应的处理。

  2. CPU的组成

    CPU 主要由运算器、控制器、寄存器组和内部总线等部件组成,如图 1-1 所示。


1)运算器

运算器由算术逻辑单元(Arithmetic and Logic Unit,ALU)、累加寄存器、数据缓冲寄存

器和状态条件寄存器等组成,它是数据加工处理部件,用于完成计算机的各种算术和逻辑运算。

相对控制器而言,运算器接受控制器的命令而进行动作,即运算器所进行的全部操作都是由控

制器发出的控制信号来指挥的,所以它是执行部件。运算器有如下两个主要功能。

(1)执行所有的算术运算,例如加、减、乘、除等基本运算及附加运算。

(2)执行所有的逻辑运算并进行逻辑测试,例如与、或、非、零值测试或两个值的比较等。

下面简要介绍运算器中各组成部件的功能。

(1)算术逻辑单元(ALU)。ALU 是运算器的重要组成部件,负责处理数据,实现对数据的算术运算和逻辑运算。

(2)累加寄存器(AC)。AC通常简称为累加器,它是一个通用寄存器,其功能是当运算器的算术逻辑单元执行算术或逻辑运算时,为 ALU 提供一个工作区。例如,在执行一个减法运算前,先将被减数取出暂存在 AC 中,再从内存储器中取出减数,然后同 AC 的内容相减,将所得的结果送回 AC 中。运算的结果是放在累加器中的,运算器中至少要有一个累加寄存器

(3)数据缓冲寄存器(DR)。在对内存储器进行读/写操作时,用 DR 暂时存放由内存储器读/写的一条指令或一个数据字,将不同时间段内读/写的数据隔离开来。DR 的主要作用为:作为 CPU 和内存、外部设备之间数据传送的中转站;作为 CPU 和内存、外围设备之间在操作速度上的缓冲;在单累加器结构的运算器中,数据缓冲寄存器还可兼作为操作数寄存器。

(4)状态条件寄存器(PSW)。PSW 保存由算术指令和逻辑指令运行或测试的结果建立的各种条件码内容,主要分为状态标志和控制标志,例如运算结果进位标志(C)、运算结果溢出标志(V)、运算结果为0标志(Z)、运算结果为负标志(N)、中断标志(I)、方向标志(D)和单步标志等。这些标志通常分别由1位触发器保存,保存了当前指令执行完成之后的状态。通常,一个算术操作产生一个运算结果,而一个逻辑操作产生一个判决。

2)控制器

运算器只能完成运算,而控制器用于控制整个 CPU 的工作,它决定了计算机运行过程的自动化。它不仅要保证程序的正确执行,而且要能够处理异常事件。控制器一般包括指令控制逻辑、时序控制逻辑、总线控制逻辑和中断控制逻辑等几个部分。

指令控制逻辑要完成取指令、分析指令和执行指令的操作,其过程分为取指令、指令译码、按指令操作码执行、形成下一条指令地址等步骤。

(1)指令寄存器(IR)。当CPU执行一条指令时,先把它从内存储器取到缓冲寄存器中,再送入 I 暂存,指令译码器根据 I 的内容产生各种微操作指令,控制其他的组成部件工作,完成所需的功能。

(2)程序计数器(PC)。PC 具有寄存信息和计数两种功能,又称为指令计数器。程序的执行分两种情况,一是顺序执行,二是转移执行。在程序开始执行前,将程序的起始地址送入PC,该地址在程序加载到内存时确定,因此PC的内容即是程序第一条指令的地址。执行指令时,CPU 自动修改 PC的内容,以便使其保持的总是将要执行的下一条指令的地址。由于大多数指令都是按顺序来执行的,所以修改的过程通常只是简单地对 PC加1。当遇到转移指令时,后继指令的地址根据当前指令的地址加上一个向前或向后转移的位移量得到,或者根据转移指令给出的直接转移的地址得到。

(3)地址寄存器(AR)。AR 保存当前 CPU 所访问的内存单元的地址。由于内存和 CPU存在着操作速度上的差异,所以需要使用 AR 保持地址信息,直到内存的读/写操作完成为止。

(4)指令译码器(ID)。指令包含操作码和地址码两部分,为了能执行任何给定的指令,必须对操作码进行分析,以便识别所完成的操作。指令译码器就是对指令中的操作码字段进行分析解释,识别该指令规定的操作,向操作控制器发出具体的控制信号,控制各部件工作,完成所需的功能。

时序控制逻辑要为每条指令按时间顺序提供应有的控制信号。总线逻辑是为多个功能部件服务的信息通路的控制电路。中断控制逻辑用于控制各种中断请求,并根据优先级的高低对中断请求进行排队,逐个交给 CPU 处理。

3)寄存器组

寄存器组可分为专用寄存器和通用寄存器。运算器和控制器中的寄存器是专用寄存器,其作用是固定的。通用寄存器用途广泛并可由程序员规定其用途,其数目因处理器不同有所差异。

  1. 多核 CPU

核心又称为内核,是 CPU 最重要的组成部分。CPU 中心那块降起的芯片就是核心,是由单品硅以一定的生产工艺制造出来的,CPU 所有的计算、接收/存储命令、处理数据都由核心执行。各种 CPU 核心都具有固定的逻辑结构,一级缓存、二级缓存、执行单元、指令级单元和总线接口等逻辑单元都会有合理的布局。

多核即在一个单芯片上面集成两个甚至更多个处理器内核,其中,每个内核都有自己的逻辑单元、控制单元、中断处理器、运算单元,一级 Cache、二级 Cache 共享或独有,其部件的完整性和单核处理器内核相比完全一致。

CPU 的主要厂商 AMD 和 Intel 的双核技术在物理结构上有所不同。AMD 将两个内核做在一个 Die(晶元)上,通过直连架构连接起来,集成度更高。Intel 则是将放在不同核心上的两个内核封装在一起,因此将 Intel 的方案称为“双芯”,将 AMD 的方案称为“双核”。从用户端的角度来看,AMD 的方案能够使双核 CPU 的管脚、功耗等指标跟单核 CPU 保持一致,从单核升级到双核,不需要更换电源、芯片组、散热系统和主板,只需要刷新 BIOS 软件即可。

多核 CPU 系统最大的优点(也是开发的最主要目的)是可满足用户同时进行多任务处理的要求。

单核多线程 CPU 是交替地转换执行多个任务,只不过交替转换的时间很短,用户一般感觉不出来。如果同时执行的任务太多,就会感觉到“慢”或者“卡”。而多核在理论上则是在任何时间内每个核执行各自的任务,不存在交替问题。因此,单核多线程和多核(一般每核也是多线程的)虽然都可以执行多任务,但多核的速度更快。

虽然采用了 Intel 超线程技术的单核可以视为是双核,4 核可以视为是8核。然而,视为是8 核一般比不上实际是8核的 CPU 性能。

要发挥 CPU的多核性能,就需要操作系统能够及时、合理地给各个核分配任务和资源(如缓存、总线、内存等),也需要应用软件在运行时可以把并行的线程同时交付给多个核心分别处理。

接口隔离原则(Interface Segregation Principle, ISP)
设计模式

客户端不应该被迫依赖它不需要的接口。应该把庞大的接口拆分成更小、更具体的接口。

# 反例:一个大而全的接口
class Worker:
    def work(self):
        pass
    def eat(self):
        pass

class Robot(Worker):
    def work(self):
        pass
    def eat(self):
        raise NotImplementedError("机器人不需要吃饭")  # 被迫实现不需要的方法

# 正例:拆分接口
class Workable:
    def work(self):
        pass

class Eatable:
    def eat(self):
        pass

class HumanWorker(Workable, Eatable):
    pass

class RobotWorker(Workable):
    pass
里氏替换原则(Liskov Substitution Principle, LSP)
设计模式

里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计的核心原则之一,由芭芭拉・利斯科夫(Barbara Liskov)在 1987 年提出。其核心思想是:子类对象必须能够替换掉它们的父类对象,而不影响程序的正确性。这意味着,子类应当遵循父类的契约,保持行为的一致性。

核心动机

  • 继承的正确性:确保子类不会破坏父类的原有功能。
  • 多态的可靠性:通过父类引用调用子类方法时,结果应符合预期。
  • 降低系统风险:避免因子类行为异常导致的潜在错误。

LSP 的关键要求

  1. 前置条件不能强化:子类方法的前置条件(输入参数)不能比父类更严格。
  2. 后置条件不能弱化:子类方法的后置条件(返回值)必须满足父类的要求。
  3. 不变式要保持:子类不能改变父类的不变量(如类的约束条件)。
  4. 异常要兼容:子类抛出的异常应当与父类一致或为其子类。

C# 示例:矩形与正方形问题

违反 LSP 的经典案例

假设我们有一个矩形类和一个正方形类,正方形继承自矩形:
// 基类:矩形
public class Rectangle
{
    public virtual double Width { get; set; }
    public virtual double Height { get; set; }

    public double Area() => Width * Height;
}

// 子类:正方形(错误设计)
public class Square : Rectangle
{
    // 正方形的宽和高必须相等
    public override double Width
    {
        get => base.Width;
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public override double Height
    {
        get => base.Height;
        set
        {
            base.Height = value;
            base.Width = value;
        }
    }
}

问题分析

这个设计违反了 LSP,因为:
  • 前置条件被强化:父类允许设置不同的宽和高,但子类强制二者相等。
  • 行为不一致:以下代码在使用父类时正常,但使用子类时会出错:
    public void TestRectangle(Rectangle rect)
    {
        rect.Width = 5;
        rect.Height = 10;
        Console.WriteLine(rect.Area()); // 预期输出50
    }
    
    // 测试
    var rectangle = new Rectangle();
    TestRectangle(rectangle); // 输出50,正确
    
    var square = new Square();
    TestRectangle(square);    // 输出100,错误!

遵循 LSP 的重构方案

方案 1:抽象公共接口

// 抽象接口:四边形
public interface IQuadrilateral
{
    double Width { get; }
    double Height { get; }
    double Area();
}

// 矩形实现
public class Rectangle : IQuadrilateral
{
    public double Width { get; set; }
    public double Height { get; set; }
    public double Area() => Width * Height;
}

// 正方形实现
public class Square : IQuadrilateral
{
    private double _side;
    
    public double Width
    {
        get => _side;
        set => _side = value;
    }
    
    public double Height
    {
        get => _side;
        set => _side = value;
    }
    
    public double Area() => _side * _side;
}

方案 2:组合而非继承

// 正方形包含一个矩形实例
public class Square
{
    private readonly Rectangle _rectangle = new Rectangle();
    
    public double Side
    {
        get => _rectangle.Width;
        set
        {
            _rectangle.Width = value;
            _rectangle.Height = value;
        }
    }
    
    public double Area() => _rectangle.Area();
}

另一个示例:银行账户与透支账户

违反 LSP 的设计

// 基类:银行账户
public class BankAccount
{
    protected double _balance;
    
    public virtual void Withdraw(double amount)
    {
        if (amount > _balance)
            throw new InvalidOperationException("余额不足");
        
        _balance -= amount;
    }
}

// 子类:透支账户(错误设计)
public class OverdraftAccount : BankAccount
{
    private double _overdraftLimit = 1000;
    
    // 重写取款方法,允许透支
    public override void Withdraw(double amount)
    {
        if (amount > _balance + _overdraftLimit)
            throw new InvalidOperationException("超过透支限额");
            
        _balance -= amount;
    }
}

问题分析

  • 前置条件被弱化:子类允许更多情况下的取款(透支),而父类不允许。
  • 行为不一致:依赖父类行为的代码(如检查余额)在使用子类时会失效。

LSP 的其他应用场景

  1. 集合类中的协变与逆变:确保泛型集合的类型安全。
  2. 事件处理:子类事件的参数应与父类兼容。
  3. 数据库操作:子类的查询条件不能比父类更严格。

总结

  • LSP 是继承的契约:子类必须遵守父类的行为约定。
  • 避免破坏父类行为:重写方法时不要改变原有的语义。
  • 优先使用组合:当继承导致 LSP 违反时,考虑使用组合或接口替代。
通过遵循 LSP,代码可以保持良好的可替换性和扩展性,降低系统的耦合度。
开闭原则(Open/Closed Principle, OCP)
设计模式
开闭原则(Open/Closed Principle, OCP)是面向对象设计的核心原则之一,由 Bertrand Meyer 提出。其核心思想是:软件实体(类、模块、函数等)应当对扩展开放,对修改关闭。这意味着在添加新功能时,应该通过扩展现有代码而非修改它来实现。

核心动机

  • 减少风险:修改现有代码可能引入新的错误,影响原有功能。
  • 提高可维护性:代码无需频繁修改,降低维护成本。
  • 促进复用:通过抽象和多态,可复用现有设计框架。

实现方式

  1. 抽象化:通过接口或抽象类定义稳定的契约。
  2. 多态:利用子类实现行为的扩展。
  3. 依赖注入:通过依赖倒置,使高层模块不依赖具体实现。

C# 示例:报表生成器

假设你正在开发一个报表生成器,初始需求是生成 PDF 报表。随着业务发展,需要支持 Excel 和 CSV 格式。
public class ReportGenerator
{
    public void GenerateReport(string format, ReportData data)
    {
        if (format == "PDF")
        {
            // 生成 PDF 报表的具体实现
            Console.WriteLine("生成 PDF 报表");
        }
        else if (format == "Excel")
        {
            // 生成 Excel 报表的具体实现
            Console.WriteLine("生成 Excel 报表");
        }
        // 问题:每次新增格式都需要修改此方法
    }
}

遵循开闭原则的重构

通过抽象化和多态,将报表生成逻辑封装到独立的类中:
// 定义报表生成器接口(抽象)
public interface IReportGenerator
{
    void Generate(ReportData data);
}

// 具体实现:PDF 报表生成器
public class PdfReportGenerator : IReportGenerator
{
    public void Generate(ReportData data)
    {
        Console.WriteLine("生成 PDF 报表");
    }
}

// 具体实现:Excel 报表生成器
public class ExcelReportGenerator : IReportGenerator
{
    public void Generate(ReportData data)
    {
        Console.WriteLine("生成 Excel 报表");
    }
}

// 新增格式:CSV 报表生成器(无需修改原有代码)
public class CsvReportGenerator : IReportGenerator
{
    public void Generate(ReportData data)
    {
        Console.WriteLine("生成 CSV 报表");
    }
}

// 报表服务:依赖抽象接口
public class ReportService
{
    private readonly IReportGenerator _generator;

    public ReportService(IReportGenerator generator)
    {
        _generator = generator; // 通过构造函数注入依赖
    }

    public void CreateReport(ReportData data)
    {
        _generator.Generate(data);
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        var data = new ReportData();
        
        // 需要 PDF 报表时
        var pdfService = new ReportService(new PdfReportGenerator());
        pdfService.CreateReport(data);

        // 需要 Excel 报表时
        var excelService = new ReportService(new ExcelReportGenerator());
        excelService.CreateReport(data);

        // 需要 CSV 报表时(扩展无需修改原有代码)
        var csvService = new ReportService(new CsvReportGenerator());
        csvService.CreateReport(data);
    }
}

关键改进点

  1. 抽象化:通过 IReportGenerator 接口定义稳定的报表生成契约。
  2. 多态:每个报表格式(PDF/Excel/CSV)都实现该接口,行为由具体子类决定。
  3. 依赖注入ReportService 依赖接口而非具体实现,支持动态切换报表生成器。

新增需求:添加 HTML 报表

若需新增 HTML 报表,只需:
  1. 创建 HtmlReportGenerator 类实现 IReportGenerator
  2. 在调用处注入新的生成器,无需修改现有类。
  3. public class HtmlReportGenerator : IReportGenerator
    {
        public void Generate(ReportData data)
        {
            Console.WriteLine("生成 HTML 报表");
        }
    }
    
    // 使用时直接注入新实现
    var htmlService = new ReportService(new HtmlReportGenerator());
    htmlService.CreateReport(data);

    开闭原则的其他应用场景

    1. 插件系统:通过接口定义插件规范,新插件只需实现接口。
    2. 策略模式:将算法封装为策略类,运行时动态切换。
    3. 事件驱动架构:通过事件和监听器实现功能扩展。

    注意事项

    • 过度抽象风险:不要为未来可能的需求过度设计,遵循 YAGNI(You Aren't Gonna Need It)原则。
    • 平衡点:对可能变化的部分应用 OCP,对稳定部分无需过度抽象。
    通过开闭原则,代码可以优雅地应对变化,同时保持稳定性和可维护性。
单例模式
软考

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

为什么使用单例模式

在应用系统开发中,我们常常有以下需求:

-在多个线程之间,比如初始化一次socket资源;比如servlet环境,共享同一个资源或者操作同一个对象

-在整个程序空间使用全局变量,共享资源

-大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。

因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。

实现单例步骤常用步骤

a)构造函数私有化

b)提供一个全局的静态方法(全局访问点)

c)在类中定义一个静态指针,指向本类的变量的静态变量指针