软件23种设计模式完整版[附Java版示例代码]

一、什么是设计模式

设计模式是在软件设计中反复出现的问题的通用解决方案。它们是经过多次验证和应用的指导原则,旨在帮助软件开发人员解决特定类型的问题,提高代码的可维护性、可扩展性和重用性。

设计模式是一种抽象化的思维方式,可以帮助开发人员更好地组织和设计他们的代码。它们提供了一种通用的框架,可以用于解决各种不同的软件设计问题。设计模式不是完整的代码,而是一种描述问题和解决方案之间关系的模板。

设计模式并不是一成不变的法则,而是根据不同的问题和情境来决定是否使用以及如何使用。了解和应用设计模式可以帮助开发人员更好地组织代码,提高代码的可读性和可维护性,同时也有助于促进团队之间的合作和沟通。

二、设计模式的分类

  1. 创建型模式(Creational):关注对象的实例化过程,包括了如何实例化对象、隐藏对象的创建细节等。常见的创建型模式有单例模式、工厂模式、抽象工厂模式等。
  2. 结构型模式(Structural):关注对象之间的组合方式,以达到构建更大结构的目标。这些模式帮助你定义对象之间的关系,从而实现更大的结构。常见的结构型模式有适配器模式、装饰器模式、代理模式等。
  3. 行为型模式(Behavioral):关注对象之间的通信方式,以及如何合作共同完成任务。这些模式涉及到对象之间的交互、责任分配等。常见的行为型模式有观察者模式、策略模式、命令模式等。

三、设计模式的基本要素

  1. 模式名称:每个设计模式都有一个简洁的名称,用于描述问题、解决方案和效果。这个名称有助于在交流中快速指代模式。
  2. 问题:描述了在什么情况下应该考虑使用特定的设计模式。问题部分阐述了该模式试图解决的具体设计难题。
  3. 解决方案:解决方案部分提供了一个详细的设计指南,描述了如何组织类、对象以及它们之间的关系,以解决特定问题。这包括了每个角色的职责、协作方式等。
  4. 效果:描述了模式应用的效果及使用模式应权衡的问题。

四、23 种设计模式概览

23种设计模式概览

五、设计模式间的关系
 

23种设计模式关系图

六、设计模式代码示例

以下包含Java版示例代码

七、设计模式详解

1. 工厂方法模式(Factory Method)

问题

在软件设计中,我们经常遇到需要创建不同类型对象的情况。但是,如果直接在代码中实例化对象,会使代码紧密耦合在一起,难以维护和扩展。此外,如果对象的创建方式需要变化,那么就需要在整个代码中进行大量的修改。工厂方法模式旨在解决这个问题。

解决方案

工厂方法模式提供了一个创建对象的接口,但是将具体的对象创建延迟到子类中。这样,客户端代码不需要知道要创建的具体对象的类,只需要通过工厂方法来创建对象。这使得客户端代码与具体对象的创建解耦,提高了代码的灵活性和可维护性。

在工厂方法模式中,通常会定义一个抽象工厂类,其中包含一个创建对象的抽象方法,而具体的对象创建则由具体的子类实现。这样,每个具体的子类都可以根据需要创建不同类型的对象,而客户端代码只需要通过抽象工厂类来调用工厂方法,而不需要关心具体的对象创建细节。

效果

工厂方法模式的优点包括:

  • 松耦合:客户端代码与具体对象的创建解耦,使得系统更具弹性和可维护性。
  • 扩展性:通过添加新的具体工厂和产品子类,可以很容易地扩展系统以支持新的对象类型。
  • 封装性:将对象的创建集中在工厂类中,封装了对象的创建细节,使得客户端代码更简洁。

然而,工厂方法模式也可能引入一些额外的复杂性,因为需要定义多个工厂类和产品类的层次结构。这可能会导致系统中类的数量增加。在选择使用工厂方法模式时,需要根据具体情况进行权衡。

工厂方法模式在实际应用中非常常见,例如,图形库可以使用工厂方法模式来创建不同类型的图形对象,数据库访问框架可以使用工厂方法模式来创建不同类型的数据库连接等。

代码示例:

