好菜每回味道不同--建造者模式

news2024/11/19 22:37:33

1.1 炒菜没放盐

        中餐,老板需要每次炒菜,每次炒出来的味道都有可能不同。麦当劳、肯德基这些不过百年的洋快餐却能在有千年饮食文化的中国发展的那么好呢?是因为你不管何时何地在哪里吃味道都一样,而鱼香肉丝在我们中餐却可以吃出上完口味来。

        依赖倒转原则?抽象不应该依赖细节,细节应该依赖于抽象,由于我们要吃的菜都依赖于厨师这样的细节,所以我们就很被动。

        "好,那再想想,老麦老肯他们的产品,味道是由什么决定的?"
        "我知道,那是由他们的工作流程决定的,由于他们制定了非常规范的工作流程,原料放多少,加热几分钟,都有严格规定,估计放多少盐都是用克来计量的。而这个工作流程是在所有的门店都必须要遵照执行的,所以我们吃到的东西不管在哪在什么时候味道都一样。这里我们要吃的食物都依赖工作流程。不过工作流程好像还是细节呀。"
        "对,工作流程也是细节,我们去快餐店消费,我们用不用关心他们的工作流程?当然是不用,我们更关心的是是否好吃。你想如果老肯发现鸡翅烤得有些焦,他们会调整具体的工作流程中的烧烤时间,如果新加一种汉堡,做法都相同,只是配料不相同,工作流程是不变的,只是加了一种具体产品而已,这里工作流程怎么样?"
        "对,这里工作流程可以是一种抽象的流程,具体放什么配料、烤多长时间等细节依赖于这个抽象。"

1.2 建造小人一

建造小人,要求要有头、身体、两手、两脚就可以了

package code.chapter13.builder1;
import java.awt.Graphics;
import javax.swing.JFrame;

class Test extends JFrame {

    public Test() {
        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }

    public void paint(Graphics g) {

        //瘦小人
        g.drawOval(150, 120, 30, 30);   //头
        g.drawRect(160, 150, 10, 50);   //身体
        g.drawLine(160, 150, 140, 200); //左手
        g.drawLine(170, 150, 190, 200); //右手
        g.drawLine(160, 200, 145, 250); //左脚
        g.drawLine(170, 200, 185, 250); //右脚

        //胖小人
        g.drawOval(250, 120, 30, 30);   //头
        g.drawOval(245, 150, 40, 50);   //身体
        g.drawLine(250, 150, 230, 200); //左手
        g.drawLine(280, 150, 300, 200); //右手
        g.drawLine(260, 200, 245, 250); //左脚

        
        g.drawLine(270, 200, 285, 250); //右脚

    }

    public static void main(String[] args) {
        new Test().setVisible(true);
    }
}

这样的话,有可能少画了一条腿或者一条胳膊,就像厨师有可能忘记放盐。

1.3 建造小人二

建两个类,一个廋人的类,一个胖子的类,不管谁都可以调用它

package code.chapter13.builder2;
import java.awt.Graphics;
import javax.swing.JFrame;

class Test extends JFrame {

    public Test() {
        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }

    public void paint(Graphics g) {

        //初始化瘦小人建造者类
        PersonThinBuilder gThin = new PersonThinBuilder(g);
        gThin.build();//画瘦小人

        //初始化胖小人建造者类
        PersonFatBuilder gFat = new PersonFatBuilder(g);
        gFat.build();//画胖小人
    }

    public static void main(String[] args) {
        new Test().setVisible(true);
    }
}

//瘦小人建造者
class PersonThinBuilder {
    private Graphics g;

    public PersonThinBuilder(Graphics g){
        this.g=g;
    }

    public void build(){
        g.drawOval(150, 120, 30, 30);   //头
        g.drawRect(160, 150, 10, 50);   //身体
        g.drawLine(160, 150, 140, 200); //左手
        g.drawLine(170, 150, 190, 200); //右手
        g.drawLine(160, 200, 145, 250); //左脚
        g.drawLine(170, 200, 185, 250); //右脚
    }
}

//胖小人建造者
class PersonFatBuilder {
    private Graphics g;

