首页 资讯频道 互联频道 智能频道 网络 数据频道 安全频道 服务器频道 存储频道

建造者设计模式有哪些?详解建造者模式相关内容

2020-10-21 08:15:18 来源 : 今日头条

前言

23种设计模式速记

单例(singleton)模式

工厂方法(factory method)模式

抽象工厂(abstract factory)模式

23种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习建造者模式相关内容。

模式定义

将一个复杂对象的创建与他的表示分离,使得同样的构建过程可以创建不同的表示。

用户只需要给出指定复杂对象的类型和内容;

建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)

解决的问题

降低创建复杂对象的复杂度

隔离了创建对象的构建过程 & 表示

从而:

方便用户创建复杂的对象(不需要知道实现过程)

代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)

模式组成

指挥者(Director)直接和客户(Client)进行需求沟通;

沟通后指挥者将客户创建产品的需求划分为各个部件的建造请求(Builder);

将各个部件的建造请求委派到具体的建造者(ConcreteBuilder);

各个具体建造者负责进行产品部件的构建;

最终构建成具体产品(Product)。

实例说明

实例概况

背景 小张希望去中关村买一台组装的台式主机

过程

中关村老板(Diretor)和小张(Client)进行需求沟通(买来打游戏?学习?看片?)

了解需求后,电脑城老板将小张需要的主机划分为各个部件(Builder)的建造请求(CPU、主板......)

指挥装机人员(ConcreteBuilder)去构建组件;

将组件组装起来成小张需要的电脑(Product)

使用步骤

步骤1:定义具体产品类(Product):电脑

classComputer{

//电脑组件的集合

privateListparts=newArrayList();

//用于将组件组装到电脑里

publicvoidAdd(Stringpart){

parts.add(part);

}

publicvoidShow(){

for(inti=0;i

System.out.println("组件"+parts.get(i)+"装好了");

}

System.out.println("电脑组装完成,请验收");

}

}

步骤2:定义组装的过程(Builder):组装电脑的过程

abstractclassBuilder{

//第一步:装CPU

//声明为抽象方法,具体由子类实现

publicabstractvoidBuildCPU();

//第二步:装主板

//声明为抽象方法,具体由子类实现

publicabstractvoidBuildMainboard();

//第三步:装硬盘

//声明为抽象方法,具体由子类实现

publicabstractvoidBuildHD();

//返回产品的方法:获得组装好的电脑

publicabstractComputerGetComputer();

}

步骤3:中关村老板委派任务给装机人员(Director)

classDirector{

//指挥装机人员组装电脑

publicvoidConstruct(Builderbuilder){

builder.BuildCPU();

builder.BuildMainboard();

builder.BuildHD();

}

}

步骤4:创建具体的建造者(ConcreteBuilder):装机人员

classConcreteBuilderextendsBuilder{

//创建产品实例

Computercomputer=newComputer();

//组装产品

@Override

publicvoidBuildCPU(){

computer.Add("组装CPU");

}

@Override

publicvoidBuildMainboard(){

computer.Add("组装主板");

}

@Override

publicvoidBuildHD(){

computer.Add("组装主板");

}

//返回组装成功的电脑

@Override

publicComputerGetComputer(){

returncomputer;

}

}

步骤5:客户端调用-小张到电脑城找老板买电脑

publicclassBuilderPattern{

publicstaticvoidmain(String[]args){

//步骤5:客户端调用-小张到电脑城找老板买电脑

//逛了很久终于发现一家合适的电脑店

//找到该店的老板和装机人员

Directordirector=newDirector();

Builderbuilder=newConcreteBuilder();

//沟通需求后,老板叫装机人员去装电脑

director.Construct(builder);

//装完后,组装人员搬来组装好的电脑

Computercomputer=builder.GetComputer();

//组装人员展示电脑给小张看

computer.Show();

}

}

输出结果

组件CPU装好了

组件主板装好了

组件硬盘装好了

电脑组装完成,请验收

优点

良好的封装性:建造者对客户端屏蔽了产品内部组成的细节,客户端不用关心每一个具体的产品内部是如何实现的。

符合开闭原则

便于控制细节风险:由于建造者是相互独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。

每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。

缺点

建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

应用场景

需要生成的对象具有复杂的内部结构

需要生成的对象内部属性本身相互依赖

与不可变对象配合使用

与工厂方法模式的区别

建造者模式最主要的功能是基本方法的调用顺序安排,基本方法已经实现,我们可以理解为零件的装配,顺序不同产生的对象也不同;而工厂方法的注重点是创建,创建零件是其主要职责,不关心组装顺序。

源码中的应用

#jdk

java.lang.StringBuilder

#Spring源码

org.springframework.web.servlet.mvc.method.RequestMappingInfo

org.springframework.beans.factory.support.BeanDefinitionBuilder

......

StringBuilder源码分析

在jdk中StringBuilder类的实现中,采用建造者模式的思想。具体分析如下:

StringBuilder类继承自AbstractStringBuilder,而AbstractStringBuilder实现了Appendable接口。AbstractStringBuilder虽然是一个抽象类,但是它实现了Appendable接口中的各个append()方法,因此在这里Appendable接口是一个抽象建造者,而AbstractStringBuilder是建造者,只是不能实例化。对于StringBuilder类,它既充当了指挥者角色,同时充当了具体的建造者,建造方法的具体实现是由AbstractStringBuilder完成,StringBuilder继承了AbstractStringBuilder。

Appendable接口

publicinterfaceAppendable{

Appendableappend(CharSequencecsq)throwsIOException;

Appendableappend(CharSequencecsq,intstart,intend)throwsIOException;

Appendableappend(charc)throwsIOException;

}

AbstractStringBuilder类

abstractclassAbstractStringBuilderimplementsAppendable,CharSequence{

char[]value;//Thevalueisusedforcharacterstorage.

intcount;//Thecountisthenumberofcharactersused.

AbstractStringBuilder(){}

AbstractStringBuilder(intcapacity){

value=newchar[capacity];

}

publicAbstractStringBuilderappend(Stringstr){

if(str==null)

returnappendNull();

intlen=str.length();

ensureCapacityInternal(count+len);

str.getChars(0,len,value,count);

count+=len;

returnthis;

}

privateAbstractStringBuilderappendNull(){

intc=count;

ensureCapacityInternal(c+4);

finalchar[]value=this.value;

value[c++]='n';

value[c++]='u';

value[c++]='l';

value[c++]='l';

count=c;

returnthis;

}

privatevoidensureCapacityInternal(intminimumCapacity){

//overflow-consciouscode

if(minimumCapacity-value.length>0){

value=Arrays.copyOf(value,

newCapacity(minimumCapacity));

}

}

publicvoidgetChars(intsrcBegin,intsrcEnd,chardst[],intdstBegin){

if(srcBegin<0){

thrownewStringIndexOutOfBoundsException(srcBegin);

}

if(srcEnd>value.length){

thrownewStringIndexOutOfBoundsException(srcEnd);

}

if(srcBegin>srcEnd){

thrownewStringIndexOutOfBoundsException(srcEnd-srcBegin);

}

System.arraycopy(value,srcBegin,dst,dstBegin,srcEnd-srcBegin);

}

//此次省略......

}

StringBuilder类:

publicfinalclassStringBuilderextendsAbstractStringBuilderimplementsjava.io.Serializable,CharSequence{

//虽说是重写,但还是调用的AbstractStringBuilder方法

@Override

publicStringBuilderappend(Stringstr){

super.append(str);

returnthis;

}

}

相关文章

最近更新