当前位置: 首页 > news >正文

《设计模式》

饿汉模式

public class SingletonEager {// 1. 静态常量,在类加载时就完成实例化private static final SingletonEager INSTANCE = new SingletonEager();// 2. 私有构造器private SingletonEager() {}// 3. 静态公有方法public static SingletonEager getInstance() {return INSTANCE;}
}
  • 这个实例我百分百会用,而且早点创建没坏处
  • 如果这个数据库连接是程序运行的核心依赖(比如权限数据库),那么宁愿在启动时就发现连接失败,而不是运行到一半才出错。
  • 配置信息在程序启动时就必须准备好

懒汉式的使用场景是——“这个实例可能用不到,或者创建它太费劲,等真要用了再说”。

public class SingletonDCL {// 关键:使用volatile禁止指令重排序private static volatile SingletonDCL instance;private SingletonDCL() {}public static SingletonDCL getInstance() {if (instance == null) { // 第一次检查,避免不必要的同步synchronized (SingletonDCL.class) {if (instance == null) { // 第二次检查,确保只有一个线程创建实例instance = new SingletonDCL();}}}return instance;}
}

简单工厂

eg

我需要根据不同的条件,创建出一系列相关但又不同的对象,但不想让调用者操心具体的创建细节、把易变的创建逻辑封装起来,避免"牵一发而动全身"、重复代码出现在同一个类中时,用方法抽象;当重复代码出现在不同类中时,用类抽象(工厂模式)。

public class PaymentFactory {public static Payment createPayment(PaymentType type) {switch (type) {case ALIPAY:return new AlipayPayment();case WECHAT_PAY:return new WechatPayment();case CREDIT_CARD:return new CreditCardPayment();default:throw new IllegalArgumentException("不支持的支付类型");}}
}// 在业务代码中
public class OrderService {public void processPayment(Order order, PaymentType paymentType) {// 业务代码不关心具体创建哪个支付对象Payment payment = PaymentFactory.createPayment(paymentType);payment.pay(order.getAmount());// 后续业务逻辑...}
}
  • 没有工厂:就像你想吃一道“宫保鸡丁”。

    • 你需要自己去菜市场买鸡肉、花生、葱姜蒜(new AlipayPayment()),然后自己掌握火候、调料来烹饪。

    • 问题:你(客户端)和所有原材料(具体类)紧密耦合,过程复杂。

  • 有简单工厂:就像你去一家餐馆点一道“宫保鸡丁”。

    • 你只需要对服务员(工厂)说:“我要一份宫保鸡丁(传入参数type)。”

    • 服务员通知后厨(工厂内部),后厨用你不知道的方式把菜做好端给你。

