7大结构型设计模式

结构性设计模式是软件工程中常用的一类设计模式。

作用:主要用于处理类或对象之间的组合以实现更灵活、可扩展和可维护的代码结构。

这些模式通常涉及到类和对象之间的静态组合关系,以及如何将它们组织在一起以满足特定的设计目标。

结构型模式有:

 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

适配器模式

文章地址:

适配器模式已经在SpringMVC中的源码实现-CSDN博客

总结:我调用适配器类,适配器类进行内部转换,返回给我一个想要的类

桥接模式

桥接模式以及在JDBC源码剖析-CSDN博客

总结:将抽象部分与实现部分分离,使它们可以独立变化。

装饰者模式

前提总结:动态地给一个对象添加一些额外的职责。

介绍

1、定义
装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则

//1、接口
public interface Coffee {double getCost();String getDescription();
}
​
//2、具体咖啡类
public class SimpleCoffee implements Coffee {
​@Overridepublic double getCost() {return 1.0;}
​@Overridepublic String getDescription() {return "Simple coffee";}
}
​
//3、装饰者类
public abstract class CoffeeDecorator implements Coffee {
​protected Coffee decoratedCoffee;
​public CoffeeDecorator(Coffee decoratedCoffee) {this.decoratedCoffee = decoratedCoffee;}
​public double getCost() {return decoratedCoffee.getCost();}
​public String getDescription() {return decoratedCoffee.getDescription();}
}
public class MilkDecorator extends CoffeeDecorator {
​public MilkDecorator(Coffee decoratedCoffee) {super(decoratedCoffee);}
​public double getCost() {return super.getCost() + 0.5;}
​public String getDescription() {return super.getDescription() + ", with milk";}
}
​
​
//4、测试demo
Coffee simpleCoffee = new SimpleCoffee();
System.out.println("Cost: " + simpleCoffee.getCost() + ", Description: " + simpleCoffee.getDescription());
​
Coffee coffeeWithMilk = new MilkDecorator(simpleCoffee);
System.out.println("Cost: " + coffeeWithMilk.getCost() + ", Description: " + coffeeWithMilk.getDescription());
 

装饰者模式在JDK中使用

在JavaIO结构中,FilterInputStream就是一个装饰者

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("example.txt"));这里就是装饰者模式的应用,有点类似套娃。

总结

装饰者模式是一种结构型设计模式,它允许你动态地将责任附加到对象上。这种模式可以通过创建一个包装类来包裹原始类,在不改变原始类接口的情况下,给其添加新的功能。

优点
  1. 灵活性:装饰者模式通过嵌套组合的方式,可以在运行时动态地添加、移除或修改对象的行为,提供了很高的灵活性。

  2. 避免继承的缺点:相比使用继承来扩展对象功能,装饰者模式避免了类爆炸问题,使得代码更加灵活、可维护和可扩展。

  3. 单一职责原则:每个装饰者类都专注于一个特定的功能,符合单一职责原则,从而使得系统更易于理解和维护。

缺点
  1. 复杂性:过度使用装饰者模式可能会导致大量的小类,增加代码复杂性和理解难度。

  2. 顺序敏感:装饰者模式中的装饰顺序很重要,如果顺序错误可能导致意外结果,需要特别注意。

适用场景
  1. 当需要在不影响其他对象的情况下,动态地、递归地给对象添加功能时,可以使用装饰者模式。

  2. 当需要动态地撤销功能时,该模式同样适用。

总的来说,装饰者模式在需要灵活地扩展对象功能、避免类爆炸以及保持单一职责原则时非常有用。然而,在实际使用时,应权衡利弊,避免过度复杂化设计。

组合模式

简单总结:组合模式是一种设计模式,它允许你将对象组合成树形结构,从而形成“部分-整体”的层次结构。每个组件都可以执行一些操作,并且这些操作可以通过递归的方式应用于组合的整个结构。

介绍

1、组合模式又称部分整体模式,它创建了对象组的树型结构,将对象组合成树状结构,以表示“整体 - 部分” 的层次关系。
2、组合模式依据树型结构来组合对象,用来表示部分以及整体层次
3、属于结构者模式
4、组合模式使得用户对单个对象和组合对象的访问具有一致性。即(组合能让客户以一致的方式处理个别对象以及组合对象)