// 首先,我们需要定义一个图形接口
interface Shape {
    void draw();
}
// 然后,我们实现两个具体的图形类,分别是 Circle(圆形)和 Rectangle(矩形)
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}
// 接下来,我们创建一个抽象工厂类 ShapeFactory
// 它定义了一个抽象的工厂方法 createShape,子类将实现这个方法来创建具体的图形对象
abstract class ShapeFactory {
    abstract Shape createShape();
}
// 然后,我们创建两个具体的工厂类,分别是 CircleFactory 和 RectangleFactory
// 它们分别实现了 ShapeFactory 并重写了 createShape 方法来返回相应的图形对象
class CircleFactory extends ShapeFactory {
    @Override
    Shape createShape() {
        return new Circle();
    }
}

class RectangleFactory extends ShapeFactory {
    @Override
    Shape createShape() {
        return new Rectangle();
    }
}
// 我们可以使用这些工厂类来创建图形对象
public class FactoryMethodExample {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw();
        
        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw();
    }
}

2. 抽象工厂模式(Abstract Factory)

问题

在某些情况下,需要创建一系列相关或相互依赖的对象,这些对象属于一组相关的产品族。同时,系统需要保证这些产品族之间的一致性。如果直接在代码中创建这些对象,会使得代码与具体产品的细节紧密耦合,不利于后续的扩展和维护。

解决方案

抽象工厂模式提供了一个接口,用于创建一系列相关或相互依赖的对象。通过使用抽象工厂接口及其具体实现,可以将对象的创建与客户端代码分离,从而实现系统的松耦合。抽象工厂模式涉及多个角色:

  • 抽象工厂(Abstract Factory):声明了一组用于创建不同产品的抽象方法。具体的工厂类必须实现这些方法来创建具体的产品对象。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建特定种类的产品对象。
  • 抽象产品(Abstract Product):定义了产品的通用接口,具体产品必须实现这个接口。
  • 具体产品(Concrete Product):实现抽象产品接口,是抽象工厂创建的实际对象。

效果

抽象工厂模式的使用可以带来以下效果:

  • 产品族一致性:抽象工厂确保创建的产品是一组相关的产品族,保证了这些产品之间的一致性。
  • 松耦合:客户端代码不需要直接依赖于具体产品,只需要通过抽象工厂接口创建产品,从而降低了代码的耦合度。
  • 可扩展性:增加新的产品族或产品变得相对容易,只需要添加新的具体工厂和产品类即可,不需要修改现有代码。
  • 限制:抽象工厂模式要求系统中的每个产品族都必须有一个对应的具体工厂,这可能增加了系统的复杂性。

抽象工厂模式适用于需要创建一系列相关产品并保证它们之间一致性的情况,例如图形界面库中的UI元素,不同操作系统下的界面组件等。通过使用抽象工厂模式,可以更好地管理和组织这些产品的创建过程。

代码示例:

// 抽象产品接口:操作系统
interface OperatingSystem {
    void run();
}

// 具体产品:Windows操作系统
class WindowsOS implements OperatingSystem {
    @Override
    public void run() {
        System.out.println("Running Windows OS");
    }
}

// 具体产品:Linux操作系统
class LinuxOS implements OperatingSystem {
    @Override
    public void run() {
        System.out.println("Running Linux OS");
    }
}

// 抽象产品接口:应用程序
interface Application {
    void open();
}

// 具体产品:Word应用程序
class WordApplication implements Application {
    @Override
    public void open() {
        System.out.println("Opening Word Application");
    }
}

// 具体产品:Excel应用程序
class ExcelApplication implements Application {
    @Override
    public void open() {
        System.out.println("Opening Excel Application");
    }
}

// 抽象工厂接口
interface SoftwareFactory {
    OperatingSystem createOperatingSystem();
    Application createApplication();
}

// 具体工厂:Windows工厂
class WindowsFactory implements SoftwareFactory {
    @Override
    public OperatingSystem createOperatingSystem() {
        return new WindowsOS();
    }

    @Override
    public Application createApplication() {
        return new ExcelApplication();
    }
}

// 具体工厂:Linux工厂
class LinuxFactory implements SoftwareFactory {
    @Override
    public OperatingSystem createOperatingSystem() {
        return new LinuxOS();
    }

    @Override
    public Application createApplication() {
        return new WordApplication();
    }
}

// 在这个示例中,抽象工厂模式通过SoftwareFactory接口和其实现类来创建不同类型的操作系统和应用程序。
// 客户端代码可以根据需要选择不同的工厂实例来创建不同的产品组合。
public class Client {
    public static void main(String[] args) {
        SoftwareFactory windowsFactory = new WindowsFactory();
        OperatingSystem windowsOS = windowsFactory.createOperatingSystem();
        Application windowsApp = windowsFactory.createApplication();

        windowsOS.run();
        windowsApp.open();

        SoftwareFactory linuxFactory = new LinuxFactory();
        OperatingSystem linuxOS = linuxFactory.createOperatingSystem();
        Application linuxApp = linuxFactory.createApplication();

        linuxOS.run();
        linuxApp.open();
    }
}

