第五篇 设计模式的选择和应用 - 智慧选择与合理实践

第五篇:设计模式的选择和应用 - 智慧选择与合理实践

1. 如何识别和选择合适的设计模式

  1. 理解问题本质:首先,要深入理解面临的问题或需求。分析系统中的对象、它们之间的关系以及可能出现的变化点。了解哪些部分需要灵活性、扩展性或者解耦。

  2. 模式匹配:根据问题特征对照已知的设计模式,识别出可能适用的模式类型。例如,若遇到对象创建过程复杂且需要解耦,可以考虑使用工厂方法、抽象工厂或建造者模式;若需处理对象间复杂的交互逻辑,则可考虑责任链、中介者或观察者模式等。

  3. 权衡比较:对于多种可能适用的设计模式,进行对比分析,考虑每种模式带来的优缺点。如复用程度、代码可读性、维护成本、性能影响等因素。

  4. 实际场景结合:确保所选模式符合项目的具体应用场景,同时考虑到系统的未来发展变化。确保选择的设计模式能够适应业务需求的演变,而不是仅仅为了应用模式而模式化设计。

2. 设计模式的权衡和适用场景分析

在选择和应用设计模式时,必须认识到每个模式都有其适用范围和局限性:

  • 一些模式可能会增加系统的复杂性,特别是在小型项目中过度使用。
  • 有些模式可能提高代码的可读性和复用性,但可能导致运行时性能下降(如工厂方法产生的类实例增多)。
  • 有的模式如单例和全局状态可能会导致难以测试和扩展。

因此,在决定采用某个设计模式时,应综合评估该模式在当前场景下的价值,包括是否解决了特定问题、是否会带来其他潜在问题以及未来可能的需求变化。

3 设计模式在实际项目中的应用案例分享

3.1. Spring框架中的依赖注入:Spring通过实现控制反转(IoC)和依赖注入(DI),实际上采用了工厂方法、策略和代理等模式,使得组件间的耦合度降低,更易于测试和维护。

Spring框架通过依赖注入(DI)实现控制反转(IoC),在实际应用中确实采用了工厂方法、策略和代理等模式的变体。下面分别以代码片段的形式说明:

1. 工厂方法模式的体现:BeanFactory与ApplicationContext

Spring中的BeanFactory接口是IoC容器的基本实现,它扮演了抽象工厂角色,负责管理和创建各种对象(即bean)。而ApplicationContext作为BeanFactory的高级实现,更加强大且功能丰富。

