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

设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

#1024程序员节|征文#在这里插入图片描述

4.1 适配器模式

  • 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。
  • 结构性模式的分类:

类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关。

对象结构型模式关心类与对象的组合,通过关联关系在一个类中定义另一个类的实例对象,然后通过该对象调用相应的方法。根据合成复用原则,在系统中尽量使用关联关系替代继承关系,因此大部分结构型模式都是对象结构型模式

4.1.1 适配器模式的定义

1.动机:适配器可以使由于接口不兼容而不能交互的类可以一起工作,这就是适配器模式的模式动机。

2.定义:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器

4.1.2 适配器模式的分析与实现

在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adaptor),它所包装的对象就是适配者(Adaptee),即被适配的类。适配器提供客户类需要的接口适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说,当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类

类适配器:

image-20241025213034577

public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter extends Adaptee implements Target{@Overridepublic void request() {super.specialRequest();}
}

对象适配器:

image-20241025213054460

public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter implements Target {private Adaptee adaptee;public void setAdaptee(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specialRequest();}
}
  • 类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。

  • 适配者类无法继承时,只能用对象适配器。

4.1.3 适配器模式的案例

现需要设计一个可以模拟各种动物行为的机器人,在机器人中定义了一系列方法,如机器人叫喊方法cry()、机器人移动方法move()等。如果希望在不修改已有代码的基础上使得机器人能够像狗一样叫,像狗一样跑,使用适配器模式进行系统设计。

image-20241025214944924

public interface Robot {public void cry();public void move();
}
public class Dog {public void cry() {System.out.println("汪汪叫");}public void move() {System.out.println("快快跑");}
}
public class DogAdapter extends Dog implements Robot{public void cry(){super.cry();}public void move(){super.move();}
}
4.1.4 适配器模式的优缺点
优点缺点
1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
2.增加了类的透明性和复用性,提高了适配者的复用性
3.灵活性和扩展性非常好,更换(增加)适配器,符合开闭原则
4.类适配器模式:由于继承关系,置换一些适配者的方法很方便不能适配多个适配类,每个目标类必须为接口,对于适配类为finial修饰的不可使用
5.对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类在适配器中置换适配者类的某些方法比较麻烦
4.1.5 适配器模式的适用场景
  • 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码

  • 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作

4.1.6 双向适配器类

image-20241025215726923

public class Adapter implements Target,Adaptee {private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target;    }	public Adapter(Adaptee adaptee) {this.adaptee = adaptee;    }	public void request() {adaptee.specificRequest();    }	public void specificRequest() {target.request();    }
}

4.2 桥接模式

4.2.1 桥接模式的定义

1.动机:如果系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使得两者可以独立扩展。桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多重继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效地控制了系统中类的个数。

2.定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

4.2.2 桥接模式的分析与实现

image-20241026112712436

  • 桥接模式中体现开闭原则、合成复用原则、里氏代换原则、依赖倒转原则等。

  • 脱耦:桥接模式将抽象化和实现化之间的耦合解开,或者说是将强关联(继承)改换成弱关联,将两个角色之间的继承关系改为关联关系,使得两者可以独立变化。

    public interface Implementor {public void implOperation();
    }
    public class ConcreteImplementorA implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征A");}
    }
    public class ConcreteImplementorB implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征B");}
    }public abstract class Abstracter {protected Implementor implementor;public void setImplementor(Implementor implementor) {this.implementor = implementor;}public abstract void operation();
    }
    public class RefinedAbstracter extends Abstracter{@Overridepublic void operation() {System.out.println("一个实体维度2的特征");implementor.implOperation();}
    }
    
4.2.3 桥接模式的案例

image-20241026114242202

image-20241026114302188

public interface VideoFile {public void decode(String osType, String fileName);
}
public class MPEGFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".MPEG文件进行播放");}
}
public class WMVFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".WMV文件进行播放");}
}
public abstract class OSVersion {protected VideoFile videoFile;public void setVideoFile(VideoFile videoFile) {this.videoFile = videoFile;}public abstract void play(String fileName);
}
public class LinuxVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Linux", fileName);}
}
public class WindowsVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Windows", fileName);}
}
public class Main {public static void main(String[] args) {WMVFile wmvFile = new WMVFile();WindowsVersion windowsVersion = new WindowsVersion();windowsVersion.setVideoFile(wmvFile);windowsVersion.play("刺客五六七");MPEGFile mpegFile = new MPEGFile();LinuxVersion linuxVersion = new LinuxVersion();linuxVersion.setVideoFile(mpegFile);linuxVersion.play("喜羊羊与灰太狼");}
}
4.2.4 桥接模式的优缺点
优点缺点
1.分离抽象接口和实现部分1.不容易正确识别俩个变化的维度
2.取代多继承,减少子类个数2.关联关系在抽象层,设计难度大
3.扩展性,俩个维度均可扩展
4.2.5 桥接模式的适用场景
  • 需要在抽象化和具体化之间增加更多的灵活性,扩展性,避免在两个层次之间建立静态的继承关系

  • 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展

  • 不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统

4.3 组合模式

4.3.1 组合模式的定义

1.动机:描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。

2.定义:组合多个对象形成树形结构以表示“部分-整体”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。

