【设计模式】建造者模式
建造者模式的意图
建造者模式又被称呼为生成器模式,属于创建型模式。(使用多个简单对象一步一步构建成一个复杂的对象,这样像一间房子从地基到建造完成,这就是为啥被称呼为叫做建造者模式的原因吧!,而且一般来说房主是不需要了解建造过程和细节的,只需要知道所需房子的类型和内容即可,其他由建造者来补充实现,就可以获得一个复杂的房子)
意图将一个复杂对象的构建和它的表示分离,使得同样的创建过程可以创建不同的表示。
- 它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程进行分离,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者互相独立,增加新的建造者非常方便,无需修改已有代码,这样系统会具有良好的扩展性。
解决什么问题
(1)、方便用户创建复杂的对象(不需要知道实现过程)
(2)、代码复用性&封装性(将对象构建过程和细节进行封装&复用)
结构图
-
抽象建造者(builder):描述具体建造者的公共接口,一般用来定义建造细节的方法,并不涉及具体的对象部件的创建。
-
具体建造者(ConcreteBuilder):描述具体建造者,并实现抽象建造者公共接口。
-
指挥者(Director):调用具体建造者来创建复杂对象(产品)的各个部分,并按照一定顺序(流程)来建造复杂对象。
-
产品(Product):描述一个由一系列部件组成较为复杂的对象。
应用实例
(找的设计模式的一个作业)
Sunny软件公司欲开发一个视频播放软件,为了给用户使用提供方便,该播放软件提供多种界面显示模式,如完整模式、精简模式、记忆模式、网络模式等。在不同的显示模式下主界面的组成元素有所差异,如在完整模式下将显示菜单、播放列表、主窗口、控制条等,在精简模式下只显示主窗口和控制条,而在记忆模式下将显示主窗口、控制条、收藏列表等。尝试使用建造者模式设计该软件。
// 角色类:复杂产品,考虑到代码的可读性,真实情况下,有些成员属性的类型需要自定义
public class Element {
// Displays menus, playlists, main windows, control bars
private String displaysMenus;
private String playlists;
private String mainWindows;
private String controlBars;
private String favoritesList;
public Element() {
}
public Element(String displaysMenus, String playlists, String mainWindows, String controlBars, String favoritesList) {
this.displaysMenus = displaysMenus;
this.playlists = playlists;
this.mainWindows = mainWindows;
this.controlBars = controlBars;
this.favoritesList = favoritesList;
}
public String getDisplaysMenus() {
return displaysMenus;
}
public void setDisplaysMenus(String displaysMenus) {
displaysMenus = displaysMenus;
}
public String getPlaylists() {
return playlists;
}
public void setPlaylists(String playlists) {
this.playlists = playlists;
}
public String getMainWindows() {
return mainWindows;
}
public void setMainWindows(String mainWindows) {
this.mainWindows = mainWindows;
}
public String getControlBars() {
return controlBars;
}
public void setControlBars(String controlBars) {
this.controlBars = controlBars;
}
public String getFavoritesList() {
return favoritesList;
}
public void setFavoritesList(String favoritesList) {
this.favoritesList = favoritesList;
}
@Override
public String toString() {
return "Element{" +
"displaysMenus='" + displaysMenus + '\'' +
", playlists='" + playlists + '\'' +
", mainWindows='" + mainWindows + '\'' +
", controlBars='" + controlBars + '\'' +
", favoritesList='" + favoritesList + '\'' +
'}';
}
}
角色建造起:抽象建造者
/**
* 显示模式建造
*/
abstract class ElementBuilder {
protected Element element = new Element();
/**
*显示菜单
*/
public abstract void buildDisplaysMenus();
/**
* 播放列表
*/
public abstract void buildPlayLists();
/**
* 主窗口
*/
public abstract void buildMainWindows();
/**
* 控制条
*/
public abstract void buildControlBars();
/**
* 收藏列表
*/
public abstract void buildFavoritesList();
/**
* 创建显示模式
* @return 模式组成元素
*/
public Element createElement(){
return element;
}
}
具体建造者
具体建造者
/**
* 记忆模式建造者
* @author haoyang
*/
public class MemoryMode extends ElementBuilder{
@Override
public void buildDisplaysMenus() {
}
@Override
public void buildPlayLists() {
}
@Override
public void buildMainWindows() {
element.setMainWindows("主窗口");
}
@Override
public void buildControlBars() {
element.setControlBars("控制条");
}
@Override
public void buildFavoritesList() {
element.setFavoritesList("收藏列表");
}
@Override
public Element createElement() {
return super.createElement();
}
}
/**
* 完整模式建造者
* @author haoyang
*/
public class CompleteMode extends ElementBuilder{
@Override
public void buildDisplaysMenus() {
element.setDisplaysMenus("显示菜单");
}
@Override
public void buildPlayLists() {
element.setPlaylists("播放列表");
}
@Override
public void buildMainWindows() {
element.setMainWindows("主窗口");
}
@Override
public void buildControlBars() {
element.setControlBars("控制条");
}
@Override
public void buildFavoritesList() {
}
@Override
public Element createElement() {
return super.createElement();
}
}
/**
* 精简模式建造者
* @author haoyang
*/
public class LiteMode extends ElementBuilder{
@Override
public void buildDisplaysMenus() {
}
@Override
public void buildPlayLists() {
}
@Override
public void buildMainWindows() {
element.setMainWindows("主窗口");
}
@Override
public void buildControlBars() {
element.setControlBars("控制条");
}
@Override
public void buildFavoritesList() {
}
@Override
public Element createElement() {
return super.createElement();
}
}
指挥者,指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类
/**
* 指挥者,指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类
* @author haoyang
*/
public class VideoPlayback {
private final ElementBuilder builder;
public VideoPlayback(ElementBuilder builder) {
this.builder = builder;
}
public Element build(){
builder.buildDisplaysMenus();
builder.buildPlayLists();
builder.buildMainWindows();
builder.buildControlBars();
builder.buildFavoritesList();
return builder.createElement();
}
}
测试类
public class Main {
public static void main(String[] args) {
ElementBuilder builder1 = new MemoryMode();
ElementBuilder builder2 = new CompleteMode();
ElementBuilder builder3 = new LiteMode();
//记忆模式
VideoPlayback vp = new VideoPlayback(builder1);
//完整模式
VideoPlayback vp2 = new VideoPlayback(builder2);
//精简模式
VideoPlayback vp3 = new VideoPlayback(builder3);
System.out.println(vp2.build());
System.out.println(vp.build());
System.out.println(vp3.build());
}
}
优缺点
1、优点
(1)、每一个具体建造者都相对独立,而且和其他的具体建造者无关,因此可以很方便地替换具体建造者或者增加新地具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
(2)、增加新的具体建造者无需修改原有类库的代码,易于扩展,符合“开闭原则”。
(3)、将复杂的产品创建步骤分解在不同的方法中,使得创建过程更加清晰,更加方便使用程序来控制创建过程。
(4)、客户端不需要知道产品内部细节,可以将产品的建造和表示进行分离,实现解耦,相同的创建过程可以创建不同的产品对象。
2、缺点
(1)、创建的产品一般具有较多的共同点,组成部分相似,如果产品直接的差异性很大,例如很多组成部分都不相同,就不适合,限制了使用的范围
(2)、内部变化复杂的话,就需要定义很多具体建造者来实现变化,这会导致系统变得庞大,增加理解难度以及运行成本,难以维护
使用时需要注意什么?
- 了解完大概这些,其实和工厂模式很相似,但是有区别:建造者模式更加关注与零件装配的顺序,一般用来构建更加复杂的对象
- 在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,电子邮件包括发件人、收件人、主题、内容、附件等部件。
适用场景(看看菜鸟教程https://www.runoob.com/design-pattern/builder-pattern.html)
- 一般来说,使用建造者模式需要包含多个成员属性,而且属性直接相互依赖,需要指定其生成的顺序,具备共性
- 适用于一个具有较多的零件(属性)的产品(对象)的创建过程。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品