    public PersonFatBuilder(Graphics g){
        this.g=g;
    }

    public void build(){
        g.drawOval(250, 120, 30, 30);   //头
        g.drawOval(245, 150, 40, 50);   //身体
        g.drawLine(250, 150, 230, 200); //左手
        g.drawLine(280, 150, 300, 200); //右手
        g.drawLine(260, 200, 245, 250); //左脚
        g.drawLine(270, 200, 285, 250); //右脚
    }
}







如果再增加一个高个子的小人,也有可能不小心,最好的办法是规定,凡是建造小人,都必须要有头和身体,以及两手两脚。

1.4 建造者模式

        如果你需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,'建造者模式(Builder)',又叫生成器模式。建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。

        建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。[DP]
        "那怎么用建造者模式呢?"
        "一步一步来,首先我们要画小人,都需要画什么?"
        "头、身体、左手、右手、左脚、右脚。"
        "对的,所以我们先定义一个抽象的建造人的类,来把这个过程给稳定住,不让任何人遗忘当中的任何一步。"

        "然后,我们需要建造一个瘦的小人,则让这个瘦子类去继承这个抽象类,那就必须去重写这些抽象方法了。否则编译器也不让你通过。"
        "当然,胖人或高个子其实都是用类似的代码去实现这个类就可以了。"
        "这样,我在客户端要调用时,还是需要知道头身手脚这些方法呀?没有解决问题。"小菜不解地问。
        "别急,我们还缺建造者模式中一个很重要的类,指挥者(Director),用它来控制建造过程,也用它来隔离用户与建造过程的关联。"
        "你看到没有,PersonDirector类的目的就是根据用户的选择来一步一步建造小人,而建造的过程在指挥者这里完成了,用户就不需要知道了,而且,由于这个过程每一步都是一定要做的,那就不会让少画了一只手,少画一条腿的问题出现了。"
        "代码结构图如下。"

package code.chapter13.builder3;
import java.awt.Graphics;
import javax.swing.JFrame;

class Test extends JFrame {

    public Test() {
        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }

    public void paint(Graphics g) {

        PersonBuilder gThin = new PersonThinBuilder(g);
        PersonDirector pdThin = new PersonDirector(gThin);
        pdThin.CreatePerson();

        PersonBuilder gFat = new PersonFatBuilder(g);
        PersonDirector pdFat = new PersonDirector(gFat);
        pdFat.CreatePerson();
        
    }

    public static void main(String[] args) {
        new Test().setVisible(true);
    }
}

//抽象的建造者类
abstract class PersonBuilder {
    protected Graphics g;

    public PersonBuilder(Graphics g){
        this.g = g;
    }

    public abstract void buildHead();       //头
    public abstract void buildBody();       //身体
    public abstract void buildArmLeft();    //左手
    public abstract void buildArmRight();   //右手
    public abstract void buildLegLeft();    //左脚
    public abstract void buildLegRight();   //右脚
}

//瘦小人建造者
class PersonThinBuilder extends PersonBuilder {
    
    public PersonThinBuilder(Graphics g){
        super(g);
    }

    public void buildHead(){
        g.drawOval(150, 120, 30, 30);   //头
    }
    public void buildBody(){
        g.drawRect(160, 150, 10, 50);   //身体
    }
    public void buildArmLeft(){
        g.drawLine(160, 150, 140, 200); //左手
    }
    public void buildArmRight(){
        g.drawLine(170, 150, 190, 200); //右手
    }
    public void buildLegLeft(){
        g.drawLine(160, 200, 145, 250); //左脚
    }
    public void buildLegRight(){
        g.drawLine(170, 200, 185, 250); //右脚 
    }
}

//胖小人建造者
class PersonFatBuilder extends PersonBuilder {
    public PersonFatBuilder(Graphics g){
        super(g);
    }

    public void buildHead(){
        g.drawOval(250, 120, 30, 30);   //头
    }
    public void buildBody(){
        g.drawOval(245, 150, 40, 50);   //身体
    }
    public void buildArmLeft(){
        g.drawLine(250, 150, 230, 200); //左手
    }
    public void buildArmRight(){
        g.drawLine(280, 150, 300, 200); //右手
    }
    public void buildLegLeft(){
        g.drawLine(260, 200, 245, 250); //左脚
    }
    public void buildLegRight(){
        g.drawLine(270, 200, 285, 250); //右脚
    }
}

