聊聊你不知道的建造者设计模式

2024-06-23 04:08

本文主要是介绍聊聊你不知道的建造者设计模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


距离上次写博客的距离也快一个月了,最近打算跟大家分享一下建造者模式,其实这个模式以前也介绍过,当时只是介绍它在android项目中广泛被应用于创建对象的链式调用,并没有深入的去说明其中的逻辑性,由于这次跟王大哥讨论建造者模式,我还是决定写一篇博客记录一下自己对建造者模式的理解,各位可以提出不同的观点,相互交流

  • 1:Builder 设计模式

    • 1.1:为什么要用建造者模式

    • 1.2:建造者模式的几个角色

    • 1.3:一款软件产品的建造过程

  • 2:变种 Builder 模式:优雅的对象构建方式

    • 2.1:android源码中的Builder 模式:AlertDialog的源码

    • 2.2:我对设计模式的理解

  • 3感悟,偏执到底对一个技术开发和管理者到底是有利还是有弊

1:Builder 设计模式

1.1为什么要用建造者模式

     建造者模式是一种很常见的设计模式,其实在我们android项目中基本上都使用它的变种的模式用于创建对象,这也是谷歌提倡的,暂且不说这个,单说builder顾名思义就是建造的意思,说起建造我们首先想到盖房子,第一步,打桩,第二步,修地基,第三步,砌砖等等,最后封顶,建造者模式跟盖房子本质是一样的的:即流程不变,但每个流程的具体实现是变化的,张二家地基要深一些,墙砌的厚一些,瓦用红色的,李四家由于靠着悬崖房子不能建的太厚,墙身偏薄,等等,一句话具体的流程怎么走不管,但流程不会变化,不会增加也不会减少,这个是非常重要的,我们熟悉的歪楼事件,就是由于先建立楼房后建立停车场,这就是典型的颠倒顺序造成的。
同样的KFC做出来的东西,不论是全国哪家店做出来就都一个味,因为KFC内部有很严格的规定,做巨无霸有做巨无霸的流程,必须严格遵守,这样做出来的东西当然一致了。KFC就是采用了建造者模式!!
说了这么多,那到底什么才是建造者模式呢,官方给出的解释是:
将一个复杂对象的构建和表示分离,同样的构建过程可以创建不同的表示。

如何理解这句话呢,构建和表示分离?何为构建?何为表示?
想弄清楚这些东西,先看下文。

1.2:建造者模式的几个角色

     先理清楚,建造者模式通常包括下面几个角色:

  1. builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建部分,并不涉及具体的对象部件的创建。

  2. ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。(1:完成产品对象的部分构建,2:返回产品实例)

  3. Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。(严格按照流程生产产品)

  4. Product:要创建的复杂对象

建造者模式优势:它将创建复杂对象的创建过程分离,无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。

网上经典的建造者模式的例子就是做汉堡
肯德基做汉堡的过程都是有严格的规范的,不管是麦香鸡腿堡还是新奥尔良烤鸡腿堡,他们的制作步骤都是有严格规定,做汉堡的人既不能多做一步,也不能少做一步。对于不同的汉堡来说,虽然每一步加的料所有不同,但做汉堡的步骤都是一样的。因为有了对做汉堡过程的严格控制,因而全国所有的肯德基店做出来的汉堡味道都是一样的。
我没做过汉堡,只会做软件,下面我以我做软件的视角来剖析一下建造者的设计思想。

1.3:一款软件产品的建造过程

下面我们来看一款软件产品的建造过程,
首先创建一个软件开发流程的接口,该接口一般声明两种方法,一种生产各个部分的方法,一种返回复杂产品。
一款软件的实现需要前期编写需求文档,画界面,处理业务逻辑三个部分。

/*** 复杂的产品,考虑到代码的可读性,这里只列举部分的成员属性* 且作为测试成员属性都是String,真实的情况下有些属性是需要自定义的。* Created by zew on 17/7/8.*/
public class Product {private String xuqiu;//需求private String ui;//界面private String luoji;//逻辑public String getXuqiu() {return xuqiu;}public void setXuqiu(String xuqiu) {this.xuqiu = xuqiu;}public String getUi() {return ui;}public void setUi(String ui) {this.ui = ui;}public String getLuoji() {return luoji;}public void setLuoji(String luoji) {this.luoji = luoji;}
}

