怎样在软件设计中选择使用GOF设计模式

在软件设计中选择使用GOF(Gang of Four)设计模式(即《设计模式:可复用面向对象软件的基础》一书中描述的23种设计模式)是一个需要仔细考虑的过程。以下是选择和应用这些设计模式的关键要点,并结合实例进行说明。

1. 明确需求和目标

  • 要点:在选择设计模式之前,首先要明确软件的需求和设计目标。例如,是否需要高内聚性、低耦合性,是否需要提高代码的可复用性或可扩展性。
  • 示例:如果项目要求在不影响现有代码的情况下添加新功能,那么“策略模式”(Strategy Pattern)可能是一个不错的选择。

2. 理解设计模式的核心思想

  • 要点:每种设计模式都有其特定的应用场景和核心思想。理解这些思想可以帮助你在适当的时候选择合适的模式。
  • 示例:“单例模式”(Singleton Pattern)的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这在需要全局控制或资源管理的场景中非常有用。

3. 分析问题域

  • 要点:分析正在解决的问题域,确定是否存在某些常见的设计问题,如对象创建、行为委托、结构组织等。
  • 示例:如果系统中有多个对象需要协同工作,并且这些对象之间的关系复杂,可以使用“中介者模式”(Mediator Pattern)来简化对象间的通信。

4. 选择合适的设计模式

  • 要点:根据问题域和需求选择最合适的设计模式。这需要对每个设计模式的适用场景有深入的理解。
  • 示例:如果需要定义一系列算法,并将它们封装起来,使它们可以互换,可以使用“策略模式”(Strategy Pattern)。例如,在一个支付系统中,可以使用策略模式来封装不同的支付方式(如信用卡、支付宝、微信支付等)。

5. 了解设计模式的设计意图

  • 要点:每种设计模式都有其特定的设计意图和解决的问题。理解这些意图可以帮助你判断该模式是否适合当前的设计问题。
  • 示例:“装饰器模式”(Decorator Pattern)的设计意图是动态地给一个对象添加额外的职责,而不影响其类的其他对象。这种模式通过将对象包装在装饰器类中来实现,适用于需要在不修改对象结构的情况下扩展其功能的情况。

6. 模式中各个类相互关联关系

  • 要点:设计模式中的类和对象通常有特定的关联关系,理解这些关系可以帮助你在实现时正确地组织代码结构。
  • 示例:“观察者模式”(Observer Pattern)中的“Subject”(主题)和“Observer”(观察者)之间的关联是一种“一对多”的关系,即一个主题可以有多个观察者。这种关系确保了当主题状态发生变化时,所有观察者都能接收到通知并做出相应反应。

7. 检查重新设计而采用设计模式的原因

  • 要点:在重新设计时采用设计模式通常是为了解决某个具体的设计问题,例如提高代码的可维护性、可扩展性或降低耦合性。了解这些原因可以帮助你更有针对性地选择和应用设计模式。
  • 示例:假设你有一个系统,其中有一个OrderService类,负责处理订单的创建、更新和取消。随着业务需求的增加,这个类变得越来越复杂,难以维护。此时,可以考虑使用“命令模式”(Command Pattern),将每个操作(如创建订单、更新订单、取消订单)封装成一个命令对象,从而简化OrderService类的设计。

8. 选择模式的考虑要点

  • 要点:在选择设计模式时,需要考虑模式的适用场景、模式的优缺点、模式的复杂性以及是否符合当前系统的设计原则。
  • 示例:在选择“策略模式”(Strategy Pattern)时,需要考虑系统中是否存在多个算法或行为,这些算法或行为可以在运行时切换。策略模式通过将算法封装在独立的策略类中,实现了算法的灵活切换,适用于需要动态选择算法的场景。

9. 考虑模式的优缺点

  • 要点:每个设计模式都有其优缺点,选择时需要权衡利弊。例如,有些模式可能会增加代码的复杂性,但同时也可能提高代码的可维护性。
  • 示例:“工厂模式”(Factory Pattern)可以简化对象的创建过程,但可能会引入额外的抽象层,增加代码的复杂性。

10. 实现和测试

  • 要点:选择设计模式后,进行具体的实现和测试。确保模式的应用确实解决了设计问题,并且没有引入新的问题。
  • 示例:在实现“观察者模式”(Observer Pattern)时,需要确保观察者能够正确地接收到主题的通知,并且不会出现循环依赖或内存泄漏的问题。

11. 持续优化和重构

  • 要点:软件设计是一个持续改进的过程。在使用设计模式后,可能会发现新的问题或改进的机会,这时需要进行重构和优化。
  • 示例:如果发现某个类承担了过多的职责,可以使用“桥接模式”(Bridge Pattern)来进行重构,将不同的职责分离到不同的类中。

