Java 设计模式:结构型模式

Java 设计模式:结构型模式

结构型模式关注的是 类和对象的组合方式,它们提供了一种 灵活且可扩展的方式 来构建复杂系统。 这些模式主要通过 定义类和对象的结构 来解决系统设计中的 复杂性问题

一、 结构型模式分类

结构型模式主要分为以下几类:

  • 适配器模式 (Adapter):将一个类的接口转换成客户期望的另一个接口。适配器模式让你可以将现有的类和不兼容的类一起工作。
  • 桥接模式 (Bridge):将抽象部分与实现部分分离,使它们可以独立变化。桥接模式可以用来 减少类之间的耦合,并 提高代码的可复用性
  • 组合模式 (Composite):将对象组合成树形结构,以表示"部分 - 整体" 的层次关系。组合模式可以让你 统一地处理单个对象和组合对象
  • 装饰器模式 (Decorator):动态地给一个对象添加额外的职责。装饰器模式可以让你 在不修改原有类的情况下,扩展对象的功能
  • 外观模式 (Facade):为子系统提供一个统一的接口,隐藏子系统的复杂性。外观模式可以让你 简化对子系统的调用,并 降低耦合度
  • 享元模式 (Flyweight):运用共享技术有效地支持大量细粒度的对象。享元模式可以让你 减少内存占用,并 提高性能
  • 代理模式 (Proxy):为其他对象提供一种代理以控制对这个对象的访问。代理模式可以让你 控制对对象的访问,并 实现延迟加载、安全控制等功能

二、 结构型模式详解

1. 适配器模式 (Adapter)

定义: 将一个类的接口转换成客户期望的另一个接口。适配器模式让你可以将现有的类和不兼容的类一起工作。

分类:

  • 类适配器: 使用继承来实现适配器,将目标接口继承下来,并实现源接口。
  • 对象适配器: 使用组合来实现适配器,将目标对象作为成员变量,并实现源接口。

应用场景:

  • 需要使用一个已有类的功能,但是它的接口不符合需求。
  • 需要将多个接口统一成一个接口。

实例:

假设你需要使用一个第三方库的 LegacyClass 类,它使用的是老式的 LegacyInterface 接口,而你的程序需要使用的是 ModernInterface 接口。 你可以使用适配器模式来解决这个问题:

// LegacyInterface 接口
public interface LegacyInterface {
    void legacyMethod();
}

// LegacyClass 类
public class LegacyClass implements LegacyInterface {
    @Override
    public void legacyMethod() {
        System.out.println("调用 LegacyClass 的方法");
    }
}

// ModernInterface 接口
public interface ModernInterface {
    void modernMethod();
}

// 类适配器实现
public class ClassAdapter extends LegacyClass implements ModernInterface {
    @Override
    public void modernMethod() {
        // 将现代方法调用转化为旧的方法调用
        this.legacyMethod();
    }
}

// 对象适配器实现
public class ObjectAdapter implements ModernInterface {
    private LegacyClass legacyClass;

    public ObjectAdapter(LegacyClass legacyClass) {
        this.legacyClass = legacyClass;
    }

    @Override
    public void modernMethod() {
        // 将现代方法调用转化为旧的方法调用
        legacyClass.legacyMethod();
    }
}

// 使用适配器
public class Main {
    public static void main(String[] args) {
        // 使用类适配器
        ClassAdapter adapter1 = new ClassAdapter();
        adapter1.modernMethod();

        // 使用对象适配器
        ObjectAdapter adapter2 = new ObjectAdapter(new LegacyClass());
        adapter2.modernMethod();
    }
}

2. 桥接模式 (Bridge)

定义: 将抽象部分与实现部分分离,使它们可以独立变化。桥接模式可以用来 减少类之间的耦合,并 提高代码的可复用性

应用场景:

  • 当你希望 独立地修改抽象部分和实现部分 时。
  • 当你希望 提供多个实现部分,以满足不同的需求时。