//指挥者
class PersonDirector{

    private PersonBuilder pb;
    //初始化时指定需要建造什么样的小人
    public PersonDirector(PersonBuilder pb){
        this.pb=pb;
    }
               
    //根据用户的需要建造小人
    public void CreatePerson(){
        pb.buildHead();     //头
        pb.buildBody();     //身体
        pb.buildArmLeft();  //左手
        pb.buildArmRight(); //右手
        pb.buildLegLeft();  //左脚
        pb.buildLegRight(); //右脚
    }
}







        "哈,我明白了,那客户端的代码我来写吧。应该也不难实现了。"
        "试想一下,我如果需要增加一个高个子和矮个子的小人,我们应该怎么做?"
        "加两个类,一个高个子类和一个矮个子类,让它们都去继承PersonBuilder,然后客户端调用就可以了。但我有个问题,如果我需要细化一些,比如人的五官,手的上臂、前臂和手掌,大腿小腿这些,如何办呢?"
        "问得好,这就需要权衡,如果这些细节是每个具体的小人都需要构建的,那就应该要加进去,反之就没必要。其实建造者模式是逐步建造产品的,所以建造者的Builder类里的那些建造方法必须要足够普遍,以便为各种类型的具体建造者构造。"

1.5 建造者解析

建造者模式(Builder)结构图

        "现在你看这张图就不会感觉陌生了。来总结一下,Builder是什么?"
        "是一个建造小人各个部分的抽象类。"
        "概括地说,是为创建一个Product对象的各个部件指定的抽象接口。ConcreteBuilder是什么呢?"
        "具体的小人建造者,具体实现如何画出小人的头身手脚各个部分。"
        "对的,它是具体建造者,实现Builder接口,构造和装配各个部件。Product当然就是那些具体的小人,产品角色了,Director是什么?"
        "指挥者,用来根据用户的需求构建小人对象。"
        "嗯,它是构建一个使用Builder接口的对象。"
        "那都是什么时候需要使用建造者模式呢?"
        "它主要用于创建一些复杂的对象,这些对象内部子对象的建造顺序通常是稳定的,但每个子对象本身的构建通常面临着复杂的变化。"
        "哦,是不是建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。"
        "来来来,我们来试着把建造者模式的基本代码推演一下,以便有一个更宏观的认识。"

1.6 建造者模式基本代码

        Product类——产品类,由多个部件组成。

        Builder类——抽象建造者类,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。
        ConcreteBuilder1类——具体建造者类。
        ConcreteBuilder2类——具体建造者类。
        Director类——指挥者类。
        客户端代码,客户不需要知道具体的建造过程。

package code.chapter13.builder0;

import java.util.ArrayList;

public class Test {

    public static void main(String[] args){

        System.out.println("**********************************************");       
        System.out.println("《大话设计模式》代码样例");
        System.out.println();  

        Director director = new Director();
        Builder b1 = new ConcreteBuilder1();
        Builder b2 = new ConcreteBuilder2();

        //指挥者用ConcreteBuilder1的方法来建造产品
        director.construct(b1); //创建的是产品A和产品B
        Product p1 = b1.getResult();
        p1.show();
        
        //指挥者用ConcreteBuilder2的方法来建造产品
        director.construct(b2); //创建的是产品X和产品Y
        Product p2 = b2.getResult();
        p2.show();

        System.out.println();
        System.out.println("**********************************************");

    }
}

//产品类
class Product{
    ArrayList<String> parts = new ArrayList<String>();

    //添加新的产品部件
    public void add(String part){
        parts.add(part);
    }
    //列举所有产品部件
    public void show(){
        for(String part : parts){
            System.out.println(part);
        }
    }
}

//抽象的建造者类
abstract class Builder {
    public abstract void buildPartA();      //建造部件A
    public abstract void buildPartB();      //建造部件B
    public abstract Product getResult();    //得到产品
}



