首页 > 编程语言 >程序员必知!组合模式的实战应用与案例分析

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

时间:2024-01-09 15:04:05浏览次数:25  
标签:实战 组合 必知 double 程序员 套餐 new getPrice public

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

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

定义

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

组合模式(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方法中,我们遍历这个列表并计算总价格,客户端代码中,我们创建了具体的菜单项对象和套餐对象,并将菜单项添加到套餐中,然后输出套餐的价格。

核心总结

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

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

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

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

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

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

标签:实战,组合,必知,double,程序员,套餐,new,getPrice,public
From: https://blog.51cto.com/bytegood/9144184

相关文章

  • 【Spring技术专题】「实战开发系列」保姆级教你SpringBoot整合Mybatis框架实现多数据
    Mybatis是什么Mybatis是一个基于JDBC实现的,支持普通SQL查询、存储过程和高级映射的优秀持久层框架,去掉了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。Mybatis主要思想是将程序中大量的SQL语句剥离出来,配置在配置文件中,以实现SQL的灵活配置。在所有ORM框......
  • 程序员必知!代理模式的实战应用与案例分析
    代理模式是在不改变原对象基础上,通过代理对象控制访问并添加额外操作,以销售代表和助理为例,助理作为代理对象,处理邮件、数据等琐碎工作,使销售代表能专注于与客户面对面交流推销,代理模式让原对象功能得以扩展,同时保持其对外接口的透明性。定义代理模式提供了一种在不改变原有对......
  • 程序员如何准备好一次高质量的汇报?
    又到一年年末时,相信大家都希望在年终汇报的时候,能给老板展示一下自己女娲补天般的业绩,但很多人却往往讲成了流水账,本来90分的成绩,从嘴里说出来变成了60分。(文末附述职PPT模版下载)同事们普遍都觉得你做的很好,但是汇报过程中,你却发现语言讲不通、功劳说不清,该讲的不讲,不该讲的......
  • AWS IoT Core 实战指南
    AmazonWebServices(AWS)提供了全球范围内的托管服务,其中包括AWSIoTCore,专为连接和管理物联网设备而设计。这个实战指南将带你一步步了解如何使用AWSIoTCore来注册设备、提高安全性、进行通信以及利用设备影子功能。设备注册1.创建Thing(设备)在AWSIoT控制台中,创建一......
  • 低代码开发中的文件上传与数据处理:实战指南
    在当今的信息化时代,数据已成为企业的重要资产。为了更好地管理和利用这些数据,许多企业开始采用表单上传组件来导入和处理数据。通过使用表单上传组件,用户可以方便地将文件上传至系统中,然后进行后续的数据处理和分析。这种方式的优点在于,用户无需掌握复杂的编程技术,即可完成数据导入......
  • 《PySpark大数据分析实战》-10.独立集群模式的代码运行
    ......
  • 闪速优选--五天学会SpringCloud实战
    本专栏带你用SpringCloudAlibaba搭建一套项目,让你五天掌握微服务的使用。微服务是很重要的技术,学会微服务会大大提升个人竞争力,大大提高简历筛选和面试通过率。项目名字:闪速优选。SpringCloudAlibaba在2020年之后的微服务项目中占主流,学它是最好的选择。教程地址:SpringCloud项目......
  • 十年老程序员运营第一个万粉
    知乎twitter背景上学的时候,认识一些朋友,他们都在记录一些技术内容,后来也跟他们学习,在一些平台学习记录。出来工作后,内容运营有些方向性,我一开始就打算学习大数据方面,所以写作方向是大数据AI方面。分析应用开发:刚入行时候就没有兴趣。游戏开发:小时候父亲就是卖游戏软件方面,初中以后......
  • Lua网络爬虫实战:使用http服务器获取虾皮商品信息的全过程
    这段Lua代码是一个简单的爬虫示例,使用了Lua中的http模块进行网络请求,并设置了代理信息。以下是对代码的一些解释和注意事项:安装http模块:luarocksinstallhttp这个命令用于安装Lua的http模块,以便在程序中使用HTTP请求功能。代理设置:localproxy_host="www.duoip.cn......
  • 文心一言实战大全
    "文心一言"是一款基于人工智能的写作助手,它能够协助用户生成多种类型的文本。以下是一些使用"文心一言"的实战示例:写博文如果你是博客作者,"文心一言"可以帮助你轻松生成博文。只需输入你的主题或关键词,它将生成一篇相关的博文。你可以直接使用生成的博文,也可根据需要进行编辑和修改......