实例:

假设你需要设计一个图形绘制工具,它可以绘制不同的形状,并且可以支持不同的颜色。 你可以使用桥接模式来实现这个功能:

// 形状抽象类
public abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

// 圆形类
public class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制一个" + color.getColorName() + "色的圆形");
    }
}

// 正方形类
public class Square extends Shape {
    public Square(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制一个" + color.getColorName() + "色的正方形");
    }
}

// 颜色抽象类
public abstract class Color {
    public abstract String getColorName();
}

// 红色类
public class Red extends Color {
    @Override
    public String getColorName() {
        return "红色";
    }
}

// 蓝色类
public class Blue extends Color {
    @Override
    public String getColorName() {
        return "蓝色";
    }
}

// 使用桥接模式
public class Main {
    public static void main(String[] args) {
        // 创建红色圆形
        Shape redCircle = new Circle(new Red());
        redCircle.draw();

        // 创建蓝色正方形
        Shape blueSquare = new Square(new Blue());
        blueSquare.draw();
    }
}

3. 组合模式 (Composite)

定义: 将对象组合成树形结构,以表示"部分 - 整体" 的层次关系。组合模式可以让你 统一地处理单个对象和组合对象

应用场景:

  • 需要表示 部分 - 整体 的层次关系。
  • 需要 统一地处理单个对象和组合对象

实例:

假设你需要设计一个文件系统,它可以包含目录和文件,并且可以递归地遍历文件系统。 你可以使用组合模式来实现这个功能:

// 文件系统抽象类
public abstract class FileSystemItem {
    public abstract String getName();

    public abstract void printDetails();

    public abstract FileSystemItem findItem(String name);
}

// 文件类
public class File extends FileSystemItem {
    private String name;

    public File(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void printDetails() {
        System.out.println("文件: " + name);
    }

    @Override
    public FileSystemItem findItem(String name) {
        return name.equals(this.name) ? this : null;
    }
}

// 目录类
public class Directory extends FileSystemItem {
    private String name;
    private List<FileSystemItem> items = new ArrayList<>();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void printDetails() {
        System.out.println("目录: " + name);
        for (FileSystemItem item : items) {
            item.printDetails();
        }
    }

    @Override
    public FileSystemItem findItem(String name) {
        for (FileSystemItem item : items) {
            if (item.getName().equals(name)) {
                return item;
            }
            if (item instanceof Directory) {
                FileSystemItem foundItem = ((Directory) item).findItem(name);
                if (foundItem != null) {
                    return foundItem;
                }
            }
        }
        return null;
    }

    public void addItem(FileSystemItem item) {
        items.add(item);
    }
}

// 使用组合模式
public class Main {
    public static void main(String[] args) {
        // 创建文件系统
        Directory root = new Directory("root");
        Directory dir1 = new Directory("dir1");
        Directory dir2 = new Directory("dir2");
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");

        // 构建树形结构
        root.addItem(dir1);
        root.addItem(dir2);
        dir1.addItem(file1);
        dir2.addItem(file2);

        // 打印文件系统细节
        root.printDetails();

        // 查找文件
        FileSystemItem foundFile = root.findItem("file2.txt");
        if (foundFile != null) {
            System.out.println("找到文件: " + foundFile.getName());
        }
    }
}

4. 装饰器模式 (Decorator)

定义: 动态地给一个对象添加额外的职责。装饰器模式可以让你 在不修改原有类的情况下,扩展对象的功能

应用场景:

  • 需要 动态地扩展对象的功能,而不改变原有类的代码。
  • 需要 提供多种装饰功能,并可以自由组合。

实例:

假设你需要设计一个咖啡机,它可以制作各种咖啡,并且可以添加不同的配料,比如糖、牛奶、香草等。 你可以使用装饰器模式来实现这个功能:

// 咖啡抽象类
public abstract class Coffee {
    public abstract String getDescription();