//具体建造者1
class ConcreteBuilder1 extends Builder {
    private Product product = new Product();

    public void buildPartA(){
        product.add("部件A");
    }
    public void buildPartB(){
        product.add("部件B");
    }
    public Product getResult(){
        return product;
    }
}

//具体建造者2
class ConcreteBuilder2 extends Builder {
    private Product product = new Product();
    public void buildPartA(){
        product.add("部件X");
    }
    public void buildPartB(){
        product.add("部件Y");
    }
    public Product getResult(){
        return product;
    }
}


//指挥者
class Director{
    public void construct(Builder builder){
        builder.buildPartA();
        builder.buildPartB();
    }
}







        "所以说,建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1570493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言数据结构专题--顺序表(1基础)

前言 我们在对C语言有一定的了解之后&#xff0c;我们就可以开始数据结构的学习了&#xff0c;数据结构多用指针、结构体、动态内存开辟等知识&#xff0c;若对这些知识还不太了解的朋友&#xff0c;就需要加深其理解了&#xff0c;那么废话不多说&#xff0c;我们正式开始本节…

【C++学习】哈希的应用—位图与布隆过滤器

目录 1.位图1.1位图的概念1.2位图的实现3.位图的应用 2.布隆过滤器2.1 布隆过滤器提出2.2布隆过滤器概念2.3如何选择哈希函数个数和布隆过滤器长度2.4布隆过滤器的实现2.4.1布隆过滤器插入操作2.4.2布隆过滤器查找操作2.4.3 布隆过滤器删除 2.5 布隆过滤器优点2.6布隆过滤器缺陷…

小程序实现微信 【我的】界面

小程序实现仿微信 【我的】界面 一、简介 小程序实现仿微信 【我的】界面 采用 uni-app 实现&#xff0c;可以适用微信小程序、其他各种小程序以及 APP、Web等多个平台 具体实现步骤如下&#xff1a; 下载开发者工具 HbuilderX进入 【Dcloud 插件市场】 搜索 【小程序实现…

HTML基础知识详解(上)(如何想知道html的全部基础知识点,那么只看这一篇就足够了!)

前言&#xff1a;在学习前端基础时&#xff0c;必不可少的就是三大件&#xff08;html、css、javascript &#xff09;&#xff0c;而HTML&#xff08;超文本标记语言——HyperText Markup Language&#xff09;是构成 Web 世界的一砖一瓦&#xff0c;它定义了网页内容的含义和…

SwiftUI 中无法对添加模糊(blur)效果视图截图的初步解决

概览 在 万物皆可截图:SwiftUI 中任意视图(包括List和ScrollView)截图的通用实现 这篇博文里,我们讨论了在 SwiftUI 中对任意视图截图的一般方法。 不过,经码友反应这些方法对添加模糊(blur)效果的视图好像不太灵了。这里,就让我们看看一些可能的应变(Workaround)之…

Vue3:组件间通信-各种通信方式的用法总结

Vue3组件通信和Vue2的区别&#xff1a; 移出事件总线&#xff0c;使用mitt代替。vuex换成了pinia。把.sync优化到了v-model里面了。把$listeners所有的东西&#xff0c;合并到$attrs中了。$children被砍掉了。

用顺序表实现通讯录

前言 这次的通讯录是基于上一篇的动态顺序表的基础上实现的&#xff0c;如果对动态顺序表不熟悉&#xff0c;可以打开这个链接阅读http://t.csdnimg.cn/9zJ5g&#xff0c;这里我们会调用动态顺序表的函数。 如果想看静态顺序表实现通讯录&#xff0c;可以打开这个链接阅读http:…

【Canvas与艺术】绘制蓝色波纹铜质Best Product Guaranteed徽章

【关键点】 使用贝塞尔二次曲线生成环状波纹轮廓。 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>蓝色波纹铜质…

离线数仓(十)【ADS 层开发】

前言 剩下的 ADS 层主要就是写 SQL 了&#xff0c;就像我们之前练习的 HQL 题一样&#xff0c;不同的是这里的数据从哪张表读取&#xff08;DWD 还是 ADS 甚至个别表需要从 DIM 层读取&#xff09;需要我们自己来分析。 ADS 的建表语句和 MySQL 是对应的&#xff0c;我们到时候…