这里我们抽象一个builder,它定义如何创建复杂对象的各个部件。

/*** 抽象建造者* Created by zew on 17/7/8.*/
public interface  Builder {void buildXuqiu();//文档设计void buildUi();//界面void buildLuoji();//业务逻辑Product getApp();//返回开发的产品
}

然后根据不同的软件我们可以创建不同的具体的创建者,譬如我这里的信用猫创建者用于创建信用猫,信用花创建者用于创建信用花,对于具体的建造者,有三个注意点1:具体完成接口builder来构建或者装配产品部件,2:定义明确所要完成的产品是什么东西,3:提供一个可以获取产品的接口

/*** 信用猫builder具体的实现* Created by zew on 17/7/8.*/
public class CreditCatBuilder implements Builder{Product p;public CreditCatBuilder() {p=new Product();}@Overridepublic void buildXuqiu() {p.setXuqiu("建造信用猫需求文档");}@Overridepublic void buildUi() {p.setUi("建造信用猫画UI");}@Overridepublic void buildLuoji() {p.setLuoji("建造信用猫写逻辑");}//暴露可以获取产品的方法@Overridepublic Product getApp() {return p;}
}
/*** 信用花builder具体的实现* Created by zew on 17/7/8.*/
public class CreditHuaBuilder implements Builder{Product p;public CreditHuaBuilder() {p=new Product();}@Overridepublic void buildXuqiu() {p.setXuqiu("建造信用花设计需求文档");}@Overridepublic void buildUi() {p.setUi("建造信用花画UI");}@Overridepublic void buildLuoji() {p.setLuoji("建造信用花写逻辑");}//暴露可以获取产品的方法@Overridepublic Product getApp() {return p;}
}

指挥者类,该类定一个construct()方法,该方法拥有一个抽象建造者作为参数,该方法内部实现了软件开发的具体流程。

/*** 指挥类,该类定义一个construct方法,该方法拥有一个抽象建造者类型的参数这样可以通过范型把不同的建造者模式都可以传入* Created by zew on 17/7/8.*/
public class AppDirector {//严格按照生产顺序生产产品//完成需求文档builder.buildXuqiu();//完成uibuilder.buildUi();//完成业务逻辑builder.buildLuoji();//返回产品return builder.getApp();}
}

功能测试

  AppDirector appDirector = new AppDirector();//传入信用猫builderProduct p = appDirector.construct(new CreditCatBuilder());xinyongmao.setText(p.getXuqiu()+"==="+p.getUi()+"==="+p.getLuoji());//传入信用花builderProduct p2 = appDirector.construct(new CreditHuaBuilder());xinyonghua.setText(p2.getXuqiu()+"==="+p2.getUi()+"==="+p2.getLuoji());

这里写图片描述

这么两款优秀的app就被生产出来了。

总结:在建造者模式中,只需要创建一个指挥者对象,指挥者类建造者面向接口编程,只需要传入具体的建造者实例类型,指挥者对象就会一步一步构建完成的产品(逐步调用具体的建造者的buildX()方法),相同的构造过程可以完成不同的产品。
在刚刚的app生产实例中,如果想要生产不同的app,只需要更换具体的建造者对象即可,原有的代码无需修改,完全符合“开闭原则”。

写到这大家肯定都暗自高兴原来这就是建造者模式,为自己学习到一技之长而高兴,其实我要说的建造者模式只是开始,下面我们看下android中对建造者的变种。

2变种 Builder 模式:优雅的对象构建方式

        这个链接是我当初写的一个博客,主要是跟大家分享一下,这种通过建造者模式可以优雅的创建对象,这个在java圣经Effective java中被热烈推荐的方式,而且在阅读过android源码的人都知道AlertDialog.builder就是使用这种灵活的方式,大家可以阅读。地址:http://note.youdao.com/share/?id=6060eb9b1063aa6663c13e3516b475b9&type=note

2.1:android源码中的Builder 模式:AlertDialog的源码

下面带着大家看AlertDialog的源码。