    public abstract double cost();
}

// 黑咖啡类
public class Espresso extends Coffee {
    @Override
    public String getDescription() {
        return "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}

// 装饰器抽象类
public abstract class CoffeeDecorator extends Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

    @Override
    public double cost() {
        return coffee.cost();
    }
}

// 糖装饰器类
public class Sugar extends CoffeeDecorator {
    public Sugar(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 糖";
    }

    @Override
    public double cost() {
        return coffee.cost() + 0.25;
    }
}

// 牛奶装饰器类
public class Milk extends CoffeeDecorator {
    public Milk(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + " + 牛奶";
    }

    @Override
    public double cost() {
        return coffee.cost() + 0.50;
    }
}

// 使用装饰器模式
public class Main {
    public static void main(String[] args) {
        // 创建黑咖啡
        Coffee espresso = new Espresso();
        System.out.println(espresso.getDescription() + " $" + espresso.cost());

        // 添加糖和牛奶
        Coffee coffeeWithSugarAndMilk = new Milk(new Sugar(espresso));
        System.out.println(coffeeWithSugarAndMilk.getDescription() + " $" + coffeeWithSugarAndMilk.cost());
    }
}

5. 外观模式 (Facade)

定义: 为子系统提供一个统一的接口,隐藏子系统的复杂性。外观模式可以让你 简化对子系统的调用,并 降低耦合度

应用场景:

  • 需要 简化对复杂子系统的调用
  • 需要 降低子系统与其他模块的耦合度

实例:

假设你需要设计一个数据库系统,它包含多个组件,比如连接池、数据库操作、事务管理等。 你可以使用外观模式来简化对数据库系统的调用:

// 数据库子系统接口
public interface DatabaseSubsystem {
    void connect();

    void executeQuery(String query);

    void commitTransaction();

    void rollbackTransaction();

    void disconnect();
}

// 数据库子系统实现类
public class DatabaseSubsystemImpl implements DatabaseSubsystem {
    // 连接池
    private ConnectionPool connectionPool;

    // 数据库操作
    private DatabaseOperations databaseOperations;

    // 事务管理
    private TransactionManager transactionManager;

    public DatabaseSubsystemImpl(ConnectionPool connectionPool, DatabaseOperations databaseOperations, TransactionManager transactionManager) {
        this.connectionPool = connectionPool;
        this.databaseOperations = databaseOperations;
        this.transactionManager = transactionManager;
    }

    @Override
    public void connect() {
        connectionPool.getConnection();
    }

    @Override
    public void executeQuery(String query) {
        databaseOperations.executeQuery(query);
    }

    @Override
    public void commitTransaction() {
        transactionManager.commitTransaction();
    }

    @Override
    public void rollbackTransaction() {
        transactionManager.rollbackTransaction();
    }

    @Override
    public void disconnect() {
        connectionPool.releaseConnection();
    }
}

// 数据库外观类
public class DatabaseFacade {
    private DatabaseSubsystem databaseSubsystem;

    public DatabaseFacade(DatabaseSubsystem databaseSubsystem) {
        this.databaseSubsystem = databaseSubsystem;
    }

    public void executeAndCommit(String query) {
        databaseSubsystem.connect();
        databaseSubsystem.executeQuery(query);
        databaseSubsystem.commitTransaction();
        databaseSubsystem.disconnect();
    }

    public void executeAndRollback(String query) {
        databaseSubsystem.connect();
        databaseSubsystem.executeQuery(query);
        databaseSubsystem.rollbackTransaction();
        databaseSubsystem.disconnect();
    }
}

// 使用数据库外观
public class Main {
    public static void main(String[] args) {
        // 创建数据库子系统
        DatabaseSubsystem databaseSubsystem = new DatabaseSubsystemImpl(new ConnectionPool(), new DatabaseOperations(), new TransactionManager());

        // 创建数据库外观
        DatabaseFacade databaseFacade = new DatabaseFacade(databaseSubsystem);

        // 使用外观执行查询并提交事务
        databaseFacade.executeAndCommit("SELECT * FROM users");

        // 使用外观执行查询并回滚事务
        databaseFacade.executeAndRollback("UPDATE users SET name = 'John'");
    }
}

6. 享元模式 (Flyweight)

定义: 运用共享技术有效地支持大量细粒度的对象。享元模式可以让你 减少内存占用,并 提高性能

应用场景:

