草庐IT

设计模式之(6)——建造者模式

一只烤鸭朝北走 2023-03-28 原文

  定义:建造者模式也称为生成器模式,将一个个简单对象一步步构造成一个复杂的对象,将复杂对象的构建和它的表示分离,使得同样的构建过程有不同的表示;

  主要解决:系统中复杂对象的创建过程,通常由各个部分的子对象采用一定的算法构成;由于需求的变化 ,这个复杂对象的各个部分通常面临着剧烈的变化,但是将他们组合在一起的算法却相对稳定;

  何时使用:一些基本部件不变,而其组合经常变化的时候;

  如何解决:将变与不变相分离;

   模式结构(PS:本图是从网上找过来的):

  

  模式角色分析:

    1、产品类:是一个较为复杂的对象,这个对象的创建过程较为复杂,实际编程中可以由一个抽象类和它的不同实现组成,也可以由抽象类与他们的实现组成;

    2、抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交给它的子类来实现,这样更容易扩展,同时也符合面向接口编程的出发点,一般包含两个抽象方法,一个用来建造产品,一个用来返回产品;

    3、建造者:实现抽象类所有未实现的方法,组件产品,返回组装好的产品;

    4、指挥类:负责调用适当的建造者来组建产品,指挥类一般不与产品类发生依赖关系,与指挥类直接交互的是建造者类,一般来说指挥类被用来封装程序中易变的部分;

  应用场景:

  1、创建复杂对象的算法独立于组成对象的部件;

  2、肯德基的汉堡、可乐、薯条、炸鸡等是不变的,而其组合是经常变化的,将不同的产品组合在一起,生成出来所谓的“套餐”;

  3、jdk中的StringBuilder类;

  4、同一个创建过程需要有不同的内部属性的产品对象,例如建造房子,利用沙子、水泥、钢筋既可以建造别墅也可以建造普通楼房;

  优点:

  1、客户端不必知道产品组成的细节,将产品本身与产品的创建过程,使得相同的创建过程可以创建不同的产品对象;

  2、每个具体建造者都独立,因此可以方便地更换、或者增加具体的建造者,用户使用不同的具体建造者可以得到不同的产品对象;

  3、可以更精细地控制产品的创建过程,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰;

  4、增加新的具体的建造者不需要修改原来类库的代码,指挥类针对抽象建造者类编程,系统方便扩展,符合“开闭原则”;

  缺点:

  1、建造者过多时,会产生很多类,难以维护;

  2、建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,若产品之间的差异性很大,则不适合使用该模式,使用范围受限;

  工厂模式和建造者模式联系和区别:

  工厂模式重点关注如何获取实例对象,而建造者模式重点关注如何建造实例对象;建造者模式和工厂模式从总体上看仅仅是多了一个“指挥类”的角色,如果将“指挥类”看做是最终调用的客户端,那么剩余部分就可以看做是一个简单的工厂模式了,工厂模式是将实例对象的建造过程封装在工厂中了,工厂直接返回实例对象给调用者,而建造者模式是将实例对象的建造过程封装在了具体的建造者类中,由“指挥类”调用,返回对象给客户端调用;

  UML类图:

  

  示例代码:

package cn.com.pep.model.builder.builder2;
/**
 * 
 * @Title: Builder  
 * @Description:  抽象建造者
 * @author wwh 
 * @date 2022-9-1 9:56:08
 */
public abstract class Builder {
    
    /**
     * 
     * @Title: builderPartA 
     * @Description:
     */
    public abstract void builderPartA();
    
    /**
     * 
     * @Title: builderPartB 
     * @Description:
     */
    public abstract void builderPartB();
    
    /**
     * 
     * @Title: getProduct 
     * @Description:  
     * @return
     */
    public abstract Product getProduct();
}

 

package cn.com.pep.model.builder.builder2;
/**
 * 
 * @Title: ConcreteBuilderA  
 * @Description:  具体建造者A
 * @author wwh 
 * @date 2022-9-1 10:00:40
 */
public class ConcreteBuilderA extends Builder{
    
    private Product product = new Product();

    @Override
    public void builderPartA() {
        product.addPart("VegetableBurger");
    }

    @Override
    public void builderPartB() {
        product.addPart("Cocacola");
    }

    @Override
    public Product getProduct() {
        return product;
    }

    
}
package cn.com.pep.model.builder.builder2;
/**
 * 
 * @Title: ConcreteBuilderB  
 * @Description:  具体建造者B
 * @author wwh 
 * @date 2022-9-1 10:04:48
 */
public class ConcreteBuilderB extends Builder{
    
    private Product product = new Product();

    @Override
    public void builderPartA() {
        // TODO Auto-generated method stub
        product.addPart("ChickenBurger");
    }

    @Override
    public void builderPartB() {
        // TODO Auto-generated method stub
        product.addPart("Pepsi");
    }

    @Override
    public Product getProduct() {
        // TODO Auto-generated method stub
        return product;
    }

}
package cn.com.pep.model.builder.builder2;

/**
 * 
 * @Title: Product  
 * @Description:  
 * @author wwh 
 * @date 2022-9-1 9:50:03
 */

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
 * 
 * @Title: Product  
 * @Description:  产品类
 * @author wwh 
 * @date 2022-9-1 9:55:50
 */
public class Product {

    List<String> parts = new ArrayList<>();

    /**
     * 
     * @Title: addPart
     * @Description: 添加产品部件
     * @param part
     */
    public void addPart(String part) {
        parts.add(part);
    }

    /**
     * 
     * @Title: show
     * @Description:显示产品细节
     */
    public void show() {
        Iterator<String> it = parts.iterator();
        while (it.hasNext()) {
            String string = (String) it.next();
            System.err.println(string);
        }
    }

}
package cn.com.pep.model.builder.builder2;
/**
 * 
 * @Title: Director  
 * @Description:  指挥者类
 * @author wwh 
 * @date 2022-9-1 10:12:05
 */
public class Director {
    
    /**
     * 
     * @Title: creatProduct 
     * @Description:  
     * @param builder
     */
    public void creatProduct(Builder builder) {
        builder.builderPartA();
        builder.builderPartB();
    }
}
package cn.com.pep.model.builder.builder2;
/**
 * 
 * @Title: BuilderPatternDemo  
 * @Description:  测试类
 * @author wwh 
 * @date 2022-9-1 10:13:51
 */
public class BuilderPatternDemo {
    
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilderA();
        Director director = new Director();
        director.creatProduct(builder);
        Product p = builder.getProduct();
        p.show();
        
        builder = new ConcreteBuilderB();
        director.creatProduct(builder);
        p = builder.getProduct();
        p.show();
        
    }
}

有关设计模式之(6)——建造者模式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  4. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  7. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  8. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

  9. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  10. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

随机推荐