java设计模式-组合模式详解

Java设计模式-组合模式详解

什么是组合模式?

组合模式属于结构型设计模式,它将对象组合成树形结构,以表示'部分-整体'的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性,通常适用于处理树形结构,或者希望将单个对象和组合对象以相同的方式进行处理。

组合模式主要包含以下两种角色:

  • Component(抽象构件):定义了叶子和容器构件的公用接口,并提供默认实现

  • Leaf(叶子构件):在组合结构中表示叶子节点对象,它实现了Component接口的操作,但是叶子节点没有子节点

  • Composite(容器构件):表示容器节点对象,它实现了Component接口的操作,并且包含或管理子节点(即Leaf和Composite)

组合模式的优点是什么?

在使用组合模式时,可以获得以下优点:

  • 简化客户端操作,将单个对象和组合对象看作一致,无需过多考虑对象的层次结构

  • 客户可以一致性的使用组合结构中所有对象

  • 方便增加新的构件,符合开闭原则

组合模式示例1: 文件系统

现在我们使用组合模式实现一个文件系统,文件系统包含文件夹和文件两种对象,文件夹可以包含文件夹或文件。文件系统操作包含创建文件夹、创建文件、删除文件夹、删除文件以及展示文件和文件夹等。

public interface FileSystem {
    void show(String prefix);
    String getName();
}

public class Folder implements FileSystem {
    private final String name;
    private final List<FileSystem> files;

    public Folder(String name) {
        this.name = name;
        this.files = new ArrayList<>();
    }

    @Override
    public void show(String prefix) {
        System.out.println(prefix + name);
        prefix += "    "; // 缩进处理
        for (FileSystem file : files) {
            file.show(prefix);
        }
    }

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

    public void addFile(FileSystem file) {
        files.add(file);
    }

    public void removeFile(FileSystem file) {
        files.remove(file);
    }
}

public class File implements FileSystem {
    private final String name;

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

    @Override
    public void show(String prefix) {
        System.out.println(prefix + name);
    }

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

示例2: 饮品现场下单系统

在饮品下单系统中,有饮品和套餐两种对象,套餐对象包含了饮品和其他套餐,它们都可以打印出订单中的内容。具体的代码实现如下:

public abstract class Drink {
    protected final String name;
    protected final Double price;

    public Drink(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    public void print() {
        System.out.println(name + " : ¥" + price);
    }

    public Double getPrice() {
        return price;
    }
}

public class Coffee extends Drink {
    public Coffee(String name, Double price) {
        super(name, price);
    }
}

public class Juice extends Drink {
    public Juice(String name, Double price) {
        super(name, price);
    }
}

public class Meal {
    protected final String name;
    protected final Double price;
    protected final List<Drink> drinks;

    public Meal(String name) {
        this.name = name;
        this.price = 0.0;
        this.drinks = new ArrayList<>();
    }

    public Meal(String name, Double price) {
        this.name = name;
        this.price = price;
        this.drinks = new ArrayList<>();
    }

    public void addDrink(Drink drink) {
        drinks.add(drink);
    }

    public void removeDrink(Drink drink) {
        drinks.remove(drink);
    }

    public Double getPrice() {
        Double totalPrice = price;
        for (Drink drink : drinks) {
            totalPrice += drink.getPrice();
        }
        return totalPrice;
    }

    public void print() {
        System.out.println(String.format("套餐名称:%s, 价格:¥%.2f", name, getPrice()));
        System.out.println("饮品列表:");
        for (Drink drink : drinks) {
            drink.print();
        }
    }
}

public class SetMeal extends Meal {
    private final List<Meal> meals;

    public SetMeal(String name, Double price) {
        super(name, price);
        this.meals = new ArrayList<>();
    }

    public void addMeal(Meal meal) {
        meals.add(meal);
    }

    public void removeMeal(Meal meal) {
        meals.remove(meal);
    }

    @Override
    public Double getPrice() {
        Double totalPrice = price;
        for (Meal meal : meals) {
            totalPrice += meal.getPrice();
        }
        for (Drink drink : drinks) {
            totalPrice += drink.getPrice();
        }
        return totalPrice;
    }

