程序员必知!组合模式的实战应用与案例分析

程序员必知!组合模式的实战应用与案例分析 - 程序员古德

组合模式是一种设计模式,允许将对象组合成树形结构并像单个对象一样使用它们,这种模式在处理类似公司组织结构这样的树形数据时非常有用,通过组合模式,我们可以将公司和部门视为同一类型的对象,从而以统一的方式处理发送给不同层级的请求或任务,叶节点是没有子节点的对象,而复合节点则包含子节点,客户端可以与这些节点进行交互,无需知道它们的具体类型。组合模式提供了表示层次结构的灵活方式,并统一了客户端的交互方式。

定义

程序员必知!组合模式的实战应用与案例分析 - 程序员古德

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得客户端对单个对象和复合对象的使用具有一致性。

举个业务中形象的例子,比如,我们有一个餐饮公司,其中提供了各种食品,如汉堡、薯条、饮料等,同时,公司也提供套餐服务,比如“汉堡套餐”包括汉堡、薯条和饮料,“全餐套餐”包括汉堡、薯条、饮料和沙拉。在这个例子中,每一个食品,如汉堡、薯条、饮料和沙拉,都可以被视为一个单独的组件,而套餐,比如“汉堡套餐”和“全餐套餐”,则是由这些组件组合而成的复合组件。

使用组合模式,我们可以设计一个统一的接口,比如“Orderable”,所有食品和套餐都实现这个接口,这个接口可以包含方法如“getPrice()”和“serve()”,单个食品如汉堡、薯条等实现这些方法以返回自己的价格和提供自己的服务,而套餐则在其实现中递归地调用其子组件的相应方法,从而计算出总价并提供整套服务。

这样,无论是单个食品还是套餐,对于客户来说,都可以通过相同的接口进行点单和获取价格等操作,而无需关心它们内部的具体构成。

代码案例

程序员必知!组合模式的实战应用与案例分析 - 程序员古德

就拿上面餐饮公司的业务案例,下面分别是针对该业务实现的未使用组合模式的反例和使用了组合模式的正例。

1、反例,未使用组合模式

没有使用组合模式,可能会采用一种比较简单直接的方法来实现,如下代码:

// 食品接口  
public interface Food {  
    double getPrice();  
}  
  
// 汉堡类  
public class Burger implements Food {  
    @Override  
    public double getPrice() {  
        return 10.0;  
    }  
}  
  
// 薯条类  
public class Fries implements Food {  
    @Override  
    public double getPrice() {  
        return 5.0;  
    }  
}  
  
// 饮料类  
public class Drink implements Food {  
    @Override  
    public double getPrice() {  
        return 3.0;  
    }  
}  
  
// 沙拉类  
public class Salad implements Food {  
    @Override  
    public double getPrice() {  
        return 7.0;  
    }  
}  
  
// 汉堡套餐类  
public class BurgerCombo {  
    private Burger burger = new Burger();  
    private Fries fries = new Fries();  
    private Drink drink = new Drink();  
      
    public double getPrice() {  
        return burger.getPrice() + fries.getPrice() + drink.getPrice();  
    }  
}  
  
// 全餐套餐类  
public class FullMealCombo {  
    private Burger burger = new Burger();  
    private Fries fries = new Fries();  
    private Drink drink = new Drink();  
    private Salad salad = new Salad();  
      
    public double getPrice() {  
        return burger.getPrice() + fries.getPrice() + drink.getPrice() + salad.getPrice();  
    }  
}  
  
// 客户端调用案例  
public class Client {  
    public static void main(String[] args) {  
        // 创建汉堡套餐对象并获取价格  
        BurgerCombo burgerCombo = new BurgerCombo();  
        System.out.println("汉堡套餐价格: " + burgerCombo.getPrice()); // 输出: 18.0  
          
        // 创建全餐套餐对象并获取价格  
        FullMealCombo fullMealCombo = new FullMealCombo();  
        System.out.println("全餐套餐价格: " + fullMealCombo.getPrice()); // 输出: 28.0  
    }  
}

在上述代码中,我们定义了Food接口和四个实现类BurgerFriesDrinkSalad,然后,我们为每种套餐创建了一个单独的类(BurgerComboFullMealCombo),并在这些类中组合了不同的食品对象。

这种方式的问题在于,每当我们需要添加新的套餐或者修改现有套餐的组合时,都需要创建或修改相应的类,这会导致代码的维护成本增加,并且不利于代码的复用和扩展。