// Spring BeanFactory 实现了工厂方法模式
public interface BeanFactory {Object getBean(String name) throws BeansException;// ... 其他获取bean的方法
}// 通常我们使用 ApplicationContext 来获取 bean
public class ClassPathXmlApplicationContext implements ApplicationContext {public Object getBean(String name) throws BeansException {// ...}
}

2. 策略模式的体现:例如数据源配置切换

Spring允许通过Java配置或XML配置定义多个数据源,并根据运行时条件选择不同的数据源策略。

@Configuration
public class DataSourceConfig {@Autowiredprivate Environment env;@Bean@Primarypublic DataSource primaryDataSource() {return DataSourceBuilder.create().url(env.getProperty("primary.datasource.url")).username(env.getProperty("primary.datasource.username")).password(env.getProperty("primary.datasource.password")).build();}@Beanpublic DataSource secondaryDataSource() {return DataSourceBuilder.create().url(env.getProperty("secondary.datasource.url")).username(env.getProperty("secondary.datasource.username")).password(env.getProperty("secondary.datasource.password")).build();}// 在其他类中注入时可以按需选择数据源策略@Servicepublic class SomeService {@Autowiredprivate DataSource dataSource; // 这里注入的数据源可能是primaryDataSource也可能是secondaryDataSource// 根据业务需求决定使用哪个数据源// ...}
}

3. 代理模式的体现:AOP和动态代理

Spring通过AOP(面向切面编程)机制实现了对目标对象的代理,如事务管理、日志记录等。

@Aspect
@Component
public class TransactionalAdvice {@Before("execution(* com.example.service.*.*(..))")public void before(JoinPoint joinPoint) {// 开启事务的逻辑}@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")public void afterReturning(Object result) {// 提交事务的逻辑}// 其他通知...
}@Service
public class UserServiceImpl implements UserService {// 这个UserService的实例在Spring IoC容器中实际上是被代理的对象@Overridepublic void addUser(User user) {// 添加用户逻辑}
}

在这个例子中,Spring通过生成代理对象来拦截目标方法调用,从而实现了诸如事务管理这样的横切关注点。这就是代理模式在Spring AOP中的应用。Spring既可以使用JDK动态代理,也可以使用CGLIB库进行代理实现。

3.2. 电商购物车模块:在构建购物车功能时,可以使用组合模式来表示商品项及其子项(如套装内包含多个单品),利用观察者模式实现实时总价计算,当添加或删除商品时通知观察者更新总价。

由于文本交互的限制,下面将简要说明如何使用组合模式和观察者模式来实现电商购物车模块,并给出部分伪代码以展示关键逻辑。

1. 组合模式(Composite Pattern)

首先,定义一个商品接口Product以及它的两种实现:单品SingleProduct和套装BundleProduct。套装内可以包含多个子商品项,即采用组合结构。

// 商品抽象类或接口
public abstract class Product {protected double price;public abstract void add(Product product);public abstract void remove(Product product);// ... 其他如获取价格、名称等方法
}// 单品商品
public class SingleProduct extends Product {private String name;public SingleProduct(String name, double price) {this.name = name;this.price = price;}@Overridepublic void add(Product product) {throw new UnsupportedOperationException("单个商品不能添加子商品");}@Overridepublic void remove(Product product) {throw new UnsupportedOperationException("单个商品没有子商品可移除");}// ...
}// 套装商品,内部维护一个产品列表
public class BundleProduct extends Product {private List<Product> productList = new ArrayList<>();public void add(Product product) {productList.add(product);}public void remove(Product product) {productList.remove(product);}@Overridepublic double getPrice() {double totalPrice = 0;for (Product item : productList) {totalPrice += item.getPrice();}return totalPrice;}// ...
}

2. 观察者模式(Observer Pattern)

定义一个Cart购物车类,它持有商品集合并实现了观察者模式。当商品数量变化时,购物车总价自动更新。

import java.util.ArrayList;
import java.util.List;// 购物车接口,同时作为观察目标(Observable)
public interface Cart extends ObserverTarget {void addItem(Product product);void removeItem(Product product);double getTotalPrice();// 注册和删除观察者的方法由ObserverTarget提供
}// 购物车实现
public class ShoppingCart implements Cart {private List<Product> cartItems = new ArrayList<>();private List<Observer> observers = new ArrayList<>();@Overridepublic void addItem(Product product) {cartItems.add(product);notifyObservers(); // 添加商品后通知所有观察者}@Overridepublic void removeItem(Product product) {cartItems.remove(product);notifyObservers(); // 移除商品后通知所有观察者}@Overridepublic double getTotalPrice() {double totalPrice = 0;for (Product item : cartItems) {totalPrice += item.getPrice();}return totalPrice;}// 实现ObserverTarget接口中的注册与通知方法@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(this); // 更新观察者(例如总价显示组件)}}
}// 观察者接口
public interface Observer {void update(Cart cart);
}// 总价显示组件作为观察者
public class TotalPriceDisplay implements Observer {@Overridepublic void update(Cart cart) {double totalPrice = cart.getTotalPrice();// 更新UI或其他操作,显示最新的总价}
}

在这个例子中,当我们向购物车中添加或删除商品时,购物车会触发notifyObservers()方法通知所有的观察者(如总价显示组件),观察者通过调用update()方法来获取最新的购物车总价并进行相应更新。这样就实现了在添加或删除商品时实时计算并更新购物车总价的功能。

3.3. GUI事件处理:GUI编程中广泛使用了事件监听机制,这背后隐藏着观察者模式的应用,当用户触发按钮点击等事件时,相应的处理器会接收到通知并执行相应操作。

4. 避免设计模式的滥用和过度设计

设计模式虽好,但如果滥用或过度设计,反而会导致代码过于复杂,增加理解和维护难度。以下是一些避免滥用和过度设计的建议:

