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

设计模式-结构型模式(详解)

适配器模式

将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题。

适配器模式由四部分组成:

  1. 客户端:即需要使用目标接口的类

  2. 目标接口

  3. 需要适配的类,也就是已经存在好的功能,但客户端通过目标接口没办法使用这个类

  4. 适配器,会实现目标接口,然后耦合需要适配的类,调用类的功能

分为类适配器和对象适配器

// 目标接口
public interface Target {void request();
}
// 适配者类
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 类适配器
public class Adapter extends Adaptee implements Target {@Overridepublic void request() {specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Target target = new Adapter();target.request();  // Output: Adaptee's specificRequest}
}

对象适配器: 通过组合,让适配器类持有现有类的实例,并实现目标接口**。对象适配器使用组合关系来实现接口的适配**,较为常用。

// 目标接口
public interface Target {void request();
}
// 适配者类
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 对象适配器
public class Adapter implements Target {  //这里不再是和类适配器一样继承适配器,而是在类中装配适配器对象private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request();  // Output: Adaptee's specificRequest}
}

Java 日志中的 slf4j 其实就是使用了适配器模式来统一不同日志框架接口,使得我们不需要修改代码就可以替换不同的底层日志实现。

桥接模式

主要的作用是将抽象和实现解耦,使它们可以独立地变化。

我们熟知的JDBC 就使用了桥接模式,JDBC定义了抽象的规范,不同的数据库厂商遵循这些规范,但是它们各自又会有不同的实现。
在使用中,如果我们数据库是 mysql,则传入 com.mysql.jdbc.Driver 驱动实现类,如果要换成 oracle替换实现类为oracle.jdbc.driver.OracleDriver 即可,这就是典型的抽象与实现解耦。

代码实例

实现形状颜色解耦

  1. 实现化(Implementor):定义颜色接口

    public interface Color {void applyColor();
    }
    
  2. 具体实现化(Concrete Implementor):实现具体颜色

    public class RedColor implements Color {@Overridepublic void applyColor() { System.out.println("Applying red color");  //红色}
    }public class BlueColor implements Color {   //蓝色@Overridepublic void applyColor() {System.out.println("Applying blue color");}
    }
    
  3. 抽象化(Abstraction):定义形状接口

    public abstract class Shape {protected Color color;public Shape(Color color) {this.color = color;}public abstract void draw();
    }
    
  4. 细化抽象化(Refined Abstraction):实现具体形状

    public class Circle extends Shape {public Circle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a circle with ");color.applyColor();}
    }public class Rectangle extends Shape {public Rectangle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a rectangle with ");color.applyColor();}
    }
    
  5. 客户端代码