示例

import java.util.ArrayList;
import java.util.List;
​
// 组件接口
interface Component {void operation();
}
​
// 叶子节点类
class Leaf implements Component {@Overridepublic void operation() {System.out.println("Leaf operation");}
}
​
// 组合节点类
class Composite implements Component {private List<Component> children = new ArrayList<>();
​public void add(Component component) {children.add(component);}
​public void remove(Component component) {children.remove(component);}
​@Overridepublic void operation() {System.out.println("Composite operation");for (Component component : children) {component.operation();}}
}
​
public class Main {public static void main(String[] args) {// 创建叶子节点Leaf leaf1 = new Leaf();Leaf leaf2 = new Leaf();
​// 创建组合节点Composite composite = new Composite();composite.add(leaf1);composite.add(leaf2);
​// 调用操作composite.operation();}
}
​

说明:

1、Component:这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component子部件,Component可以是抽象类或接口
​
2、Leaf:在组合中表示叶子节点,叶子节点没有子节点
​
3、Composite:非叶子节点,用于存储子部件,在Component 接口中实现 子部件的相关操作。比如增加、删除....

组合模式在JDK中使用

HashMap中的使用。

这里是Map接口(类似上述的Component接口)

这里是HashMap的内部类,类似上述的Leaf节点

这里是HashMap类,类似上述Composite

总结

个人理解:

组合模式确实就是将复合组件(Composite)和叶子组件(Leaf)组合起来,以实现一些功能。

在组合模式中,复合组件可以包含叶子组件,也可以包含其他复合组件,从而形成一个树形结构。

这种树形结构使得客户端可以统一地对待单个组件和组合组件,而不必关心它们的具体类型。客户端可以通过统一的接口来访问组合中的所有组件,从而简化了客户端的代码。

注意事项和细节

1、简化客户端操作。 客户只需要面对一致的对象,而不需要考虑整体部分或者叶子节点的问题。

2、具有较强的扩展性。 当需要修改组合对象时,只需要调整内部的层次关系,客户端不需要做出任何改动。

3、方便创建出复杂的层次结构。 客户不需要了解内部的组成细节,容易添加节点或叶子从而创建出复杂的树型结构

4、需要遍历组织机构,或处理对象具有树型结构时,非常适合组合模式

5、需要较高的抽象性。 如果节点和叶子有很多差异性的话,不适合组合模式。

优点
  1. 简化客户端代码:客户端可以一致地处理单个对象和组合对象,不需要区分它们的具体类型,从而简化客户端代码。

  2. 灵活性:可以通过组合不同的对象来构建复杂的层次结构,同时能够方便地增加新的组件或改变组件的结构。

  3. 统一接口:叶子节点和组合节点都实现了相同的接口,使得客户端可以统一调用操作,无需关心具体实现。

  4. 容易扩展:可以很容易地添加新的组件类,无需修改现有的代码。

缺点
  1. 限制组件类型:由于所有组件都需要实现相同的接口,可能会限制组件类型的多样性。

  2. 增加复杂性:引入组合模式会增加系统的复杂性,特别是在处理递归结构时需要小心设计,避免出现死循环或性能问题。