    • 好处:你(客户端)只关心“菜(接口)”好不好吃,不关心它具体是怎么做出来的。你和后厨的复杂工作解耦了。

好像只是把if-else从A类挪到了B类,确实没体现出明显优势。

方案一:不使用工厂(灾难版)

public class UserService {public void getUser() {// 创建MySQL连接(假设这段代码很复杂)String mysqlUrl = "jdbc:mysql://localhost:3306/test";String mysqlUser = "root";String mysqlPassword = "123456";MysqlConnection conn = new MysqlConnection(mysqlUrl, mysqlUser, mysqlPassword);// 使用连接查询用户...}
}public class OrderService {public void getOrder() {// 又要在另一个地方创建MySQL连接!String mysqlUrl = "jdbc:mysql://localhost:3306/test"; String mysqlUser = "root";String mysqlPassword = "123456";MysqlConnection conn = new MysqlConnection(mysqlUrl, mysqlUser, mysqlPassword);// 使用连接查询订单...}
}public class ReportService {public void getReport() {// 现在要创建Oracle连接,又是一堆配置!String oracleUrl = "jdbc:oracle:thin:@localhost:1521:orcl";String oracleUser = "admin";String oraclePassword = "oracle123";String driverClass = "oracle.jdbc.driver.OracleDriver";OracleConnection conn = new OracleConnection(oracleUrl, oracleUser, oraclePassword, driverClass);// 使用连接生成报表...}
}

问题暴露:

  1. 代码重复:相同的MySQL配置代码散落在各个地方

  2. 难以维护:如果要改数据库密码,要修改所有地方!

  3. 容易出错:万一某个地方配置写错了...

  4. 职责混乱:业务Service类还要负责技术细节的数据库连接创建


方案二:使用简单工厂(优雅版)

// 简单工厂 - 专门负责处理复杂的对象创建
public class ConnectionFactory {// 所有创建逻辑集中在这里!public static Connection createConnection(String dbType) {if ("mysql".equals(dbType)) {// MySQL的复杂创建逻辑String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "123456";// 可能还有连接池配置、超时设置等等...return new MysqlConnection(url, user, password);} else if ("oracle".equals(dbType)) {// Oracle的复杂创建逻辑  String url = "jdbc:oracle:thin:@localhost:1521:orcl";String user = "admin";String password = "oracle123";String driverClass = "oracle.jdbc.driver.OracleDriver";// 可能还有事务配置、字符集设置等等...return new OracleConnection(url, user, password, driverClass);}throw new IllegalArgumentException("不支持的数据库类型");}
}// 各个Service类 - 只关注业务,不关心技术细节
public class UserService {public void getUser() {// 一行代码搞定!不用关心具体实现Connection conn = ConnectionFactory.createConnection("mysql");// 使用连接查询用户...}
}public class OrderService {public void getOrder() {// 同样一行代码搞定!Connection conn = ConnectionFactory.createConnection("mysql");// 使用连接查询订单...}
}public class ReportService {public void getReport() {// 还是一行代码搞定!Connection conn = ConnectionFactory.createConnection("oracle");// 使用连接生成报表...}
}

现在看出区别了吗?

场景不使用工厂使用简单工厂
改数据库密码需要修改UserService, OrderService... 等所有用到的地方只需要修改ConnectionFactory一个地方
添加新数据库要在每个需要的地方添加新的创建逻辑只在ConnectionFactory中添加一个新分支
代码复杂度每个Service都包含技术细节,代码臃肿每个Service都很干净,只关注业务逻辑
出错概率容易在某个Service里写错配置配置集中管理,保证一致性

核心价值总结

简单工厂的真正价值在于:

  1. 封装复杂创建逻辑:当对象的创建过程很复杂(需要很多参数、配置、初始化)时,工厂把这些"脏活累活"都藏起来。

  2. 提供统一入口:无论在哪里需要该对象,都通过同一个工厂方法获取,保证行为一致。

  3. 隔离变化:当创建逻辑需要修改时(比如MySQL连接要增加SSL配置),影响范围被控制在工厂内部,不会波及业务代码。

观察者模式

一种一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并被自动更新。发布-订阅模式。

eg:

在客户端开发中,比如有一个用户数据模型UserModel(被观察者),多个UI界面,如个人资料页、头像设置页(观察者),都订阅了它。当用户修改姓名后,UserModel通知所有相关界面,它们就自动更新显示了。这完美解耦了数据和UI。“这和我后端用到的消息队列(如Kafka)的思想很像,都是解耦生产者和消费者

“我认为观察者模式之所以如此重要,是因为它解决了软件开发中一个最根本的矛盾:即‘事件源’与‘事件处理方’数量上的不对等。

一个事件(比如用户数据更新),可能被零个、一个或多个未知的模块所关心。如果让事件源去硬编码调用所有处理方,耦合会非常严重。而观察者模式通过一个注册/通知的中间层,完美地将这种‘一对多’的网状依赖,解耦成了‘一对一’的线性依赖。

这和我后端熟悉的Kafka完全一样,Kafka作为消息队列,解耦的是服务;观察者模式解耦的是对象。思想是共通的。”



“观察者模式通过解耦带来了巨大的灵活性,但我也思考过它引入的代价。主要有两点:

  1. 通知的无序性:多个观察者的通知顺序如果很重要,就需要引入复杂的优先级管理机制。

  2. 生命周期与内存泄漏:特别是在客户端,如果观察者(如一个UI页面)被销毁前没有及时取消注册,就会导致被观察者持有它的引用,无法被垃圾回收,从而引发内存泄漏。

    内存泄漏的意思就是:
    一个对象已经不再被使用了
    但由于某些意外的引用,垃圾回收器无法回收它
    导致这个对象占用的内存永远无法释放
    如果这种情况反复发生,最终会导致内存耗尽

所以,这是一个典型的‘用运行时复杂度换取代码结构灵活性’ 的权衡。在Android中,为什么LiveData要配合Lifecycle使用?本质上就是为了自动化解决我刚刚提到的生命周期问题。”


http://www.dtcms.com/a/482543.html

相关文章:

  • 不/可重入函数
  • 前端性能优化?
  • 快应用TypeError: The ‘compilation‘ argument must be an instance of Compilation错误
  • php网站开发实用技术练习题网站源码整站打包
  • vue前端面试题——记录一次面试当中遇到的题(7)
  • 算法9.0
  • 商丘哪里做网站网页加速器怎么开
  • 未来之窗昭和仙君(十九)商用虚拟数字金额键盘——东方仙盟筑基期
  • 每日小知识点:10.14 webpack 有几种文件指纹
  • 怎样撰写企业网站建设方案wordpress主题layui
  • 地区性门户网站是什么意思阿里云做网站可以吗
  • 怎样批量在图片上加12345的数字编号?实用教程分享
  • 【avalonia教程】10数据绑定语法格式
  • 图像分类数据集难度怎么评?
  • 管理系统有哪些布局框架,比如左右,上下,F型号,T型等
  • 设计网站意味着什么如何用手机制作app
  • 网站跳出率 查询免费建立自己喜欢的
  • 纵向合并和横向合并工作表的思路
  • 图像锐化的魔法棒:深入浅出理解USM锐化算法
  • PHP网站开发都需要学什么做网站用什么电脑配置
  • Naive RAG
  • 做网站开源框架本土广告公司
  • MacOS 安装器安装,正在等待其他安装完成
  • 惠洋科技H5442L 100V高耐压LED恒流驱动芯片80V72V60V48V降压12V9V6V1.2Aic方案 PWM+模拟调光
  • 网站自建设需要买什么时候开始免费推广链接
  • ElasticSearch生产环境问题集锦
  • 深圳官网建站服务商网站建设空间申请
  • RAG系统向量化存储技术深度解析:双索引架构与批量处理实践
  • 复习总结最终版:计算机网络
  • wordpress导航站模版海南省建设注册中心网站