3. 建造者模式(Builder)

问题

在某些情况下,一个对象的创建过程非常复杂,涉及多个步骤,每个步骤都可能有不同的实现方式。如果将所有创建逻辑放在一个类中,会导致该类变得庞大且难以维护。此外,如果需要创建不同的变体对象,就需要在该类中添加更多的逻辑,使得代码变得混乱。

解决方案

建造者模式提供了一种将一个复杂对象的构建过程与其表示分离的方法。它将对象的构建过程封装在一个独立的"建造者"类中,由该类负责逐步构建对象。这样,可以根据需要创建不同的建造者来构建不同的对象变体。通常,建造者模式涉及以下角色:

  • 产品(Product):表示正在构建的复杂对象。建造者模式的目标是构建这个产品。
  • 抽象建造者(Abstract Builder):定义了构建产品的步骤和方法,但没有具体的实现。不同的具体建造者可以实现不同的构建步骤,从而创建不同的产品变体。
  • 具体建造者(Concrete Builder):实现了抽象建造者定义的方法,完成了产品的构建过程。每个具体建造者负责构建特定的产品变体。
  • 指导者(Director):负责控制建造的过程。它通过将客户端与具体建造者分离,确保产品的构建是按照一定顺序和规则进行的。

效果

建造者模式的效果包括:

  • 分离构建过程和表示:通过建造者模式,可以将复杂对象的构建过程与其最终表示分离,使得构建过程更加清晰可控。
  • 支持不同的表示:通过使用不同的具体建造者,可以创建不同的产品表示,而不改变客户端的代码。
  • 更好的可扩展性:如果需要添加新的产品变体,只需创建一个新的具体建造者即可,而无需修改已有的代码。
  • 隐藏产品的内部结构:客户端只需与抽象建造者和指导者交互,无需关心产品的内部构建细节。

总之,建造者模式适用于需要构建复杂对象,且构建过程涉及多个步骤或变体的情况。通过将构建过程分解为可重用的步骤,建造者模式提供了一种结构化的方法来创建对象。

代码示例:

// 首先,我们定义房屋类 House,它具有多个属性,如地基、结构、屋顶和装修。
class House {
    private String foundation;
    private String structure;
    private String roof;
    private String interior;

    public void setFoundation(String foundation) {
        this.foundation = foundation;
    }

    public void setStructure(String structure) {
        this.structure = structure;
    }

    public void setRoof(String roof) {
        this.roof = roof;
    }

    public void setInterior(String interior) {
        this.interior = interior;
    }

    @Override
    public String toString() {
        return "House [foundation=" + foundation + ", structure=" + structure + ", roof=" + roof + ", interior=" + interior + "]";
    }
}
// 然后,我们创建一个抽象建造者类 HouseBuilder,它定义了构建房屋的方法。
abstract class HouseBuilder {
    protected House house = new House();

    public abstract void buildFoundation();
    public abstract void buildStructure();
    public abstract void buildRoof();
    public abstract void buildInterior();

    public House getHouse() {
        return house;
    }
}
// 接下来,我们创建两个具体的建造者类 ConcreteHouseBuilder 和 LuxuryHouseBuilder
// 分别实现了不同类型房屋的构建过程。
// 具体建造者类 - 普通房屋
class ConcreteHouseBuilder extends HouseBuilder {
    @Override
    public void buildFoundation() {
        house.setFoundation("Standard Foundation");
    }

    @Override
    public void buildStructure() {
        house.setStructure("Standard Structure");
    }

    @Override
    public void buildRoof() {
        house.setRoof("Standard Roof");
    }

    @Override
    public void buildInterior() {
        house.setInterior("Standard Interior");
    }
}

// 具体建造者类 - 豪华房屋
class LuxuryHouseBuilder extends HouseBuilder {
    @Override
    public void buildFoundation() {
        house.setFoundation("Strong Foundation");
    }

    @Override
    public void buildStructure() {
        house.setStructure("Reinforced Structure");
    }

    @Override
    public void buildRoof() {
        house.setRoof("Elegant Roof");
    }