4.3.2 组合模式的分析与实现
image-20241026175600054
  • 组合模式用面向对象的方式来处理树形结构,它为叶子构件和容器构件提供了一个公共的抽象构件类,客户端可以针对该抽象类进行处理,而无需关心所操作的是哪种类型的对象。
  • 使用聚合关系使得容器既可以添加叶子节点也可以添加容器
public abstract class Component {public abstract void add(Component component);public abstract void remove(Component component);public abstract Component getChild(int i);public abstract void method();
}public class Composite extends Component{private ArrayList<Component> list = new ArrayList<>();@Overridepublic void add(Component component) {list.add(component);}@Overridepublic void remove(Component component) {list.remove(component);}@Overridepublic Component getChild(int i) {return list.get(i);}@Overridepublic void method() {for (Component component : list) {component.method();}}
}public class Leaf extends Component{@Overridepublic void add(Component component) {throw new RuntimeException("叶子节点无法添加元素");}@Overridepublic void remove(Component component) {throw new RuntimeException("叶子节点无法删除元素");}@Overridepublic Component getChild(int i) {throw new RuntimeException("叶子节点无法获取元素");}@Overridepublic void method() {}
}
4.3.3 组合模式的案例

在操作系统中,一个文件夹中可能存放着图像文件,视频文件,文本文件,也可能存放其他的文件夹,而对不同类型的文件进行的浏览操作也不一样。

image-20241026181555090
public abstract class AbstractFile {protected String fileName;public abstract void display();public abstract void add(AbstractFile file);public abstract void remove(AbstractFile file);
}
public class ImageFile extends AbstractFile{public ImageFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".png");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
public class TextFile extends AbstractFile{public TextFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".txt");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
public class Folder extends AbstractFile{private ArrayList<AbstractFile> files;public Folder(String fileName) {files = new ArrayList<>();this.fileName = fileName;}@Overridepublic void display() {System.out.println("打开" + this.fileName + "文件夹");for (AbstractFile file : files) {file.display();}}@Overridepublic void add(AbstractFile file) {this.files.add(file);}@Overridepublic void remove(AbstractFile file) {this.files.remove(file);}
}
4.3.4 组合模式的优缺点
优点缺点
1.可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次1.在增加新构件时很难对容器中的构件类型进行限制
2.客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构2.不是所有方法在叶子节点中都可以使用
3.增加新的容器构件和叶子构件都很方便,符合开闭原则
4.3.5 组合模式的适用场景
  • 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们

  • 在一个使用面向对象语言开发的系统中需要处理一个树形结构

  • 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型

4.3.6 组合模式的类型
  • 透明组合模式

image-20241026182814601

定义:抽象构件中声明了所有用于管理成员对象的方法,包括add()、remove(),以及getChild()等方法。

优点:确保所有的构件类都有相同的接口,客户端一致对待所有对象。

缺点:不够安全,因为叶子对象和容器对象在本质上是有区别的。

  • 安全组合模式
image-20241026182755661

定义:抽象构件Component中没有声明任何用于管理成员对象的方法,在Composite类中声明与实现这些方法

优点:优点是安全,对于叶子对象,客户端不可能调用到这些方法

缺点:不够透明,客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件

http://www.lryc.cn/news/470001.html

相关文章:

  • 【损害和风险评估&坑洼】路面坑洼检测系统源码&数据集全套:改进yolo11-DCNV3
  • GenAI 生态系统现状:不止大语言模型和向量数据库
  • gitlab 配置ssh keys
  • 小程序开发实战:PDF转换为图片工具开发
  • 我有两台120kw充电桩一天能赚多少钱
  • 深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间
  • stable-zero123模型构建指南
  • 算法题解记录32+++最长连续序列(百题筑基)
  • 全球知名度最高的华人起名大师颜廷利:世界顶级思想哲学教育家
  • Flink Rest API
  • Zig 语言通用代码生成器:逻辑,冒烟测试版发布二
  • mysql 通过GROUP BY 聚合并且拼接去重另个字段
  • Java应用程序的测试覆盖率之设计与实现(一)-- 总体设计
  • Unity C#脚本的热更新
  • 监督学习之逻辑回归
  • 深度优先算法(DFS)洛谷P1683-入门
  • Python数据分析基础
  • 《企业自设2-软件测试》线下课day3: 006扩展虚拟机
  • 配置和排查 Lombok 在 IDEA 中使用的详细步骤
  • JavaWeb合集18-接口管理Swager
  • 背包九讲——二维费用背包问题
  • 【mysql进阶】4-7. 通用表空间
  • 2024 年互联网大厂 1300 多道 JAVA 面试题汇总,包含了程序员的所有技术点
  • 【开源免费】基于SpringBoot+Vue.JS在线文档管理系统(JAVA毕业设计)
  • Linux资源与网络请求
  • RPA技术重塑企业自动化的未来
  • 使用RabbitMQ实现延迟消息的完整指南
  • 阿里员工:阿里工作7年至少得P7吧,快的都P8了,年薪100W是正常的,80才算及格...
  • Django进一步掌握(10月22日)
  • C++从入门到起飞之——红黑树封装map和set 全方位剖析!