设计模式概述(卷一)

本文介绍了设计模式的重要性,分类以及学习设计模式的关键点。文章深入探讨了面向对象设计原则SOLID,包括单一职责原则、开闭原则、里式替换原则、接口隔离原则、依赖倒置原则以及迪米特法则,强调了每个原则在实际编程中的应用和价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模式:在特定环境下的一套用来解决某一类重复出现的问题的解决方案。

0x00 为什么需要设计模式

避免做一些重复的设计、编写一些重复的代码。

0x01 设计模式的分类

设计模式可分为创建型(Creational)、结构型(Structural)、行为型(Behavioral)三种。

设计模式一览表

模式类型模式名称使用频率
创建型单例Singleton常用
创建型建造者Builder常用
创建型工厂方法Factory Method常用
创建型抽象工厂Abstract Factory常用
创建型简单工厂Simple Factory
创建型原型Prototype
结构型组合模式Composite常用
结构型装饰者Decorator常用
结构型代理Proxy常用
结构型外观Facade常用
结构型桥接Bridge
结构型享元Flyweight
结构型适配器Adapter Pattern
行为型迭代器Iterator常用
行为型观察者Obverser常用
行为型策略Strategy常用
行为型命令Command常用
行为型模板方法Template Method常用
行为型职责链Chain of Responsibility
行为型解释器Interpreter
行为型中介者Mediator
行为型备忘录Momento
行为型状态State
行为型访问者Visitor

0x10 学习设计模式要点

模式是为了解决问题而产生的,不是用来创造问题的。

  • 要清楚具体模式能解决什么问题,有哪些前提条件
  • 不可滥用模式,不能为了使用模式而使用,只有当遇到了问题,并且经过分析发现在该情况下使用某某模式可以解决问题才去使用它。

0x11 面对对象设计原则SOLID

  • 单一职责:Simple Responsibility一个类只负责一个领域的职责。
  • 开闭:Open-Close对扩展开放,对修改关闭。软件实体应尽量在不修改原有代码的情况下进行扩展。
  • 里式替换:Liskov Substitution任何父类出现的地方,都能使用子类替代。
  • 接口隔离:Interface Segregation使用多个单一的接口,而不是单一的集成接口。
  • 依赖倒置:Dependence Inversion具体依赖抽象,上层依赖下层。

另外还有组合/聚合复用Composite Reuse :尽量使用对象组合,而不是继承;以及迪米特软件实体应当尽可能少地与其他实体发生相互作用。

单一职责原则

设计一个客户信息图形统计模块,主要包含获取数据库连接信息,查询客户信息,图表的创建和展示;初始设计方案如下。

显然,该方式违背了单一职责原则,CustomerDataChart承担了太多职责,一旦其他类需要使用连接数据库或者查询客户信息等方法,都需要对CustomerDataChart进行修改。尝试将其分解为3个类。

  1. DBUtil类,只负责连接数据库。
  2. CustomerDAO类,只负责客户信息的CRUD。
  3. CustomerDataChart,只负责图表的创建和显示。

重构后的结构图

开闭原则

开闭原则是面向对象编程的目标。

以下代码违背了开闭原则,一旦新增新的图表,需要改动原有代码。

public void display(String type){
    if (type.equals("pie")) {  
        PieChart chart = new PieChart();  
        chart.display();  
    }  
    else if (type.equals("bar")) {  
        BarChart chart = new BarChart();  
        chart.display();  
    }
}  

下图则为一种符合开闭原则的架构,如遇到新增图表,只需要增加AbstractChart的实现类即可。

里式替换原则

下图展示了这一过程。p1的模式不利于扩展,p2中传递的参数是父类,扩展只需要继承即可,无需改动sender。

接口隔离原则

这里的接口是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象。

当一个“接口”承担太多功能时,由如下缺点。

  • 很多时候用户只需要其中的一个功能,但必须实现接口的所有方法,产生了很多空方法。
  • 使得client端见到了不应该看到的方法。

依赖倒置原则

依赖倒转原则是面向对象设计的主要实现机制之一。抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

  • 在程序代码中传递参数时,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。
  • 程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展。
  • 在实现依赖倒转原则时,我们需要针对抽象层编程,将具体类的对象通过依赖注入DI的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。

在编写程序过程中,多数情况下这三个设计原则会同时出现,开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段,它们相辅相成,相互补充。

合成复用原则

通过继承来复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不能在运行时发生改变,没有足够的灵活性;

  • p1中使用了继承复用,当需要把数据库从MySQL升级为Oracle数据库时,需要修改CustomerDAO中的代码,或者修改DBUtil中的代码,违背了开闭原则。
  • p2中使用了合成复用,当需要把数据库从MySQL升级为Oracle数据库时,根据里式替换原则,只需要新增DBUtil的实现类OracleDBUtil并注入到CustomerDAO即可。

迪米勒法则

不要和“陌生人”说话、只与你的直接朋友通信,直接朋友包含以下几种。

  • 对象本身this。
  • 以参数形式传入到当前对象方法中的对象。
  • 当前对象的成员对象;
  • 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
  • 当前对象所创建的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值