    @Override
    public void buildInterior() {
        house.setInterior("Luxury Interior");
    }
}
// 最后,我们创建指导者类 Director,它协调建造过程并返回构建的房屋对象。
class Director {
    private HouseBuilder builder;

    public Director(HouseBuilder builder) {
        this.builder = builder;
    }

    public House constructHouse() {
        builder.buildFoundation();
        builder.buildStructure();
        builder.buildRoof();
        builder.buildInterior();
        return builder.getHouse();
    }
}
// 这个示例演示了如何使用建造者模式创建不同类型的房屋,每种房屋类型的建造过程都由相应的具体建造者类负责实现,而指导者类负责协调建造过程。
public class BuilderPatternExample {
    public static void main(String[] args) {
        HouseBuilder concreteBuilder = new ConcreteHouseBuilder();
        Director director1 = new Director(concreteBuilder);
        House concreteHouse = director1.constructHouse();
        System.out.println("Concrete House: " + concreteHouse);

        HouseBuilder luxuryBuilder = new LuxuryHouseBuilder();
        Director director2 = new Director(luxuryBuilder);
        House luxuryHouse = director2.constructHouse();
        System.out.println("Luxury House: " + luxuryHouse);
    }
}

4. 原型模式(Prototype)

问题

在某些情况下,需要创建对象的副本,但复制一个对象的成本可能很高,或者希望避免与对象的具体类耦合。例如,当创建对象的过程较为复杂,或者对象包含大量共享的状态时,使用常规的创建方法可能会导致性能下降。

解决方案

原型模式的解决方案是通过复制现有对象来创建新对象,而不是从头开始构建。这允许我们以更高效的方式创建新对象,同时避免了与对象类的直接耦合。核心概念是在原型对象的基础上进行克隆,使得新对象具有与原型相同的初始状态。

在原型模式中,通常会有以下几个角色:

  • 抽象原型(Prototype):声明克隆方法,作为所有具体原型的基类或接口。
  • 具体原型(Concrete Prototype):实现克隆方法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(2023|NIPS,LLaVA-Med,生物医学 VLM,GPT-4 生成自指导指令跟随数据集,数据对齐,指令调优)

LLaVA-Med: Training a Large Language-and-Vision Assistant for Biomedicine in One Day 目录 LLaVA-Med: Training a Large Language-and-Vision Assistant for Biomedicine in One Day 0. 摘要 1. 简介 2. 相关工作 3. 生物医学视觉指令数据 4. 将多模态对话模型适配…

深入理解Mybatis原理》MyBatis的sqlSessi