final AlertDialog.Builder builder = new AlertDialog.Builder(context);  builder.setCancelable(false);  builder.setIcon(R.drawable.icon);  builder.setTitle("Title");  builder.setView(textEntryView);  builder.setPositiveButton("确认",  new DialogInterface.OnClickListener() {  public void onClick(DialogInterface dialog, int whichButton) {  setTitle(edtInput.getText());  }  });  builder.setNegativeButton("取消",  new DialogInterface.OnClickListener() {  public void onClick(DialogInterface dialog, int whichButton) {  setTitle("");  }  });  builder.show();  }  

通过类名就知道这是一个builder模式,通过builder对象来组装Dialog的各个部分,如,title,message,button,等等,这个在我们信用猫项目中对dialog的二次封装也是沿袭类似的思想,下面看AlertDialog的源码:

由于代码太多,我还是截图说明

这里写图片描述
这里写图片描述
这里写图片描述

由图中可以看出builder类可以设置AlertDialog的title,message,icon,
并且这些参数都被保存在AlertController.AlertParams 的成员变量P参数中,在调用builder类的create方法创建dialog的时候这些被保存的P中的参数会引用到Alert对象中去
下面我们看看图中的P.apply(dialog.mAlert);做了什么。

  public void apply(AlertController dialog) {if (mCustomTitleView != null) {dialog.setCustomTitle(mCustomTitleView);} else {if (mTitle != null) {dialog.setTitle(mTitle);}if (mIcon != null) {dialog.setIcon(mIcon);}if (mIconId != 0) {dialog.setIcon(mIconId);}if (mIconAttrId != 0) {dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));}}if (mMessage != null) {dialog.setMessage(mMessage);}if (mPositiveButtonText != null) {dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,mPositiveButtonListener, null);}if (mNegativeButtonText != null) {dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,mNegativeButtonListener, null);}if (mNeutralButtonText != null) {dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,mNeutralButtonListener, null);}// For a list, the client can either supply an array of items or an// adapter or a cursorif ((mItems != null) || (mCursor != null) || (mAdapter != null)) {createListView(dialog);}if (mView != null) {if (mViewSpacingSpecified) {dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,mViewSpacingBottom);} else {dialog.setView(mView);}} else if (mViewLayoutResId != 0) {dialog.setView(mViewLayoutResId);}/*dialog.setCancelable(mCancelable);dialog.setOnCancelListener(mOnCancelListener);if (mOnKeyListener != null) {dialog.setOnKeyListener(mOnKeyListener);}*/}

在Apply方法中,只是将AlertParams的参数设置到AlertController中,例如将标题的message,title,icon等参数信息设置到内容视图上,我们获取到AlertDialog对象后通过show方法就可以显示对话框.

2.2:我对设计模式的理解

一点点进去最近去你会悄然发现,其实在AlertDialog的builder模式中并没有Director角色的出现,其实在很多场景中,android并没有完全的按照GOF在《设计模式:可服用面向对象软件的基础》一书中描述的经典模式实现来做,而是做了一些修改,这也是Effective java中提倡的一种创建对象的方式,也是我跟王大哥对builder模式的不同解读的很大一个区分点,android对builder模式做了一些修改,使得这个模式更加易用,这里的AlertDialog.builder同时扮演了上文提到的builder,CreditcatBuilder,AppDirector三个角色,简化了builder模式的设计。其实当模块比较稳定,不存在一些变化时没可以在经典的设计模式实现的基础上做一个精简,而不是照搬GOF上的经典的实现,更不要生搬硬套,使程序失去架构之美,真是由于这种灵活的运用设计模式,才让android源码很值得我们去学习。

3:感悟,偏执到底对一个技术开发和管理者到底是有利还是有弊

其实很多人都会这个词持有贬义,隐含着“较真”,“不懂变通”等感情色彩,但是对于做产品,它又显得是一个优点,我对偏执的态度是:我不觉得偏执是每一个技术人员的必须的能力,它是一个加分的能力,但不是一个必备的能力,而且具备这种能力的人一定要有配套的反省能力,我呢,由于性格上就具备这种能力,这对我尝试去做一些看起来很难完成任务的时候,肯定在性格上占了很大一块便宜,但是,从另一个角度来说,如果我是一名管理者,如果我选择的角度不是很明智,这对我个人和团队都会带来危害,总的来说就是如果你有反省能力和自我认知能力足够清醒,没有什么大的偏差的话,偏执对一个管理者是好事,对一个技术人,偏执向来都是利大于弊。。。