示例1:使用“适配器模式”

假设你有一个旧系统,其中有一个LightBulb类,它有一个turnOn()方法。现在你需要将这个类集成到一个新的智能家居系统中,该系统期望所有设备都实现一个activate()方法。

适配器模式可以帮助你将LightBulb适配到新的系统中:

// 旧系统中的类
class LightBulb {void turnOn() {System.out.println("LightBulb is ON");}
}// 新系统的接口
interface Device {void activate();
}// 适配器类
class LightBulbAdapter implements Device {private LightBulb bulb;LightBulbAdapter(LightBulb bulb) {this.bulb = bulb;}@Overridepublic void activate() {bulb.turnOn();}
}// 使用适配器的新系统
public class SmartHomeSystem {public static void main(String[] args) {LightBulb bulb = new LightBulb();Device device = new LightBulbAdapter(bulb);device.activate(); // 输出: LightBulb is ON}
}

在这个例子中,通过使用“适配器模式”,我们能够复用旧的LightBulb类,并将其适配到新的系统中,而不需要修改旧类的代码。

示例2:使用“策略模式”处理支付方式

假设你正在设计一个支持多种支付方式(如信用卡、支付宝、微信支付)的支付系统。每种支付方式都有不同的处理逻辑,但它们都需要实现相同的支付接口。

// 支付接口
interface PaymentStrategy {void pay(double amount);
}// 信用卡支付
class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " using Credit Card");}
}// 支付宝支付
class AlipayPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " using Alipay");}
}// 微信支付
class WeChatPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " using WeChat");}
}// 支付上下文
class PaymentContext {private PaymentStrategy strategy;public PaymentContext(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(double amount) {strategy.pay(amount);}
}// 客户端代码
public class PaymentApp {public static void main(String[] args) {PaymentContext context = new PaymentContext(new CreditCardPayment());context.executePayment(100.0);context = new PaymentContext(new AlipayPayment());context.executePayment(200.0);context = new PaymentContext(new WeChatPayment());context.executePayment(300.0);}
}

在这个例子中,“策略模式”的设计意图是封装不同的支付算法,并通过统一的接口进行调用。各个支付类(如CreditCardPaymentAlipayPaymentWeChatPayment)都实现了相同的PaymentStrategy接口,它们之间通过PaymentContext类进行关联。这种方式使得支付系统在运行时可以灵活地切换不同的支付方式,而不需要修改支付逻辑。

总结

在软件设计中选择使用GOF设计模式需要综合考虑需求、问题域、模式的适用场景以及模式的优缺点。通过理解设计模式的核心思想,并结合具体的示例进行实践,可以有效地提高软件的可维护性、可扩展性和代码复用性。理解设计模式的设计意图、类之间的关联关系,以及重新设计的原因是非常重要的。通过这些要点,可以更有针对性地选择合适的模式,解决系统设计中的具体问题,提高代码的可维护性、可扩展性和灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/473624.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk)

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk) 1.计算模型介绍 使用GARCH(广义自回归条件异方差)模型计算VaR(风险价值)时,方差法是一个常用的方法。GARCH模型能够捕捉到金融时间序列数据中的波…

基于YOLOv8深度学习的智慧课堂学生专注度检测系统(PyQt5界面+数据集+训练代码)

本研究提出了一种基于YOLOv8深度学习的智慧课堂学生专注度检测系统,旨在实现对课堂中学生专注度的实时分析与评估。随着智慧教育的快速发展,学生的课堂表现和专注度成为评估学习效果的重要因素之一。然而,传统的专注度评估方法往往依赖于主观…

如何在 Ubuntu 上安装 Emby 媒体服务器

Emby 是一个开源的媒体服务器解决方案,它能让你整理、流媒体播放和分享你的个人媒体收藏,包括电影、音乐、电视节目和照片。Emby 帮你集中多媒体内容,让你无论在家还是在外都能轻松访问。它还支持转码,让你能够播放各种格式的内容…

HarmonyOS 如何获取设备信息(系统、版本、网络连接状态)

文章目录 前言一、引入模块和基本设备信息的获取二、设备硬件和系统版本信息的获取三、获取安全相关的设备信息四、获取网络状态信息五、完整 Demo 代码1. 导入所需模块2. 获取设备基本信息代码解析 3. 检测网络连接状态4. 执行函数 总结 前言 HarmonyOS 提供了一个强大的 API…

ES6笔记

ES6 ECMAScript ECMA组织:脚本语言标准化国际组织 1.什么是ES6 ES的全称是:ECMAScript,它是ECMA国际标准化组织制定的一项脚本语言的标准规范 2015年6月:ES2015 2016年6月:ES2016 2017年6月:ES2017 2018年…

常用命令之LinuxOracleHivePython