  • 需要 创建大量相同或相似的对象
  • 需要 减少内存占用,并 提高性能

实例:

假设你需要设计一个游戏,它需要创建大量的树木,而这些树木可能只是颜色和大小不同,其他属性都相同。 你可以使用享元模式来实现这个功能:

// 树抽象类
public abstract class Tree {
    public abstract void draw(int x, int y);
}

// 具体树类
public class ConcreteTree implements Tree {
    private String color;
    private int size;

    public ConcreteTree(String color, int size) {
        this.color = color;
        this.size = size;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("绘制一棵 " + color + " 色的树,大小为 " + size + ",位置为 (" + x + ", " + y + ")");
    }
}

// 树工厂类
public class TreeFactory {
    private Map<String, Tree> trees = new HashMap<>();

    public Tree getTree(String color, int size) {
        String key = color + "_" + size;
        Tree tree = trees.get(key);
        if (tree == null) {
            tree = new ConcreteTree(color, size);
            trees.put(key, tree);
        }
        return tree;
    }
}

// 使用享元模式
public class Main {
    public static void main(String[] args) {
        // 创建树工厂
        TreeFactory treeFactory = new TreeFactory();

        // 创建多棵树
        Tree tree1 = treeFactory.getTree("绿色", 10);
        Tree tree2 = treeFactory.getTree("绿色", 10);
        Tree tree3 = treeFactory.getTree("蓝色", 5);

        // 绘制树
        tree1.draw(10, 20);
        tree2.draw(30, 40);
        tree3.draw(50, 60);
    }
}

7. 代理模式 (Proxy)

定义: 为其他对象提供一种代理以控制对这个对象的访问。代理模式可以让你 控制对对象的访问,并 实现延迟加载、安全控制等功能

分类:

  • 远程代理: 为位于不同地址空间的对象提供本地代理。
  • 虚拟代理: 为需要较长时间创建的对象提供代理,延迟创建真实对象。
  • 保护代理: 为真实对象提供安全控制,限制对对象的访问。

应用场景:

  • 需要 控制对对象的访问
  • 需要 实现延迟加载、安全控制等功能

实例:

假设你需要设计一个图片加载器,它可以加载网络图片。 你可以使用代理模式来实现这个功能,并实现延迟加载:

// 图片接口
public interface Image {
    void display();
}

// 真实图片类
public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk(fileName);
    }

    private void loadFromDisk(String fileName) {
        System.out.println("从磁盘加载 " + fileName + " 图片...");
        // 这里模拟图片加载过程
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("图片加载完成");
    }

    @Override
    public void display() {
        System.out.println("显示 " + fileName + " 图片");
    }
}

// 图片代理类
public class ProxyImage implements Image {
    private String fileName;
    private RealImage realImage;

    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName);
        }
        realImage.display();
    }
}

// 使用代理模式
public class Main {
    public static void main(String[] args) {
        // 创建图片代理
        Image image = new ProxyImage("photo.jpg");

        // 首次调用 display(),会加载图片
        image.display();

        // 再次调用 display(),图片已经加载,直接显示
        image.display();
    }
}

三、 总结

结构型模式是设计模式中非常重要的组成部分,它们提供了一种灵活且可扩展的方式来构建复杂系统。 在实际开发中,我们可以根据具体需求选择合适的结构型模式来 提高代码的可读性、可维护性和可扩展性

需要注意的是,设计模式不是万能的,应该根据实际情况选择合适的模式,不要为了使用模式而使用模式。

  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯陀含

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值