• 建造者模式 rust和java的实现


    建造者模式

    建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。

    一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

    介绍

    • 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
    • 主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
    • 关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
    • 应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
    优点
    • 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
    • 可以更好地控制构建过程,隐藏具体构建细节。
    • 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
    缺点
    • 如果产品的属性较少,建造者模式可能会导致代码冗余。
    • 建造者模式增加了系统的类和对象数量。
    使用场景
    • 需要生成的对象具有复杂的内部结构。
    • 需要生成的对象内部属性本身相互依赖。

    建造者模式在创建复杂对象时非常有用,特别是当对象的构建过程涉及多个步骤或参数时。它可以提供更好的灵活性和可维护性,同时使得代码更加清晰可读。

    实现

    我们假设一个快餐店的商业案例,其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。

    我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。

    然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。

    建造者模式的 UML 图
    在这里插入图片描述

    java

    步骤 1
    创建一个表示食物条目和食物包装的接口。
    Item.java

    public interface Item {
       public String name();
       public Packing packing();
       public float price();    
    }
    Packing.java
    public interface Packing {
       public String pack();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    步骤 2
    创建实现 Packing 接口的实体类,方便进行不同的包装。
    Wrapper.java

    public class Wrapper implements Packing {
     
       @Override
       public String pack() {
          return "Wrapper";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Bottle.java

    public class Bottle implements Packing {
     
       @Override
       public String pack() {
          return "Bottle";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    步骤 3
    创建实现 Item 接口的抽象类,该类提供了默认的功能,实现汉堡抽象和冷饮抽象的包装类。

    Burger.java

    public abstract class Burger implements Item {
     
       @Override
       public Packing packing() {
          return new Wrapper();
       }
     
       @Override
       public abstract float price();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ColdDrink.java

    public abstract class ColdDrink implements Item {
     
        @Override
        public Packing packing() {
           return new Bottle();
        }
     
        @Override
        public abstract float price();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    步骤 4
    创建扩展了 Burger 和 ColdDrink 的实体类。

    VegBurger.java

    public class VegBurger extends Burger {
     
       @Override
       public float price() {
          return 25.0f;
       }
     
       @Override
       public String name() {
          return "Veg Burger";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ChickenBurger.java

    public class ChickenBurger extends Burger {
     
       @Override
       public float price() {
          return 50.5f;
       }
     
       @Override
       public String name() {
          return "Chicken Burger";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Coke.java

    
    public class Coke extends ColdDrink {
     
       @Override
       public float price() {
          return 30.0f;
       }
     
       @Override
       public String name() {
          return "Coke";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Pepsi.java

    
    public class Pepsi extends ColdDrink {
     
       @Override
       public float price() {
          return 35.0f;
       }
     
       @Override
       public String name() {
          return "Pepsi";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    步骤 5
    创建一个 Meal 类,带有上面定义的 Item 对象。

    Meal.java

    import java.util.ArrayList;
    import java.util.List;
     
    public class Meal {
       private List<Item> items = new ArrayList<Item>();    
     
       public void addItem(Item item){
          items.add(item);
       }
     
       public float getCost(){
          float cost = 0.0f;
          for (Item item : items) {
             cost += item.price();
          }        
          return cost;
       }
     
       public void showItems(){
          for (Item item : items) {
             System.out.print("Item : "+item.name());
             System.out.print(", Packing : "+item.packing().pack());
             System.out.println(", Price : "+item.price());
          }        
       }    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    步骤 6
    创建一个 MealBuilder 类,实际的 builder 类负责创建 Meal 对象。

    MealBuilder.java

    public class MealBuilder {
     
       public Meal prepareVegMeal (){
          Meal meal = new Meal();
          meal.addItem(new VegBurger());
          meal.addItem(new Coke());
          return meal;
       }   
     
       public Meal prepareNonVegMeal (){
          Meal meal = new Meal();
          meal.addItem(new ChickenBurger());
          meal.addItem(new Pepsi());
          return meal;
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    步骤 7
    BuiderPatternDemo 使用 MealBuilder 来演示建造者模式(Builder Pattern)。

    BuilderPatternDemo.java

    public class BuilderPatternDemo {
       public static void main(String[] args) {
          MealBuilder mealBuilder = new MealBuilder();
     
          Meal vegMeal = mealBuilder.prepareVegMeal();
          System.out.println("Veg Meal");
          vegMeal.showItems();
          System.out.println("Total Cost: " +vegMeal.getCost());
     
          Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
          System.out.println("\n\nNon-Veg Meal");
          nonVegMeal.showItems();
          System.out.println("Total Cost: " +nonVegMeal.getCost());
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    步骤 8
    执行程序,输出结果:

    
    Veg Meal
    Item : Veg Burger, Packing : Wrapper, Price : 25.0
    Item : Coke, Packing : Bottle, Price : 30.0
    Total Cost: 55.0
    
    
    Non-Veg Meal
    Item : Chicken Burger, Packing : Wrapper, Price : 50.5
    Item : Pepsi, Packing : Bottle, Price : 35.0
    Total Cost: 85.5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    rust

    因为rust的类支持组合式而不支持继承,在进行建造者构件时比java更加容易,rust的trait是支持继承的。

    // rsut trait不支持重名
    pub trait Item {
        fn name(&self)->String;   
        fn price(&self)->f32;   
        fn packing(&self)->String;
    }
    
    // 汉堡实体类
    struct ChickenBurger;
    impl Item for ChickenBurger {
        fn name(&self)->String {
            String::from("ChickenBurger")
        }
        fn price(&self)->f32 {
            35.0
        }
        fn packing(&self)->String {
            String::from("Wrappper")
        }
       
    }  
    struct VegBurger;
    impl Item for VegBurger {
        fn name(&self)->String {
            String::from("Pepsi")
        }
        fn price(&self)->f32 {
            35.0
        }
        fn packing(&self)->String {
            String::from("Wrappper")
        }
    }  
    
    // 饮料实体类
    struct Pepsi;
    
    impl Item for Pepsi {
        fn name(&self)->String {
            String::from("Pesi")
        }
        fn price(&self)->f32 {
            35.0
        }
        fn packing(&self)->String {
            String::from("Bottle")
        }
    }  
    struct Coke;
    
    impl Item for Coke {
        fn name(&self)->String {
            String::from("Coke")
        }
        fn price(&self)->f32 {
            35.0
        }
        fn packing(&self)->String {
            String::from("Bottle")
        }
    }  
    
    struct Meal {
        items:Vec<Box<dyn Item>>,
    }
    impl Meal {
        fn add_item<T>(&mut self,item:Box<dyn Item>) 
        {
            self.items.push(item)
        }
        fn get_cost(&self)->f32{
            // 普通函数实现
            // let mut sum:f32=0.0; 
            // for i in self.items.iter()  {
            //     let price = i.price();
            //     sum+=price;
            // }
            // sum
    
            // 函数sji
            self.items.iter().fold(0.0, |acc, x| acc + x.price())
        }
        fn  show_items(&self){
            for  i in self.items.iter() {
                println!("{}",i.name());
                println!("{}",i.packing());
                println!("{}",i.price());
            }
        }
    }
    // 添加建造者
    struct MealBuilder {}
    impl  MealBuilder {
        fn prepareVegMeal()->Meal{
            let mut meal=Meal{items:Vec::new()};
            meal.add_item::<Box<dyn Item>>(Box::new(VegBurger{}));
            meal.add_item::<Box<dyn Item>>(Box::new(Coke{}));
            meal
        }
        fn prepareNonVegMeal()->Meal{
            let mut meal=Meal{items:Vec::new()};
            meal.add_item::<Box<dyn Item>>(Box::new(ChickenBurger{}));
            meal.add_item::<Box<dyn Item>>(Box::new(Pepsi{}));
            meal
        }
    }
    fn main() {
        let m=MealBuilder::prepareVegMeal();
        println!(" Veg Meal");
        m.show_items();
        println!("Total Cost : {}",m.get_cost());
        let m=MealBuilder::prepareNonVegMeal();
        println!(" \n\nNon-Veg Meal");
        m.show_items();
        println!("Total Cost : {}",m.get_cost());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    rust代码仓库

    https://github.com/onenewcode/design.git
    本教程项目在bin文件夹下的builder.rs文件中

  • 相关阅读:
    前端URL拼接路径参数
    在英文电脑系统中,中文显示??????
    前端基础之CSS
    一篇永久摆脱Mysql时区错误问题,idea数据库可视化插件配置
    轻量且强大的 uni-app http 网络库 - 掘金
    AI的制作思维导图
    linux地址空间
    零基础学Java(1)初识Java程序
    微信小程序获取手机号(2023年10月 python版)[无需订阅]
    html和winform webBrowser控件交互并播放视频(包含转码)
  • 原文地址:https://blog.csdn.net/studycodeday/article/details/134308892