这篇关于聊聊你不知道的建造者设计模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086189

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)

文章目录 1、工厂模式概述1)特点:2)主要角色:3)工作流程:4)优点5)缺点6)适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中,有三个主要角色:2) 简单工厂模式的优点包括:3) 简单工厂模式也有一些限制和考虑因素:4) 简单工厂模式适用场景:5) 简单工厂UML类图:6) 代码示例: 3、工厂方法模式1) 在工厂方法模式中,有4个主要角色:2) 工厂方法模式的工作流程

C#设计模式(1)——单例模式(讲解非常清楚)

一、引言 最近在学设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考。首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类) 二、单例模式的介绍 说到单例模式,大家第一

漫谈设计模式 [12]:模板方法模式

引导性开场 菜鸟:老大,我最近在做一个项目,遇到了点麻烦。我们有很多相似的操作流程,但每个流程的细节又有些不同。我写了很多重复的代码,感觉很乱。你有啥好办法吗? 老鸟:嗯,听起来你遇到了典型的代码复用和维护问题。你有没有听说过“模板方法模式”? 菜鸟:模板方法模式?没听过。这是什么? 老鸟:简单来说,模板方法模式让你在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。这样,你可

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟:老鸟,我最近在做一个项目,感觉代码越来越复杂,我都快看不懂了。尤其是有好几个子系统,它们之间的调用关系让我头疼。 老鸟:复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你的代码结构? 菜鸟:设计模式?我听说过一些,但不太了解。你觉得我应该用哪个模式呢? 老鸟:听起来你的问题可能适合用**外观模式(Facade Pattern)**来解决。我们可以一起探讨一下。

设计模式大全和详解,含Python代码例子

若有不理解,可以问一下这几个免费的AI网站 https://ai-to.cn/chathttp://m6z.cn/6arKdNhttp://m6z.cn/6b1quhhttp://m6z.cn/6wVAQGhttp://m6z.cn/63vlPw 下面是设计模式的简要介绍和 Python 代码示例,涵盖主要的创建型、结构型和行为型模式。 一、创建型模式 1. 单例模式 (Singleton

聊聊说话的习惯

1 在日常生活中,每个人都有固定的说话习惯。心理学研究表明,通过一个人的说话习惯,也可以分析出他的性格特点。对于每一个人来讲,说话习惯已经融为他们生活中的一部分。在社交活动中,一些不良的说话习惯很可能会给他们带来麻烦。因此,了解说话习惯对心理活动的影响是十分有必要的。 2 具有顺畅的说话习惯的人,大多思路清晰、语速适中、用词准确并且声声人耳,是典型的顺畅型说话方式这种类型的人要么不说话,要么

漫谈设计模式 [6]:适配器模式

引导性开场 菜鸟:老鸟,我最近在项目中遇到一个问题,我们的系统需要集成一个新的第三方库,但这个库的接口和我们现有的代码完全不兼容。我该怎么办? 老鸟:这是个常见的问题,很多开发者都会遇到这种情况。你有没有听说过适配器模式? 菜鸟:适配器模式?没有,能详细说说吗? 老鸟:当然可以!这就是我们今天要讨论的主题。适配器模式是一个设计模式,可以帮助我们解决你现在遇到的问题。 渐进式介绍概念 老

2 观察者模式(设计模式笔记)

2 观察者模式(别名:发布-订阅) 概念 定义对象间的一种一对多的依赖关系,当一个对象状态发生变化时,所以依赖于它的对象都得到通知并被自动更新。 模式的结构与使用 角色 主题(Subject)观察者(Observer)具体主题(ConcreteSubject)具体观察者(ConcreteObserver) 结构 Subject依赖于Observer最重要!!! package

1 单例模式(设计模式笔记)

1 单例模式 概述:使得一个类的对象成为系统中的唯一实例。 具体实现: 构造函数私有化 限制实例的个数 懒汉式(时间换空间) public class Singleton2 {public static Singleton2 singleton2;private Singleton2(){}public static Singleton2 getInstance() throws I