设计模式

🚏 导论 设计模式是软件开发中解决常见问题的最佳实践,它们凝聚了多年的工程经验与智慧,是提升代码质量、可维护性和灵活性的关键工具。设计模式通过提供一套通用的解决方案,使得开发人员能够应对不同的需求和挑战,而不必从零开始设计系统架构。 在这部分内容中,我将通过学习经典的《大话设计模式》一书,深入理解和探讨23种设计模式。从实际应用的角度出发,我们不仅关注每种模式的定义和结构,更会探索它们在现实世界中的应用场景。 💻 代码 Java代码实现 🔍 索引 设计模式的七大原则 单一职责原则(Single Responsibility Principle) 开放-封闭原则(Open Closed Principle) 依赖倒置原则(Dependency Inversion Principle) 里氏替换原则(Liskov Substitution Principle) 接口隔离原则(Interface Segregation Principle) 迪米特法则(Law of Demeter) 合成复用原则(Composite Reuse Principle) 设计模式的三大类 创建性(Creational Pattern) 抽象工厂模式(Abstract Factory Pattern) 建造者模式(Builder Pattern) 工厂方法模式(Factory Method Pattern) 原型模式(Prototype Pattern) 单例模式(Singleton Pattern) 结构性(Structural Pattern) 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 组合模式(Composite Pattern) 装饰模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) 行为型(Behavioral Pattern) 观察者模式(Observer Pattern) 模板模式(Template Pattern) 命令模式(Command Pattern) 状态模式(State Pattern) 职责链模式(Chain of Responsibility Pattern) 解释器模式(Interpreter Pattern) 中介者模式(Mediator Pattern) 访问者模式(Visitor Pattern) 策略模式(Strategy Pattern) 备忘录模式(Memento Pattern) 迭代器模式(Iterator Pattern)

January 7, 2025 · 1 min · 88 words · Rex

装饰模式(Decorator Pattern)

🚏 导论 装饰模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。当现有目标功能不足的时候,需要增强时,可以考虑使用装饰模式。 装饰模式把每个要装饰的代码放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。 装饰器常在面向切面编程(AOP)中使用,比如日志、事务、权限等功能。 🚦 结构 UML类图 classDiagram class Component{ <<interface>> +operation() } class ConcreteComponent{ +operation() } class Decorator{ <<abstract>> -component: Component +operation() } class ConcreteDecoratorA{ -addedState +operation() } class ConcreteDecoratorB{ +operation() -AddedBehavior() } Component <|-- ConcreteComponent Component <|-- Decorator Decorator o-- Component Decorator <|-- ConcreteDecoratorA Decorator <|-- ConcreteDecoratorB Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。 装饰模式是利用setComponent来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。 基本代码 Component类 public interface Component { void operation(); } ConcreteComponent类 public class ConcreteComponent implements Component { @Override public void operation() { System.out.println("具体对象的操作"); } } Decorator类 ...

January 11, 2025 · 4 min · 751 words · Rex

里氏替换原则(Liskov Substitution Principle)

🚏 导论 里氏替换原则(LSP):子类型必须能够替换掉它们的父类型。 里氏替换原则是Barbara Liskov女士在1988年发表的,A behavioral notion of subtyping, 具体的数学定义如下所示:If S is a declared subtype of T, objects of type S should behave as objects of type T are expected to behave, if they are treated as objects of type T。用大白话翻译就是一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。 由于有里氏替换原则,才使得开放-封闭成为了可能,正是由于子类性的可替换性才使得使用父类类型的模块在无需修改的情况下可以扩展。 🎬 场景 场景一:🐒 动物世界 因为了有了这个原则,使得继承复用成为了可能,只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。猫是继承动物类的,以动物的身份拥有吃、喝、跑、叫等行为,可当某一天,我们需要狗、牛、羊也拥有类似的行为,由于它们都是继承于动物,所以除了更改实例化的地方,程序其他处不需要改变。

January 10, 2025 · 1 min · 47 words · Rex

依赖倒转原则(Dependency Inversion Principle)

🚏 导论 依赖倒转原则 A. 高层模块不应该依赖低层模块。两个都应该依赖抽象。 B. 抽象不应该依赖细节。细节应该依赖抽象。 🎬 场景 场景一:📦 修电脑 当电脑出现蓝屏时,通常考虑是否时内存坏了或是内存条与主板接触不良。如果是内存坏了,那么就需要更换内存条,如果是内存条与主板接触不良,那么就需要重新插拔内存条。得益于电脑部件以及相关接口的设计,只需要了解简单的计算机知识,就可以轻松的定位问题并维修电脑了。他们的设计中体现了依赖倒转原则,当然还有其他的原则(单一职责原则、开放-封闭原则)。依赖倒转原则原话是说抽象不应该依赖细节,细节应该依赖于抽象,其实就是面向接口编程,而不是面向实现编程。无论主板、CPU、内存、硬盘都是在针对接口设计的,如果针对实现来设计,内存就要对应到具体的某个品牌的主板,那就回出现换内存需要把主板也换了的尴尬。 与修📻收音机相比,修电脑反而要简单。是因为收音机耦合过度了,只要收音机出现故障,不管是没有声音、不能调频,还是有杂音,反正都很难修,因为任何问题都可能涉及其他部件,各个部件相互依赖,难易维护。

January 10, 2025 · 1 min · 13 words · Rex

开放-封闭原则(Open Closed Principle)

🚏 导论 开放-封闭原则,是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。 对于拓展是开放的(Open for extension),对于更改是封闭的(Closed for modiication) 我们在做任何系统的时候都不要指望系统一开始时需求确定,就再也不会变化,这是不现实也不科学的想法,而既然需求是一定会变化的,那么如何在面对需求的变化时,设计的软件可以相对容易修改,不至于说,新需求一来,就要把整个程序推到重来。怎样的设计才能让软件在需求变化时,可以相对容易的修改呢?这就是开放-封闭原则要解决的问题。 具体来说,在设计的时候,时刻要考虑,尽量让这个类足够好,写好了就不要去修改了,如果新需求来了,增加一些类,原来的代码能不动则不动。当然,绝对的对修改封闭是不可能的。无论模块是多么的“封闭”,都会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。若猜测失败,要及时的去调整。面对新需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。 开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。 🎬 场景 场景一:🏢 公司管理 现要作为老板,给公司制定考勤制度,规定九点上班,不允许迟到。但是有公司骨干,老是迟到。他们也有实际的难处,比如有些人家离公司太远,有些人每天上午要送小孩子上学。需要对他们特殊处理,但不能违反公司的规定。其实迟到不是问题,最主要的是保证8小时的工作量或是完成业绩目标。于是应该改变管理方式,如弹性上班工作制,早到早下班,晚到晚下班,或者每人每月允许三次迟到,迟到者当天下班补时间等等。对市场销售人员可能就更加以业绩为标准,工作时间不固定了。这其实就是对工作时间或业绩成效的修改关闭,而对时间制度拓展的开放。

January 10, 2025 · 1 min · 16 words · Rex