  3. 不适合所有情况:并不是所有的场景都适合使用组合模式,特别是当组件间的层次关系比较简单或不固定时,可能会显得过度复杂。

小结

组合模式在处理整体 - 部分结构的问题上具有明显的优点,但在某些情况下也需要权衡其复杂性和适用性。

外观模式

介绍

1、外观模式又称过程模式。
外观模式为子系统中的一组接口提供了一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
​
2、外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关注子系统中的内部细节。

外观模式中的角色:

1、外观类(Facade):为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当的子系统对象。
​
2、调用者(Client):外观接口的调用者
​
3、子系统的集合:指模块或子系统,处理Facade 对象指派的任务,他是功能的提供者。

实例

下面是一个简单的家庭影院系统作为案例。在这个案例中,外观模式可以隐藏复杂的子系统,并提供一个简单的接口给客户端。

家庭影院外观 HomeTheaterFacade 封装了投影仪、音响和屏幕等子系统的操作,为客户端提供了简单的接口。客户端只需与外观类交互,而不需要了解内部子系统的复杂操作。

// 子系统类:投影仪
class Projector {public void on() {System.out.println("投影仪打开");}
​public void off() {System.out.println("投影仪关闭");}
}
​
// 子系统类:音响
class AudioSystem {public void on() {System.out.println("音响打开");}
​public void off() {System.out.println("音响关闭");}
}
​
// 子系统类:屏幕
class Screen {public void up() {System.out.println("屏幕上升");}
​public void down() {System.out.println("屏幕下降");}
}
​
// 外观类:家庭影院外观
class HomeTheaterFacade {private Projector projector;private AudioSystem audioSystem;private Screen screen;
​public HomeTheaterFacade(Projector projector, AudioSystem audioSystem, Screen screen) {this.projector = projector;this.audioSystem = audioSystem;this.screen = screen;}
​public void watchMovie() {System.out.println("准备观影...");projector.on();audioSystem.on();screen.down();}
​public void endMovie() {System.out.println("结束观影...");projector.off();audioSystem.off();screen.up();}
}
​
// 客户端类
public class Client {public static void main(String[] args) {Projector projector = new Projector();AudioSystem audioSystem = new AudioSystem();Screen screen = new Screen();
​HomeTheaterFacade homeTheater = new HomeTheaterFacade(projector, audioSystem, screen);homeTheater.watchMovie();System.out.println("一段时间后...");homeTheater.endMovie();}
}

外观模式在Mybatis框架的使用

上述就是在Mybatis框架中的使用。

1、子系统类:
DefaultObjectFactory类、DefaultObjectWrapperFactory类、DefaultReflectorFactory类
2、外观类:
Configuration类

外观模式像一个集合子系统类,为什么叫外观模式呢?

外观模式的主要目的是提供一个简化接口,用于访问系统中一组复杂的子系统。外观模式通过创建一个高层接口(外观类),封装了子系统中的一组接口,从而隐藏了子系统的复杂性,并提供了一个更简单的接口给客户端使用。

虽然外观模式中的外观类看起来像是集合了多个子系统的功能,但它们的核心不在于集合,而在于简化接口。外观模式的外观类不负责实现功能,而是将请求转发给子系统中相应的对象,让子系统来完成实际的工作。

因此,外观模式的核心特点可以总结为:

  1. 简化接口:外观类提供了一个简化的接口,隐藏了子系统的复杂性,使得客户端不需要了解子系统的具体实现细节。

  2. 封装子系统:外观类封装了子系统中的一组接口,通过外观类访问子系统,客户端不需要直接与子系统的组件进行交互。

  3. 解耦:外观模式将客户端与子系统之间的耦合度降低到最低程度,客户端只需要与外观类进行交互,而不需要了解子系统的内部结构。

因此,尽管外观模式中的外观类看起来像是集合了多个子系统的功能,但其主要作用是提供一个简化接口,隐藏复杂性,降低耦合度,而不是简单地将多个类集合在一起形成一个新的集合类。

总结

个人理解:

外观模式理解为一个主类(外观类)集成了多个子类(子系统),并通过外观类来调用这些子类完成特定功能的过程

外观模式是一种结构型设计模式,旨在为复杂系统提供一个简单统一的接口,从而隐藏系统的复杂性,使客户端与系统之间的交互变得更加简单和直观。

优点:

  1. 简化接口:外观模式提供了一个简单的接口,隐藏了子系统的复杂性,使客户端使用起来更加方便。

  2. 解耦:通过外观模式,客户端与子系统之间的耦合度降低,客户端不需要直接与多个子系统进行交互,只需与外观类交互即可。

  3. 更好的封装性:外观模式将子系统的细节封装在内部,对客户端隐藏了具体实现细节,提高了系统的安全性和稳定性。

缺点:

  1. 不符合开闭原则:当系统中的子系统发生变化时,可能需要修改外观类,违反了开闭原则。

  2. 可能造成性能问题:在某些情况下,外观类可能会变得过于庞大,导致性能问题。