2、正例,使用组合模式

使用组合模式,如下代码:

// 菜单项接口,定义了计算价格的方法  
interface MenuItem {  
    double getPrice();  
}  
  
// 具体菜单项类,实现了菜单项接口  
class Burger implements MenuItem {  
    @Override  
    public double getPrice() {  
        return 5.0; // 汉堡的价格  
    }  
}  
  
class Fries implements MenuItem {  
    @Override  
    public double getPrice() {  
        return 3.0; // 薯条的价格  
    }  
}  
  
class Drink implements MenuItem {  
    @Override  
    public double getPrice() {  
        return 2.0; // 饮料的价格  
    }  
}  
  
class Salad implements MenuItem {  
    @Override  
    public double getPrice() {  
        return 4.0; // 沙拉的价格  
    }  
}  
  
// 套餐类,实现了菜单项接口,并包含一个菜单项列表  
class Meal extends ArrayList<MenuItem> implements MenuItem {  
    @Override  
    public double getPrice() {  
        double sum = 0.0;  
        for (MenuItem item : this) {  
            sum += item.getPrice(); // 计算套餐的总价格  
        }  
        return sum;  
    }  
}  
  
// 客户端调用案例  
public class Main {  
    public static void main(String[] args) {  
        // 创建具体的菜单项对象  
        MenuItem burger = new Burger();  
        MenuItem fries = new Fries();  
        MenuItem drink = new Drink();  
        MenuItem salad = new Salad();  
          
        // 创建套餐对象,并将具体的菜单项添加到套餐中  
        Meal burgerMeal = new Meal();  
        burgerMeal.add(burger);  
        burgerMeal.add(fries);  
        burgerMeal.add(drink);  
        System.out.println("汉堡套餐的价格: $" + burgerMeal.getPrice()); // 输出: 汉堡套餐的价格: $10.0  
          
        Meal fullMeal = new Meal();  
        fullMeal.add(burger);  
        fullMeal.add(fries);  
        fullMeal.add(drink);  
        fullMeal.add(salad);  
        System.out.println("全餐套餐的价格: $" + fullMeal.getPrice()); // 输出: 全餐套餐的价格: $14.0  
    }  
}

在上述代码中,我们定义了一个MenuItem接口,它有一个getPrice方法用于计算价格,具体的菜单项(如BurgerFriesDrinkSalad)实现了这个接口,套餐类(Meal)也实现了这个接口,并且包含一个菜单项列表,在套餐类的getPrice方法中,我们遍历这个列表并计算总价格,客户端代码中,我们创建了具体的菜单项对象和套餐对象,并将菜单项添加到套餐中,然后输出套餐的价格。

核心总结

程序员必知!桥接模式的实战应用与案例分析 - 程序员古德

组合模式,就是把一些对象组合起来,形成一个树状的结构,这种结构特别像我们平常生活中遇到的那种“部分与整体”的关系。比如说,一个公司由不同的部门组成,每个部门又有自己的员工,这样一层一层组合起来,就形成了一个完整的公司结构。

使用组合模式,可以简化客户端的代码,客户端在处理单个对象和一堆对象组合起来的大对象时,不需要知道它们之间的区别,可以用同样的方式处理,这就好像我们在处理一个单独的员工和一个整个部门时,可以用同样的方法来下达指令,而不需要去了解他们内部的具体细节。

组合模式还能提高系统的可扩展性,如果我们想添加新的组件类型,只需要在现有的基础上稍作修改,就可以轻松实现,这就像一个搭积木的过程,我们可以随时添加新的积木类型,搭建出更丰富的造型。

它的缺点就是结构的复杂性,如果组件和叶子有很多共同行为,但又存在一些微小的差异,那么在组合模式中处理它们可能会变得很复杂。这就好像我们在处理一堆形状、颜色都差不多的积木时,要找出其中那一块与众不同的积木一样困难。另外,由于组合模式使用了递归,如果组合的结构太深或者太大,可能会导致大量的内存消耗。这就像我们不断地往积木塔上添加积木,最终导致塔太高而倒塌一样。