sqlSessionFactory 与 SqlSession 正如其名,Sqlsession对应着一次数据库会话。由于数据库会话不是永久的,因此Sqlsession的生命周期也不应该是永久的,相反,在你每次访问数据库时都需要创建它(当然并不是说在Sqlsession…

Numpy数组的属性

NumPy中最重要的一个特点就是其n维数组对象,即ndarray(别名array)对象,该对象具有矢量算术能力和复杂的广播能力,可以执行一些科学计算。不同于Python内置的数组类型, array对象拥有对高维数组的处理能力,这也是数值计…

(十)提示词任务分解的策略探讨

📢📢📢 大家好,我是云楼Yunlord,CSDN博客之星人工智能领域前三名,多年人工智能学习工作经验,一位兴趣稀奇古怪的【人工智能领域博主】!!!😜&#…

01 数据分析介绍及工具准备

数据分析介绍及工具准备 一、工具准备二、下载和使用Anaconda三、jupyter notebook常用快捷键 一、工具准备 数据科学库 NumPy,SciPy,Pandas,Scikit-Learn 数据可视化库 Matplotlib,Seaborn 编译器 Jupyter Notebook 数据科…

excel表格二维X、Y坐标散点图

excel中存在两列或两行数据,分别表示x坐标和对应的y坐标,同时选中两列或两行数据: 依次选择菜单,插入,图标,XY散点图 可以看到在表格中生成了以第1列为X轴,第2列为Y轴的二维XY散点图&#xff…

Cursor无限续杯——解决Too many free trials.

前情提要 我们都知道Cursor对新用户是有14天且500条免费限制的。 一般情况下,当14天过期,是可以注销账户再重新注册,这样就可以继续拥有14天的体验时长。 但是!!如果使用超过500次,Cusor就会把你的电脑I…

HCIE-day10-ISIS

ISIS ISIS(Intermediate System-to-Intermediate System)中间系统到中间系统,属于IGP(内部网关协议);是一种链路状态协议,使用最短路径优先SPF算法进行路由计算,与ospf协议有很多相…

洛谷P1617———数字转英文

题目如下 思路:将1~9的英文和20~90的英文用字符串数组存储,把下标看作对应的数字进行输出,遇到0或连续多个0就输出“and”,定义l用来看枚举到哪一位了,如果是单独输入一个“0”,则直接输出zero然后结束。否…

UnityRenderStreaming使用记录(五)

UnityRenderStreaming不一样的错误,船新的版本 继续docker部署UnityRenderStreamingdockerfile一些命令出现了新的错误先解决一个报错不知道怎么解决,先跑个glxgears测试一下先解决MESA和glx的问题新的log,额新的错误尝试解决libnvidia-encod…

Unity-Mirror网络框架-从入门到精通之AdditiveScenes 示例

文章目录 前言Additive Levels和Additive ScenesAdditive Levels场景介绍Portal传送门FadeInOut特效 Additive Scenes示例介绍ZoneHandlerSceneMassage 最后 前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框…

Mac-docker配置

1.配置的文件路径 cd ~/.docker (base) zhangyaweimacbookair .docker % ls buildx cli-plugins config.json contexts daemon.json desktop-build mutagen run (base) zhangyaweimacbookair .docker % cat daemon.json## 重启docker服务 sudo systemctl daemon-reload sudo…

PHP进阶-在Ubuntu上搭建LAMP环境教程

本文将为您提供一个在Ubuntu服务器上搭建LAMP(Linux, Apache, MySQL, PHP)环境的完整指南。通过本文,您将学习如何安装和配置Apache、MySQL、PHP,并将您的PHP项目部署到服务器上。本文适用于Ubuntu 20.04及更高版本。 一、系统更新…

Elasticsearch(看这一篇就够了)

目录: Elasticsearch介绍正排索引和倒排索引Elasticsearch安装安装ES服务安装服务安装kibana 索引操作创建索引查询索引库修改索引库删除索引库 Elasticsearch常用操作文档操作新增文档查询文档删除文档根据id批量查询文档查询所有文档修改文档部分字段 域的属性分词…

嵌入式技术之Linux(Ubuntu) 一

一、Linux入门 1.硬件和操作系统以及用户的关系 一个传感器,获得数据后,需要向服务器发送数据。传感器传数据给上位机。 上位机需要一个程序来接收数据,那么这个上位机是什么机器? 我们的笔记本电脑就可以当成上位机。 两个手…

【实用技能】如何使用 .NET C# 中的 Azure Key Vault 中的 PFX 证书对 PDF 文档进行签名

TX Text Control 是一款功能类似于 MS Word 的文字处理控件,包括文档创建、编辑、打印、邮件合并、格式转换、拆分合并、导入导出、批量生成等功能。广泛应用于企业文档管理,网站内容发布,电子病历中病案模板创建、病历书写、修改历史、连续打…

oracle闪回恢复数据:(闪回查询,闪回表,闪回库,回收站恢复)

oracle的闪回查询,可以查询提交在表空间的闪回数据,并可以还原所查询的数据,用于恢复短时间内的delele 或者 update 误操作,非常方便,缺点是只能恢复大概几小时内的数据。 文章目录 概要闪回查询恢复数据的主要方法包括…

开放词汇检测新晋SOTA:地瓜机器人开源DOSOD实时检测算法

在计算机视觉领域,目标检测是一项关键技术,旨在识别图像或视频中感兴趣物体的位置与类别。传统的闭集检测长期占据主导地位,但近年来,开放词汇检测(Open-Vocabulary Object Detection-OVOD 或者 Open-Set Object Detec…

【网络协议】静态路由详解

网络中的路由器通过以下两种方式之一发现远程网络: 静态配置路由动态路由协议 在本文,我们将学习关于静态路由的各种概念,例如如何配置静态路由、路由表如何进行决策、路由接口等相关知识。 文章目录 引言直连网络静态路由路由表原则原则1原…

(长期更新)《零基础入门 ArcGIS(ArcScene) 》实验七----城市三维建模与分析(超超超详细!!!)

城市三维建模与分析 三维城市模型已经成为一种非常普遍的地理空间数据资源,成为城市的必需品,对城市能化管理至关重要。语义信息丰富的三维城市模型可以有效实现不同领域数据与IS相信息的高层次集成及互操作,从而在城市规划、环境模拟、应急响应和辅助决策等众多领域公挥作用、…