  3. 可能引入不必要的复杂性:如果系统本身并不复杂,引入外观模式可能会增加代码复杂性。

总的来说,外观模式适合用于简化复杂系统的接口,提高系统的易用性和灵活性。在设计时需要权衡好利弊,确保外观模式的引入能够带来实际的好处。

享元模式

“享元”是中国古代的一种度量衡单位,用于衡量铜器时代的重量和容量

介绍

1、享元模式又称蝇量模式。 运用共享技术有效地支持大量细粒度对象(系统中存在许多具有相似性质和功能的小型对象)

2、常用于系统底层开发,解决系统的性能问题,像数据库连接池,里面都是创建好的链接对象,里面都是已创建好的连接对象,在这些连接对象中。

3、能够解决重复对象内存浪费问题。 当系统中有大量相似对象,需要缓冲池时,不需要新建对象,可以从缓冲池中拿。 -》降低系统内存,提高效率

4、享元模式经典使用场景:池技术。 String常量池、数据库连接池、缓冲池等等

实例

import java.util.HashMap;
import java.util.Map;
​
// 享元工厂
class FlyweightFactory {private static final Map<String, Flyweight> flyweights = new HashMap<>();
​public static Flyweight getFlyweight(String key) {if (!flyweights.containsKey(key)) {flyweights.put(key, new ConcreteFlyweight());}return flyweights.get(key);}
}
​
// 享元接口
interface Flyweight {void operation();
}
​
// 具体享元
class ConcreteFlyweight implements Flyweight {@Overridepublic void operation() {System.out.println("具体享元的操作");}
}
​
// 客户端
public class Client {public static void main(String[] args) {Flyweight flyweight1 = FlyweightFactory.getFlyweight("key1");flyweight1.operation();
​Flyweight flyweight2 = FlyweightFactory.getFlyweight("key2");flyweight2.operation();}
}
​

代码分析

前提:
1、享元模式提出了两个要求:细粒度和共享对象。这里涉及到内部状态和外部状态了,即将对象的信息分为两个部分:内部状态和外部状态。1)"大量细粒度对象"指的是系统中存在许多具有相似性质和功能的小型对象,这些对象通常具有较小的内存占用和较简单的结构。2)共享对象指的是被多个客户端或实例共同引用或共享的对象。这种共享可以带来一些好处,例如减少内存占用、提高性能和降低系统复杂度2、内部状态:对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变
3、外部状态:对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态
​
代码分析
1、FlyweightFactory :享元工厂类,用于构建一个池容器(集合),同时提供从池中获取对象方法
2、Flyweight:抽象的享元对象,他是产品的抽象类,同时定义出对象的外部状态和内部状态
3、ConcreteFlyweight:具体享元对象,是具体的产品类,实现抽象角色定义的业务

享元模式在JDK-Integer的应用源码分析

       Integer x = Integer.valueOf(127);   Integer y = new Integer(127);Integer z = Integer.valueOf(127);Integer w = new Integer(127);System.out.println(x.equals(y));//trueSystem.out.println(x == y);//falseSystem.out.println(x == z);//trueSystem.out.println(y == w);//false

小结:

1、在valueOf方法中,先判断是否在IntegerCache中,如果不在,就创建新的Integer(new),否则,就直接从缓存池中返回

2、这里使用到了享元模式

总结

个人理解: 一种生成重复对象的工厂,但是它给的如果是相同内容的对象,就是引用。 ​ ​ 享元模式确实是一种用于避免重复创建相同对象的设计模式。

当使用享元模式时,如果请求创建的对象已经存在,工厂会返回对现有对象的引用,而不是创建一个新的对象,从而节省内存和提高效率。这种方式确保了相同内容的对象在系统中只有一个实例,并且多个客户端使用同一对象的引用。

优点:

  1. 减少内存占用:通过共享对象的方式,减少了大量相似对象的内存占用。

  2. 提高性能:由于共享对象,可以减少创建和销毁对象的开销,提高系统性能。

缺点:

  1. 需要对内部状态和外部状态进行区分和管理,增加了系统复杂度。

  2. 如果共享对象过多,可能会导致系统的维护困难。

代理模式(重点)

代理模式以及静态代理、JDK代理、Cglib代理的实现-CSDN博客

一般在面试中会考察SpringAOP使用的Cglib动态代理和JDK代理的区别?

是一种通过代理某一个类,并增强其功能的设计模式。

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

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

相关文章

【源码阅读】evmⅠ