创意绘图小程序:绘画与实用功能的完美融合

创意绘图小程序&#xff1a;绘画与实用功能的完美融合 在数字化时代&#xff0c;创意绘图小程序以其便捷性、互动性和创新性&#xff0c;成为了人们表达自我、释放创意的新平台。本文将介绍一款集白板画、黑板画功能于一身&#xff0c;同时融合画笔调整、画布清空、橡皮擦清除…

专有钉钉微应用埋点以及本地调试埋点总结

最近在对接浙政钉&#xff0c;稳定性监控、通用采集 SDK、基础埋点、基础埋点&#xff0c;每次发布上去&#xff0c;工作人员那边反馈抓取不到信息 稳定性监控代码、通用采集 SDK index.html <!-- 流量稳定监控 S 关于埋点上线打开--><script src"https://wpk-…

在project模式下使用Implementation Runs窗口

要在“Implementation Runs”窗口中启动active implementation run&#xff0c;请执行以下任一操作&#xff1a; • 在Flow Navigator中选择“Run Implementation”。 • 在主菜单中选择“Flow > Run Implementation”。 • 从工具栏菜单中选择“Run Implementation”。 • …

达梦DMHS-Manager工具日常操作

目录 1、前言 2、同步服务管理 2.1、DMHS Agent节点管理 2.2、DMHS实例节点管理 2.3、DMHS模块节点管理 3、监控及告警 3.1、主机资源监控 3.2、同步链路监控 3.3、告警配置 4、系统管理 4.1、用户管理 4.2、角色管理 4.3、系统配置 4.4、审计信息 5、联机帮助 …

《手把手教你》系列技巧篇(七十一)-java+ selenium自动化测试-自定义类解决元素同步问题(详解教程)

1.简介 前面宏哥介绍了几种关于时间等待的方法&#xff0c;也提到了&#xff0c;在实际自动化测试脚本开发过程&#xff0c;百分之90的报错是和元素因为时间不同步而发生报错。本文介绍如何新建一个自定义的类库来解决这个元素同步问题。这样&#xff0c;我们在写脚本的时候&a…

spark高手必备

Spark 官网 https://spark.apache.org/ spark官方问题交流 Stack Overflow Newest apache-spark Questions - Stack Overflow 其它参考文档 Distributed Systems Architecture | brought to you by Alexey Grishchenko Shuffle原理 Spark Architecture: Shuffle | Distri…

C语言动态内存空间分配

1. 前言 在讲内存分配前&#xff0c;咱来聊一下为什么会有内存分配这个概念呢&#xff0c;大家都知道C语言当中是有着许多的数据类型&#xff0c;使用这些数据类型就会在内存上开辟其相对应的空间&#xff0c;那既然会开辟相应的空间&#xff0c;为什么还会有内存分配呢&#x…

函数式编程(一)

函数式编程总体介绍 函数式编程(functional programming)其实是个很古老的概念&#xff0c;诞生距今快60年啦&#xff01; 最古老的函数式编程语言Lisp 新出现的函数式编程语言&#xff1a;比如Erlang、Scala、clojure等 热门语言&#xff1a;Python、java、JavaScript、C等…

Scala第十九章节(Actor的相关概述、Actor发送和接收消息以及WordCount案例)

Scala第十九章节 章节目标 了解Actor的相关概述掌握Actor发送和接收消息掌握WordCount案例 1. Actor介绍 Scala中的Actor并发编程模型可以用来开发比Java线程效率更高的并发程序。我们学习Scala Actor的目的主要是为后续学习Akka做准备。 1.1 Java并发编程的问题 在Java并…

【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案

【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天寸铁…

java(7)之跳转语句

1、break跳转语句 说到break其实也不是跳转&#xff0c;它更像是一个终结语句&#xff0c;常用于在循环语句需要停止出现例如 while&#xff08;&#xff09;{ if&#xff08;&#xff09;{ break&#xff1b; }} 这样的形式或者 switch&#xff08;&#xff09;{ case…