关注我,每天学习互联网编程技术 - 程序员古德

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《程序员的硬核识大全》是一本面向程序员的综合性识手册,涵盖了各个领域的关键识点,旨在帮助程序员提升技术水平和解决实际问题。该书以PDF格式出版,便于读者在电脑、手机等设备上随时查阅。 该书内容包括以下几个方面的硬核识: 1. 编程语言识:介绍了主流的编程语言,如Java、C++、Python等,包括语法、数据结构、算法等方面的内容。 2. 操作系统和计算机原理:详细介绍了操作系统的基本原理和常见问题解决方法,以及计算机组成原理和计算机网络等相关识。 3. 数据库和存储识:讲解了数据库设计和管理的基本原理,介绍了关系型数据库如MySQL和非关系型数据库如MongoDB等的使用方法和优化技巧。 4. 网站和网络开发识:包括Web开发的基本原理、前后端开发技术、网络安全和性能优化等方面的内容。 5. 软件工程和开发方法论:介绍了软件工程的基本概念和常用开发方法,包括敏捷开发、测试驱动开发和持续集成等。 6. 设计模式和架构识:详细介绍了常用的设计模式和软件架构,帮助程序员设计可维护、可扩展和高效的软件系统。 除了以上几个方面的内容,该书还涵盖了其他与程序员工作密切相关的技术和识,如版本控制、软件部署、性能调优等。《程序员的硬核识大全》适合本科或者有一定编程经验的程序员阅读,对于提高技术实力和职业发展都有很大帮助。 ### 回答2: "程序员的硬核识大全 pdf"是一份提供程序员识的电子书,PDF格式可以方便地在各种设备上阅读。这本书包含了各个方面的硬核识,帮助程序员提高技术能力和解决问题的能力。 这本电子书的内容包括了数据结构和算法,编程语言,操作系统,网络通信,数据库管理等各方面的识。对于程序员而言,这些都是非常重要的基础识,能够帮助他们理解和设计高效的程序。 在数据结构和算法部分,程序员将学习到各种基础的数据结构,如数组、链表、栈和队列,以及常见的算法,如排序和搜索算法。这些识对于程序的效率和性能优化至关重要。 编程语言部分将介绍多种编程语言,如C、C++、Java和Python等。这些语言在不同的领域有各自的优点和适用范围,程序员需要了解它们的特点和使用方法,以便在开发项目时选择合适的语言。 操作系统部分将深入讲解操作系统的原理和设计。程序员将了解到进程管理、内存管理、文件系统等重要概念,这些对于编写具有高可靠性和高性能的程序至关重要。 网络通信部分将介绍计算机网络的基本原理和常见的协议,如TCP/IP和HTTP等。程序员需要理解网络通信的基础识,以便与其他系统进行数据交换和通信。 数据库管理部分将详细介绍关系型数据库和非关系型数据库的原理和使用方法。程序员需要了解数据库的设计和优化,以提高数据的存储和检索效率。 总之,这本电子书涵盖了程序员备的硬核识,对于提高他们的技术能力和解决问题的能力非常有帮助。 ### 回答3: 《程序员的硬核识大全》是一本汇集了程序员备的核心识的书籍,可以帮助程序员提升自己的技术水平。这本书涵盖了计算机科学的各个领域和重要概念,包括数据结构与算法、操作系统、编程语言、网络通信、数据库、Web开发、软件工程等。 在数据结构与算法部分,书中介绍了常用的数据结构如链表、栈、队列以及各种排序和搜索算法,帮助程序员理解和应用这些经典的算法。在操作系统方面,书中讲解了进程、线程、内存管理、文件系统等重要概念,帮助程序员深入了解计算机系统的工作原理。 在编程语言方面,书中列举了多种编程语言的特性和应用场景,如C++、Java、Python等,有助于程序员选择适合自己的编程语言并掌握其特性。在网络通信部分,书中介绍了TCP/IP协议、HTTP协议等重要的网络通信协议和技术,帮助程序员理解网络通信的基本原理。 此外,书中还介绍了数据库的相关识,包括关系数据库、SQL语言、数据备份与恢复等内容,有助于程序员设计和管理数据库。在Web开发方面,书中介绍了前端开发、后端开发、服务器部署等关键技术,帮助程序员构建高效、安全的Web应用程序。 最后,在软件工程方面,书中讲解了软件开发的生命周期、需求分析、设计模式、测试和持续集成等内容,有助于程序员理解和掌握软件开发过程中的重要环节。 总的来说,这本《程序员的硬核识大全》提供了一站式的学习资料,涵盖了程序员备的核心识,可以帮助程序员系统地学习和应用这些识,提升自己的技术能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员古德

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

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

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

打赏作者

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

抵扣说明:

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

余额充值