代码位置如下&#xff1a; 参考link 以太坊中有一个很重要的用途是智能合约&#xff0c;而其中evm模块是实现了执行智能合约的虚拟机。evm可以逐条解析执行智能合约的指令。 evm中的核心对象是EVM&#xff0c;代表一个以太坊虚拟机。其内部主要依赖&#xff1a;解释器Interore…

微服务技术栈SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式(五):分布式搜索 ES-下

文章目录 一、数据聚合1.1 聚合种类1.2 DSL实现聚合1.3 RestAPI实现聚合1.4 演示&#xff1a;多条件聚合 二、自动补全2.1 拼音分词器2.2 自定义分词器2.3 DSL自动补全查询2.5 实现酒店搜索框自动补全2.5.1 修改酒店索引库数据结构2.5.2 RestAPI实现自动补全查询2.5.3 实战 三、…

基于PyTorch的视频分类实战

1、数据集下载 官方链接&#xff1a;https://serre-lab.clps.brown.edu/resource/hmdb-a-large-human-motion-database/#Downloads 百度网盘连接&#xff1a; https://pan.baidu.com/s/1sSn--u_oLvTDjH-BgOAv_Q?pwdxsri 提取码: xsri 官方链接有详细的数据集介绍&#xf…

基于SpringBoot的后勤管理系统【附源码】

后勤管理系统开发说明 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myecli…

3d导出stl格式模型破碎是什么原因,怎么解决?---模大狮模型网

在导出3D模型为STL格式时出现破碎(或称为碎片化)的情况通常是由于模型中存在几何上的问题造成的。以下是一些可能导致STL模型破碎的原因以及解决方法&#xff1a; 3d导出stl格式模型破碎的原因&#xff1a; 模型不封闭&#xff1a;STL格式要求模型必须是封闭的实体&#xff0c…

【ArcGISProSDK】获取扩展模块许可到期时间

结果 以下是获取的3D分析模块的许可到期时间 代码 var licenseExpirationDate ArcGIS.Core.Licensing.LicenseInformation.GetExpirationDate(LicenseCodes.Analyst3D); 扩展模块 MemberDescriptionAnalyst3D3D AnalystAviationAirportsAviation and AirportsBusinessAnal…

数据可视化实战(二)

将每个城市在每个月份平均PM2.5绘制成折线图 import pandas as pd import matplotlib.pyplot as plt df pd.read_excel(./PM2.5.xlsx)display(df.head(10)) df.shape # (161630, 15)城市年份月份日期小时季节PM2.5露点湿度压强温度风向累计风速降水量累计降水量0北京2010112…

【Python循环4/5】跳出循环的办法

目录 导入 break 具体用法 在for循环中的运用 在while循环中的运用 continue 具体用法 区别 总结 导入 前几天的博文里&#xff0c;我们学习了for循环和while循环。 无论是for循环还是while循环&#xff0c;默认的终止条件都是边界条件。在触发边界条件之前&am…

电脑插上网线之后仍然没网络怎么办?

前言 有小伙伴在使用Windows系统的时候&#xff0c;经常会遇到电脑没网络&#xff0c;但又不知道具体怎么调整才好。 本篇内容适合插网线和使用Wi-Fi的小伙伴&#xff0c;文章本质上是重置电脑的网络设置。 注意事项&#xff1a;网络重置操作会让已连接过的wifi密码丢失&…

使用 stable-diffusion 入门级教程【Mac】

最近一直在短视频平台刷到AI生成的图片&#xff0c;质量也非常不错。术哥也跟我讲解了下如何安装使用。于是周末试了试。 也差点变成从入门到放弃了&#xff0c;所以也把过程中遇到的问题记录一下。 目前基本上运行正常&#xff0c;只是内存稍微小了点&#xff0c;把质量调低即…

【PyTorch】一文详细介绍【0维】张量

【PyTorch】一文详细介绍【0维】张量 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您的订阅和支持~ &#x1…

供应链投毒预警 | 恶意Py组件tohoku-tus-iot-automation开展窃密木马投毒攻击

概述 上周&#xff08;2024年3月6号&#xff09;&#xff0c;悬镜供应链安全情报中心在Pypi官方仓库&#xff08;https://pypi.org/&#xff09;中捕获1起新的Py包投毒事件&#xff0c;Python组件tohoku-tus-iot-automation 从3月6号开始连续发布6个不同版本恶意包&#xff0c…