  • 只有在真正需要解决特定设计问题时才引入设计模式,不要为模式而模式。
  • 在设计初期保持简洁,随着需求迭代逐渐优化结构,适时引入设计模式以应对复用、扩展和解耦的需求。
  • 对于简单的场景,优先选择简单直观的设计方案,无需刻意追求高级设计模式。
  • 在团队协作中建立良好的设计规范,明确何时、何地以及如何恰当地使用设计模式。

总结来说,选择和应用设计模式的关键在于深入理解其原理,把握好适用的时机,并结合实际情况灵活运用,最终目的是为了提升软件的可读性、可维护性和可扩展性,而非盲目追求理论上的完美设计。

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

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

相关文章

【管理篇 / 恢复】❀ 07. macOS下用命令刷新固件 ❀ FortiGate 防火墙

【简介】随着苹果电脑的普及&#xff0c;很多管理员都会通过苹果电脑对飞塔防火墙进行管理。当防火墙需要命令状态下刷新固件时&#xff0c;在macOS下用命令刷新固件&#xff0c;将会是一个小小的挑战。 首先是硬件的连接&#xff0c;USB配置线的USB一头&#xff0c;接入MAC的U…

OpenGL如何基于glfw库 进行 点线面 已解决

GLFW是现在较流行、使用广泛的OpenGL的界面库&#xff0c;而glut库已经比较老了。GLEW是和管理OpenGL函数指针有关的库&#xff0c;因为OpenGL只是一个标准/规范&#xff0c;具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多&#xff0c;它大多数函数的位置…

内网DNS隐蔽隧道搭建之iodine工具

iodine iodine是基于C语言开发的&#xff0c;分为服务端和客户端。iodine支持转发模式和中继模式。其原理是&#xff1a;通过TAP虚拟网卡&#xff0c;在服务端建立一个局域网&#xff1b;在客户端&#xff0c;通过TAP建立一个虚拟网卡&#xff1b;两者通过DNS隧道连接&#xf…

解析消费全返---看如何使用模式探索餐饮业新航标。

每天五分钟讲解一个商业模式&#xff0c;大家好我是模式策划啊浩。 亲爱的餐饮业朋友们&#xff0c;今天我想和大家分享一个话题&#xff0c;那就是消费增值模式在餐饮行业的应用。近年来&#xff0c;随着消费者需求的不断升级和市场竞争的加剧&#xff0c;消费增值模式为餐饮…

uniapp中uview组件库丰富的Slider 滑动选择器的使用方法

目录 #平台差异说明 #基本使用 #设置最大和最小值 #设置步进值 #禁用状态 #自定义按钮的内容和样式 #自定义滑动选择器整体的样式 #此页面源代码地址 #API #Props #Slider Events 该组件一般用于表单中&#xff0c;手动选择一个区间范围的场景。 说明 该组件在H5&…

IntelliJ IDEA 如何配置git

在 IntelliJ IDEA 中配置 Git 的步骤如下&#xff1a; 打开 IntelliJ IDEA。找到 File–>Setting–>Version Control–>Git–>Path to Git executable。在 Git 的安装路径下找到 cmd 文件夹下的 git.exe&#xff0c;到此 Git 配置已完成。

服务器为什么大多用 Linux?

服务器为什么大多用 Linux&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「Linux的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&#…

Oracle的日期加减

一、直接加减数字 select sysdate 当前时间,sysdate 1 加一天,sysdate - 1 减一天,sysdate (1 / 24) 加一小时,sysdate (1 / 24 / 60) 加一分钟,sysdate (1 / 24 / 60 / 60) 加一秒钟 from dual;二、add_months…

如何制作可预约的上门维修服务小程序?

上门维修服务已经成为人们日常生活中不可或缺的一部分。为了满足这一需求&#xff0c;我们学习如何无经验自己制作上门维修服务小程序。 首先&#xff0c;打开乔拓云-门店系统的后台&#xff0c;可以看到有很多各行各业的模版。这些模版涵盖了各种行业&#xff0c;包括家电维修…

Spring Security 6.x 系列(14)—— 会话管理之源码分析

一、前言 在上篇 Spring Security 6.x 系列(13)—— 会话管理之会话概念及常用配置 Spring Security 6.x 系列(14)—— 会话管理之会话固定攻击防护及Session共享 中了清晰了协议和会话的概念、对 Spring Security 中的常用会话配置进行了说明,并了解会话固定攻击防护…

vuex基础用法 与 辅助函数使用

效果图 index.js文件 import Vue from "vue"; import Vuex from vuexVue.use(Vuex)export default new Vuex.Store({state: {shopsList: [{goodsName: "手机1", //商品名goodsAmount: 0, //购买的商品数量goodsPrice: 100, //单个商品价格totalPrice: 0,i…

国信集团通过ZStack cloud构建云基础设施

为有效推进集团信息化发展的进程&#xff0c;国信集团选择云轴科技ZStack Cloud云平台整合现有资源&#xff0c;构建统一的资源池。ZStack Cloud云平台具备先进性和可扩展性&#xff0c;充分满足了国信集团现有及未来的业务需求&#xff1b;同时&#xff0c;国信集团将在两中心…

数通基础知识总结

1. 基础概念 1.1. 通信基本原理 通信基本原理涉及信息的生成、编码、传输和解码的过程。在实际应用中&#xff0c;例如电话通信&#xff0c;信息通过话筒转换成模拟信号&#xff0c;经过传输线路传递到接收端&#xff0c;再由耳机解码还原为可理解的信息。 1.2. 信道和信号 …

Required request body is missing报错及解决

今天&#xff0c;我在尝试调用后端接口展示文章数据时遇到了错误&#xff0c;错误原因是请求体缺失&#xff0c; 但是我明明传了参数 然后我找了很久错误原因&#xff0c;发现在之前跟着写的一个差不多的功能时&#xff0c;请求方式是post 而我写的确是get 将get改为post后&…

PHP 基础编程 2

文章目录 时间函数dategetdatetime 使用数组实现登录注册和修改密码简单数组增加元素方法修改元素方法删除元素方法 具体实现方法数组序列化数组写入文件判断元素是否在关联数组中&#xff08;登录功能实现&#xff09;实现注册功能实现修改admin用户密码功能 时间函数 时区&am…

docker容器的常见命令

docker 及docker-compose network概念及操作详解 ## network相关的操作# 列出所有当前主机上或Swarm集群上的网络docker network ls#查看网络详情docker network inspect network名称# 清除未使用的docker网络docker network prune -f# 创建网络ocker network create -d brid…

蓝牙简学(二)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、服务和特性二、数据收发三、UUID 一、服务和特性 service、characteristic 下面的图是蓝牙协议的整体架构&#xff0c; 1.物理层&#xff1a;负责无线电波的收…

x-cmd pkg | procs - ps 命令的现代化替代品

目录 简介首次用户功能特点类似工具进一步阅读 简介 procs 是用 Rust 编写的 ps 替代品&#xff0c;用于显示有关任务进程的信息 首次用户 使用 x procs 即可自动下载并使用 在终端运行 eval "$(curl https://get.x-cmd.com)" 即可完成 x 命令安装, 详情参考 x-cmd…

python学完之后可以做什么,python学完可以做什么

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python学完可以做哪些工作&#xff0c;python学完之后可以做什么&#xff0c;今天让我们一起来看看吧&#xff01; Python是一种全栈的开发语言&#xff0c;你如果能学好Python&#xff0c;前端&#xff0c;后端&#x…

Spring实现IoC:依赖注入/构造注入

● 控制反转&#xff0c;反转的是什么&#xff1f; ○ 将对象的创建权利交出去&#xff0c;交给第三方容器负责。 ○ 将对象和对象之间关系的维护权交出去&#xff0c;交给第三方容器负责。 ● 控制反转这种思想如何实现呢&#xff1f; ○ DI&#xff08;Dependency Injection&…