1. 用户改密 passwd app_adm chage -l app_adm passwd -x 90 app_adm -> 执行操作后,app_adm用户的密码时间改为90天有效期--查看该euser用户过期信息使用chage命令 --chage的参数包括 ---m 密码可更改的最小天数。为零时代表任何时候都可以更改密码。 ---M 密码…

游戏如何应对内存修改

据观察,近年来游戏黑灰产攻击角度多样化趋势显著,主要面临工作室、定制注入挂、模拟点击挂、内存修改挂、破解版等多方面安全问题。 据FairGuard数据统计,在游戏面临的众多安全风险中,「内存修改」攻击占比约为13%,主…

STM32单片机设计防儿童人员误锁/滞留车内警报系统

目录 目录 前言 一、本设计主要实现哪些很“开门”功能? 二、电路设计原理图 1.电路图采用Altium Designer进行设计: 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 近年来在车辆逐渐普及的情况下,由于家长的疏忽,将…

华为欧拉系统使用U盘制作引导安装华为欧拉操作系统

今天记录一下通过U盘来安装华为欧拉操作系统 华为欧拉操作系统是国产的一个类似于Centos的Linus系统 具体实现操作步骤: 先在官网下载欧拉系统镜像点击跳转到下载 准备好一个大于16g的U盘 ,用于制作U盘启动 下载一个引导程序制作工具,我使用…

Excel单元格中自适应填充多图

实例需求:在Excel插入图片时,由于图片尺寸各不相同,如果希望多个图片填充指定单元格,依靠用户手工调整,不仅费时费力,而且很难实现完全填充。如下图中的产品图册,有三个图片,如下图所…

51单片机应用开发---LCD1602显示应用

实现目标 1、了解LCD1602液晶屏; 2、掌握驱动程序的编写; 3. 具体目标:在屏幕上显示字符。 一、LCD1206概述 1.1 定义 LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块,可以显示ASCII码的标准字符和其它的一些内置…

问题分析与解决:Android开机卡动画问题分析

1. 问题背景及描述 在一个android设备的开发的项目中遇到了一个比较典型的问题:在主板贴片完成后,首次刷入androdi固件验证时,遇到了按键出发开机后,系统启动到android动画界阶段时一直循环卡在此阶段,无法进入桌面。如下如所示: 此问题在许多android项目的首次点亮阶段均…

nfs服务器--RHCE

一,简介 NFS(Network File System,网络文件系统)是FreeBSD支持的文件系统中的一种,它允许网络中的计 算机(不同的计算机、不同的操作系统)之间通过TCP/IP网络共享资源,主要在unix系…

黑马智慧商城项目学习笔记

目录 智慧商城项目创建项目调整初始化目录vant组件库vant按需导入和全部导入 项目中的vw适配路由设计配置登录页静态布局图形验证码功能request模块-axios封装api模块-封装图片验证码接口 Toast轻提示(vant组件)短信验证倒计时功能登录功能响应拦截器统一…

MySQL中将一个字符串字段按层级树状展开

水善利万物而不争,处众人之所恶,故几于道💦 文章目录 需求1.分析2.实现3.思路刨析表结构和数据 需求 数据库中有个字段如下 如何将其转换为如下形式: 1.分析 1.他的层级个数是不确定的,也就是说有的有2层有的有5…

IDEA优雅debug

目录 引言一、断点分类🎄1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧🎉3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…

springboot基于Web足球青训俱乐部管理后台系统开发(代码+数据库+LW)

摘 要 随着社会经济的快速发展,人们对足球俱乐部的需求日益增加,加快了足球健身俱乐部的发展,足球俱乐部管理工作日益繁忙,传统的管理方式已经无法满足足球俱乐部管理需求,因此,为了提高足球俱乐部管理效率…

STM32保护内部FLASH

在实际发布的产品中,在STM32芯片的内部FLASH存储了控制程序,如果不作任何保护措施的话,可以使用下载器直接把内部FLASH的内容读取回来,得到bin或hex文件格式的代码拷贝,别有用心的厂商即可利用该代码文件山寨产品。为此…

树的直径计算:算法详解与实现

树的直径计算:算法详解与实现 1. 引言2. 算法概述3. 伪代码实现4. C语言实现5. 算法分析6. 结论在图论中,树的直径是一个关键概念,它表示树中任意两点间最长路径的长度。对于给定的树T=(V,E),其中V是顶点集,E是边集,树的直径定义为所有顶点对(u,v)之间最短路径的最大值。…

无人机场景 - 目标检测数据集 - 车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍:无人机场景车辆检测数据集,真实场景高质量图片数据,涉及场景丰富,比如无人机场景城市道路行驶车辆图片、无人机场景城市道边停车车辆图片、无人机场景停车场车辆图片、无人机场景小区车辆图片、无人机场景车辆遮挡、车…