    public class Client {public static void main(String[] args) {// 创建红色圆形Shape redCircle = new Circle(new RedColor());redCircle.draw();  // 输出: Drawing a circle with Applying red color// 创建蓝色矩形Shape blueRectangle = new Rectangle(new BlueColor());blueRectangle.draw();  // 输出: Drawing a rectangle with Applying blue color}
    }
    

组合模式

将对象组合成树状结构以表示“整体——部分”的层次关系

以部门为示例,展示组织内的部门和人员信息

// 抽象组织
interface OrganizationComponent {  void showDetails();
}// 组织人员
class Employee implements OrganizationComponent {private String name;private String position;public Employee(String name, String position) {this.name = name;this.position = position;}@Overridepublic void showDetails() {System.out.println("Employee: " + name + ", Position: " + position);}
}// 组织部门
class Department implements OrganizationComponent {private String name;private List<OrganizationComponent> components = new ArrayList<>();public Department(String name) {this.name = name;}@Overridepublic void showDetails() {System.out.println("Department: " + name);for (OrganizationComponent component : components) {component.showDetails();}}public void add(OrganizationComponent component) { //往部门添加人员 或 部门components.add(component);}public void remove(OrganizationComponent component) {components.remove(component);}
}// 使用代码
public class Client {public static void main(String[] args) {// 创建人员OrganizationComponent employee1 = new Employee("John Doe", "Developer");OrganizationComponent employee2 = new Employee("Jane Smith", "Designer");OrganizationComponent employee3 = new Employee("Emily Davis", "Manager");// 创建部门Department engineeringDepartment = new Department("Engineering Department");Department designDepartment = new Department("Design Department");Department headDepartment = new Department("Head Department");// 添加人员到部门engineeringDepartment.add(employee1);designDepartment.add(employee2);headDepartment.add(employee3);// 添加子部门到上级部门headDepartment.add(engineeringDepartment);headDepartment.add(designDepartment);// 显示整个组织结构的详情headDepartment.showDetails();// 输出// Department: Head Department// Employee: Emily Davis, Position: Manager// Department: Engineering Department// Employee: John Doe, Position: Developer// Department: Design Department// Employee: Jane Smith, Position: Designer}
}

通过组合模式,提供统一的接口,简化对层次结构的处理,使得使用方代码更加简洁与灵活。

装饰器模式

主要作用是通过创建包装类来实现功能的增强,而不是修改原始类

通过创建一个装饰器类,该类实现了与原始对象相同的接口,并持有一个原始对象的引用。通过将原始对象传递给装饰器

代理模式中,代理类附加的是跟原始类无关的功能,而在装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

最典型的装饰器实现就是 Java 中的I/O类库,示例代码如下:

import java.io.*;
public class IOExample {public static void main(String[] args) throws IOException {File file = new File("test.txt");FileInputStream fis = new FileInputStream(file);  //读取文件流BufferedInputStream bis = new BufferedInputStream(fis);  //fis被BufferedlnputStream 装饰,提供了缓存的功能DataInputStream dis = new DataInputStream(bis); //被 DatalnputStream 装饰,提供了按数据类型读取的功能while (dis.available() > 0) {System.out.println(dis.readLine());}dis.close();}
}

文件流的代码比较复杂,这里就不展示了,我们简单看个多装饰器叠加的代码实现:

// 组件
interface Component {void operation();
}// 具体构件
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation");}
}// 装饰器
abstract class Decorator implements Component {protected Component component;   public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
// 具体装饰器 A
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorA added behavior");}
}
// 具体装饰器 B
class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedState();}private void addedState() {System.out.println("ConcreteDecoratorB added state");}
}// 客户端代码
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB.operation();// Output:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added state}
}

外观模式

也叫门面模式,提供了一个简化的接口,用于访问复杂系统中的一组接口。将复杂系统的功能封装起来,让客户端可以更方便地使用系统功能而不需要了解其内部复杂结构。

举个例子就清晰了。例如 A系统有 a、b、c三个接口,B需要分别调用 a、b、c三个接口,这样比较麻烦,所以A将 a、b、c封装成一个接口给B调用,对B来说使用起来就方便了,这就是外观模式

class CPU {         //CPUpublic void start() {System.out.println("CPU 启动");}public void shutdown() {System.out.println("CPU 关闭");}
}
class Memory {            //内存public void start() {System.out.println("内存启动");}public void shutdown() {System.out.println("内存关闭");}
}class HardDrive {     //硬盘public void start() {System.out.println("硬盘启动");}public void shutdown() {System.out.println("硬盘关闭");}}
class ComputerFacade {         //外观类,封装了计算机系统的一组复杂接口,包括 CPU、内存和硬盘的启动和关闭private CPU cpu;private Memory memory;private HardDrive hardDrive;public ComputerFacade() {cpu = new CPU();memory = new Memory();hardDrive = new HardDrive();}public void start() {       //启动计算机System.out.println("计算机启动开始");cpu.start();memory.start();hardDrive.start();System.out.println("计算机启动完成");}public void shutdown() {    //关闭计算机System.out.println("计算机关闭开始");cpu.shutdown();memory.shutdown();hardDrive.shutdown();System.out.println("计算机关闭完成");}
}
ComputerFacade computerFacade = new ComputerFacade();
computerFacade.start();
// 输出:
// 计算机启动开始
// CPU 启动
// 内存启动
// 硬盘启动
// 计算机启动完成computerFacade.shutdown();
// 输出:
// 计算机关闭开始
// CPU 关闭
// 内存关闭
// 硬盘关闭
// 计算机关闭完成

享元模式

享元模式本质就是对象池,判断是否存在,若存在则取,不存在则添加。

Integer的缓存(-128~127)采用了享元模式。

具体原理可看 Java基础 29.什么是Java的Integer缓冲池?

示例:

假设我们要绘制棋盘上的棋子,棋子的种类有很多,但是每种棋子的形状和颜色是固定的。我们可以使用享元模式来共享相同种类的棋子对象,从而减少对象的创建数量。

// 棋子接口
interface ChessPiece {void setColor(String color);void display(int x, int y);
}
// 具体棋子类
class ConcreteChessPiece implements ChessPiece {private String color;public ConcreteChessPiece(String color) {this.color = color;}@Overridepublic void setColor(String color) {this.color = color;}@Overridepublic void display(int x, int y) {System.out.println("Chess Piece color: " + color + ", position: (" + x + "," + y + ")");}
}
// 享元工厂类
class ChessPieceFactory {private Map<String, ChessPiece> chessPieces;public ChessPieceFactory() {this.chessPieces = new HashMap<>();    //用集合存chessPieces}public ChessPiece getChessPiece(String color) {  //返回单例ChessPiece chessPiece = chessPieces.get(color);if (chessPiece == null) {chessPiece = new ConcreteChessPiece(color);chessPieces.put(color, chessPiece);}return chessPiece;}
}
// 客户端代码
public class Client {public static void main(String[] args) {ChessPieceFactory chessPieceFactory = new ChessPieceFactory();ChessPiece blackPiece1 = chessPieceFactory.getChessPiece("black");  ChessPiece blackPiece2 = chessPieceFactory.getChessPiece("black");ChessPiece whitePiece1 = chessPieceFactory.getChessPiece("white");ChessPiece whitePiece2 = chessPieceFactory.getChessPiece("white");blackPiece1.display(1, 2);  // 输出:Chess Piece color: black, position: (1,2)blackPiece2.display(3, 4);  // 输出:Chess Piece color: black, position: (3,4)whitePiece1.display(5, 6);  // 输出:Chess Piece color: white, position: (5,6)whitePiece2.display(7, 8);  // 输出:Chess Piece color: white, position: (7,8)}
}

代理模式

作用:在不改变原始类的情况下,为其提供一个代理,以控制对这个对象的访问

(代理模式和装饰器模式很像,其主要不同是,前者是控制原对象的访问,后者是为原对象增强已有类的功能)

核心是创建一个代理类,该类实现了与原始对象相同的接口,并持有一个原始对象的引用。在代理类的方法中,我们可以添加额外的功能,然后将请求转发给原始对象进行处理。

// 图片接口
interface Image {void display();
}
// 具体图片类
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadImageFromDisk();}private void loadImageFromDisk() {System.out.println("Loading " + filename + " from disk.");}@Overridepublic void display() {System.out.println("Displaying " + filename);}
}
// 代理图片类
class ProxyImage implements Image {private RealImage realImage;   //引入具体图片类private String filename;		//实现了对原始图片对象的控制,而不需要修改原始图片类的代码public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}beforeDisplay();realImage.display();}private void beforeDisplay() {System.out.println("Before displaying " + filename + ", do some pre-processing.");}
}
// 客户端代码
public class Client {public static void main(String[] args) {Image image1 = new ProxyImage("image1.jpg");Image image2 = new ProxyImage("image2.jpg");image1.display();  // 输出:Before displaying image1.jpg, do some pre-processing.//        Loading image1.jpg from disk.//        Displaying image1.jpgimage2.display();  // 输出:Before displaying image2.jpg, do some pre-processing.//        Loading image2.jpg from disk.//        Displaying image2.jpg}
}

相关文章:

  • 粗糙表面生成程序及模拟方法
  • docker部署并测试翻译模型-CSANMT连续语义增强机器翻译
  • 典型城市工况数据(Drive Cycle)用于车辆仿真
  • 用算法实现 用统计的方式实现 用自然语言处理的方法实现 用大模型实现 专利精益化统计分析
  • 网络学习-TCP协议(七)
  • 深度解析:SQLynx 如何筑牢数据库安全防线​
  • 敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系
  • 使用 GPUStack 纳管摩尔线程 GPU 进行大语言模型和文生图模型的推理
  • 相同,对称,平衡,右视图(二叉树)
  • 全国青少年信息素养大赛-python编程—省赛真题—卡牌游戏
  • 国产高云FPGA实现MIPI视频解码+图像缩放,基于OV5647摄像头,提供Gowin工程源码和技术支持
  • LVS + Keepalived + Nginx 高可用负载均衡系统实验
  • 学习黑客 tcpdump
  • 如何在UI设计中更好地平衡美学与功能性?
  • IP-guard发布新版本4.87.2241.0
  • css 里面写if else 条件判断
  • [Windows] 格式工厂 FormatFactory v5.20.便携版 ——多功能媒体文件转换工具
  • 禅道——安装PHP的ioncube扩展
  • wordpress上传图片时出现服务器无法处理图片
  • 高通usecase理解
  • 模板网恋/潮州seo建站
  • 长沙做四维彩超玛丽亚m网站/seo优化软件有哪些
  • 邯郸网站设计服务平台/搜索引擎排名优化建议
  • 沈阳做企业网站/网站查询ip
  • 开通网站费可以做待摊费用吗/如何建立个人网站的步骤
  • h5网站开发多少钱/南昌seo搜索优化