    @Override
    public void print() {
        System.out.println(String.format("套餐名称:%s, 价格:¥%.2f", name, getPrice()));
        System.out.println("套餐包含:");
        for (Meal meal : meals) {
            meal.print();
        }
        System.out.println("饮品列表:");
        for (Drink drink : drinks) {
            drink.print();
        }
    }
}

以上就是组合模式的详解,包括了什么是组合模式、优点以及两个示例。使用组合模式可以非常方便地处理树形结构的数据,提高代码的可读性和可维护性,是一种非常实用的设计模式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java设计模式-组合模式详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • 在windows下揪出java程序占用cpu很高的线程并完美解决

    以下是针对“在 Windows 下揪出 Java 程序占用 CPU 很高的线程并完美解决”的完整攻略: 1. 使用 Java 可视化工具揪出占用 CPU 较高的线程 步骤1:下载 VisualVM VisualVM 是一款 Java 虚拟机监控和性能分析工具,可以在 Windows 等多个平台上使用,具有良好的界面和体验。可以到以下网址下载 VisualVM…

    Java 2023年5月19日
    00
  • 快速入门介绍Java中强大的String.format()

    让我为你详细讲解一下如何快速入门介绍Java中强大的String.format()。 什么是String.format()? String.format()是Java中一个非常强大的方法,它可以让我们将一种字符串格式转换为另一种格式。它使用的格式化字符串语法类似于C语言中的printf()函数。 String.format()方法的语法 String.for…

    Java 2023年5月26日
    00
  • Java中如何正确重写equals方法

    Java中的equals方法通常需要被重写,以便进行对象之间的比较。正确重写equals方法不仅可以提高代码质量,而且可以避免因错误的比较导致的程序错误。下面是Java中如何正确重写equals方法的完整攻略。 1. 理解equals方法 在开始重写equals方法之前,我们需要先理解equals方法的作用以及如何使用它来比较两个对象。在Java中,equa…

    Java 2023年5月26日
    00
  • 基于Java实现双向链表

    实现双向链表的步骤 1. 定义链表节点类 双向链表的节点类需要有三个属性: data: 保存节点所存放的数据。 prev: 保存上一个节点的引用。 next: 保存下一个节点的引用。 以下是这个节点类的简单实现: public class Node { public int data; public Node prev; public Node next; …

    Java 2023年5月19日
    00
  • Spring Boot面试必问之启动流程知识点详解

    下面我将为你详细讲解Spring Boot中启动流程的相关知识点。 1. Spring Boot应用启动原理 Spring Boot的应用启动依赖于Spring框架,其启动过程是基于Spring框架的启动过程进行的。在Spring Boot应用启动过程中,主要包含以下步骤: 加载Spring Boot应用的配置信息; 创建Spring应用上下文Applica…

    Java 2023年5月19日
    00
  • 一篇文章带你了解SpringMVC数据绑定

    一篇文章带你了解SpringMVC数据绑定 SpringMVC是一个非常流行的Java Web框架,它提供了一种方便的方式来处理HTTP请求和响应。在SpringMVC中,数据绑定是一个非常重要的概念,它允许我们将HTTP请求中的数据绑定到Java对象中,以便更方便地处理请求。本文将详细介绍SpringMVC数据绑定的原理和过程,并提供两个示例说明。 数据绑…

    Java 2023年5月17日
    00
  • 解决spring data jpa 批量保存更新的问题

    当我们要批量插入或更新数据时,使用Spring Data JPA的saveAll()方法可能会出现性能问题。 原因是saveAll()内部是将数据一条一条插入或更新到数据库,这样会导致插入或更新的性能较低,尤其在数据量较大的情况下。 为了解决这个问题,我们可以使用以下两种方式: 方式一:批量插入或更新实例列表 使用批量插入或更新实例列表的方法可以提高性能,不…

    Java 2023年5月20日
    00
  • FeignClient服务器抛出异常客户端处理方案

    要讲解”FeignClient服务器抛出异常客户端处理方案”,我们需要分别从服务端和客户端两个方面来进行说明。 服务端 在服务端,我们需要在被调用的服务接口上添加一个自定义异常处理器,以使得当服务端抛出异常时能够被正确地处理。具体步骤如下: 定义自定义异常类,并添加 @ResponseStatus 注解标识状态码,以方便客户端能够正确地处理异常。 @Resp…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部