【再探】设计模式—抽象工厂及建造者模式

 抽象工厂模式和建造者模式都属于创建型模式。两者都能创建对应的对象,而创建者模式更侧重于创建复杂对象,将对象的创建过程封装起来,让客户端不需要知道对象的内部细节。

1 抽象工厂模式

需求:

  1. 在使用工厂方法模式时,当增加新的产品类型时,需要创建对应的Factory类,这导致类的数量增加,让系统变得臃肿。
  2. 需要保证同风格下生成一致的组件。比如在写页面时,有dark及light模式,我们希望button、text等组件能在不同模式下保持一致的风格。抽象工厂模式介绍

1.1 抽象工厂模式介绍

为创建一组对象提供一组解决方案。与工厂模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,而是创建一族产品。

图 抽象工厂模式UML

public class Button {private final String color;public Button(String color) {this.color = color;}@Overridepublic String toString() {return getClass().getSimpleName() + "{" +"color='" + color + '\'' +'}';}
}public class Text {private final String color;public Text(String color) {this.color = color;}@Overridepublic String toString() {return getClass().getSimpleName() + "{" +"color='" + color + '\'' +'}';}
}public class DarkButton extends Button{public DarkButton(String color) {super(color);}
}public class DarkText extends Text{public DarkText(String color) {super(color);}
}public class LightButton extends Button{public LightButton(String color) {super(color);}
}public class LightText extends Text{public LightText(String color) {super(color);}
}
public interface ComponentsFactory {Button buildButton();Text buildText();}public class DarkComponentFactory implements ComponentsFactory{private final String color = "dark";@Overridepublic Button buildButton() {return new DarkButton(color);}@Overridepublic Text buildText() {return new DarkText(color);}}public class LightComponentFactory implements ComponentsFactory{private final String color = "light";@Overridepublic Button buildButton() {return new LightButton(color);}@Overridepublic Text buildText() {return new LightText(color);}
}

 

public class HtmlWeb {public static void main(String[] args) {ComponentsFactory componentsFactory = new DarkComponentFactory();System.out.println("-----------dark模式-----------");System.out.println(componentsFactory.buildButton());System.out.println(componentsFactory.buildText());System.out.println("-----------light模式-----------");componentsFactory = new LightComponentFactory();System.out.println(componentsFactory.buildButton());System.out.println(componentsFactory.buildText());}
}

1.1.1 优缺点

优点:

  1. 隔离类的实例化过程,使得客户端并不需要知道如何创建对象。
  2. 当不同产品族多个对象被设计成一起工作时,能保证客户端始终只使用同一个产品族的对象。
  3. 减少了工厂类的数量。
  4. 增加新的产品族方便,符合开闭原则。

缺点:

  1. 不符合单一职责原则,一个类创建了多个对象。
  2. 族群增加新的种类时,不符合开闭原则,需要修改全部的工厂类。

2 建造者模式

需求:

  1. 需要创建一个复杂的对象,隔离类的实例化过程,使得客户端不需要知道对象的内部细节。
  2. 创建对象时,对执行顺序有要求。

2.1 建造者模式介绍

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

图 构建模式UML

Director 为指挥者,用来控制Buider 的执行顺序,在实际开发中,这个角色经常会被省略,它的功能集成到Builder上;而Builder中的builderPart方法的返回值为它本身,这样就可以链式调用了。

public class JdbcConnector {private JdbcConnection connection;public void initConnection(URI uri) {connection = new JdbcConnection(uri);}public JdbcPreparedStatement getPreparedStatement(String query) {if (connection == null) throw new RuntimeException("连接器还未初始化");return connection.getPreparedStatement(query);}public static class JdbcConnection {public JdbcConnection(URI uri){System.out.println(uri);}public JdbcPreparedStatement getPreparedStatement(String query) {return new JdbcPreparedStatement(query);}}public static class JdbcPreparedStatement {String query;public JdbcPreparedStatement(String query) {this.query = query;}public String getResult() {return this.query;}}}public class JdbcConnectorBuilder {private String scheme;private String host;private String port;private String database;private String username;private String password;public JdbcConnectorBuilder setScheme(String scheme) {this.scheme = scheme;return this;}public JdbcConnectorBuilder setHost(String host) {this.host = host;return this;}public JdbcConnectorBuilder setPort(String port) {this.port = port;return this;}public JdbcConnectorBuilder setDatabase(String database) {this.database = database;return this;}public JdbcConnectorBuilder setUsername(String username) {this.username = username;return this;}public JdbcConnectorBuilder setPassword(String password) {this.password = password;return this;}/*** 产品*/private JdbcConnector jdbcConnector = null;public JdbcConnectorBuilder() {jdbcConnector = new JdbcConnector();}public JdbcConnector build() {StringBuilder sb = new StringBuilder("jdbc:");sb.append(scheme == null ? "mysql" : scheme).append("://");if (host == null) throw new RuntimeException("host不能为空");sb.append(host);sb.append(":").append(port == null ? "3306" : port);if (database == null) throw new RuntimeException("数据库不能为空");sb.append("/").append(database);try {URI uri = new URI(sb.toString());if (username == null || password == null) throw new RuntimeException("账号或密码错误");jdbcConnector.initConnection(uri);} catch (URISyntaxException e) {throw new RuntimeException("连接失败,连接信息有误");}return jdbcConnector;}}public class JdbcConnectionTest {public static void main(String[] args) {JdbcConnectorBuilder builder = new JdbcConnectorBuilder();builder.setScheme("mysql").setHost("localhost").setPort("3307").setDatabase("my-database").setUsername("root").setPassword("123456");JdbcConnector jdbcConnector = builder.build();JdbcConnector.JdbcPreparedStatement statement = jdbcConnector.getPreparedStatement("select * from student");System.out.println(statement.getResult());}
}

JDK 中的StringBuilder及Apache httpclient 的 URIBuilder 应用了建造者模式。

自定义StringBuilder

public class CustomStringBuilder {public static void main(String[] args) {CustomStringBuilder customStringBuilder = new CustomStringBuilder("hello customStringBuilder");for (int i =0; i < 100; i++) {customStringBuilder.append("---建造者模式---").append(i + "");}System.out.println(customStringBuilder);}char[] value;int count = 0;public CustomStringBuilder(int capacity) {value = new char[capacity];}public CustomStringBuilder(String str) {this(str.length() + 16);append(str);}CustomStringBuilder append(String str) {if (str == null) {throw new RuntimeException("字符串不能为空");}ensureCapacity(count + str.length());str.getChars(0,str.length(),value,count);count += str.length();return this;}private void ensureCapacity(int minCapacity) {if (minCapacity >= value.length) {value = Arrays.copyOf(value,value.length << 1);}}@Overridepublic String toString() {return new String(value,0,count);}
}

自定义URIBuilder

public class CustomURIBuilder {public static void main(String[] args) throws URISyntaxException {CustomURIBuilder customURIBuilder = new CustomURIBuilder();customURIBuilder.setHost("localhost").setPort("8080").setEncodedPath("/userinfo");customURIBuilder.appendQueryParam("username","hmf");customURIBuilder.appendQueryParam("status","1");customURIBuilder.appendQueryParam("createDate","2024/04/20");URI uri = customURIBuilder.build();System.out.println(uri);}private String scheme;private String host;private String port;private String encodedPath;private List<NameValuePair> queryParams;public CustomURIBuilder setScheme(String scheme) {this.scheme = scheme;return this;}public CustomURIBuilder setHost(String host) {this.host = host;return this;}public CustomURIBuilder setPort(String port) {this.port = port;return this;}public CustomURIBuilder setEncodedPath(String encodedPath) {this.encodedPath = encodedPath;return this;}public CustomURIBuilder appendQueryParam(String name,String value) {if (queryParams == null) queryParams = new ArrayList<>();queryParams.add(new NameValuePair(name,value));return this;}public URI build() throws URISyntaxException {return new URI(buildStr());}public String buildStr() {StringBuilder sb = new StringBuilder();if (this.scheme != null) sb.append(this.scheme).append("://");if (this.host == null) throw new RuntimeException("host不能为空");sb.append(this.host);if (this.port != null) sb.append(":").append(this.port);if (this.encodedPath != null) sb.append(this.encodedPath);if (this.queryParams != null) {for (int i = 0; i < this.queryParams.size(); i++) {sb.append(i == 0 ? "?" : "&").append(this.queryParams.get(i));}}return sb.toString();}private static class NameValuePair {String name;String value;public NameValuePair(String name, String value) {this.name = name;this.value = value;}@Overridepublic String toString() {if (this.value == null) return name;return name + "=" + value;}}}

2.1.1 优缺点

优点:

  1. 封装性好,将产品的内部表示与产品的生成过程分割开。客户端只需知道所需的产品类型,而不需要知道产品内部的具体结构和实现细节。
  2. 扩展性好,各个具体建造者相互独立,如果需要添加新的产品,只需创建对应的建造者即可,符合开闭原则。
  3. 便于构建发展对象,可以简化对象的创建过程,提高代码的可读性和可维护性。

缺点:

  1. 可维护性差,如果产品的内部发生变化,则对应的创建者可能需要修改的地方会比较多。
  2. 类的数量增加。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++入门基础(二)

目录 缺省参数缺省参数概念缺省参数分类全缺省参数半缺省参数声明与定义分离 缺省参数的应用 函数重载函数重载概念例子1 参数类型不同例子2 参数的个数不同例子3 参数的顺序不同 C支持函数重载的原理--名字修饰(name Mangling) 感谢各位大佬对我的支持,如果我的文章对你有用,欢…

Rust中的并发性:Sync 和 Send Traits

在并发的世界中&#xff0c;最常见的并发安全问题就是数据竞争&#xff0c;也就是两个线程同时对一个变量进行读写操作。但当你在 Safe Rust 中写出有数据竞争的代码时&#xff0c;编译器会直接拒绝编译。那么它是靠什么魔法做到的呢&#xff1f; 这就不得不谈 Send 和 Sync 这…

【MySQL精炼宝库】深度解析索引 | 事务

目录 一、索引 1.1 索引(index)概念&#xff1a; 1.2 索引的作用&#xff1a; 1.3 索引的缺点&#xff1a; 1.4 索引的使用场景&#xff1a; 1.5 索引的使用&#xff1a; 1.6 面试题:索引底层的数据结构&#xff08;核心内容&#xff09;&#xff1a; 1.7 索引列查询(主…

Stability AI 推出稳定音频 2.0:为创作者提供先进的 AI 生成音频

概述 Stability AI 的发布再次突破了创新的界限。这一尖端模型以其前身的成功为基础&#xff0c;引入了一系列突破性的功能&#xff0c;有望彻底改变艺术家和音乐家创建和操作音频内容的方式。 Stable Audio 2.0 代表了人工智能生成音频发展的一个重要里程碑&#xff0c;为质量…

【docker】Docker开启远程访问

将构建的镜像自动上传到服务器。 需要开放 Docker 的端口&#xff0c;让我们在本地能连接上服务器的 Docker&#xff0c;这样&#xff0c;才能上传构建的镜像给 Docker。 开启远程访问 首先在服务器打开 Docker 的服务文件 vim /usr/lib/systemd/system/docker.service修改…

Java项目:基于SSM框架实现的实践项目管理系统(ssm+B/S架构+源码+数据库+毕业论文+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的实践项目管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff…

使用Ollama和OpenWebUI在CPU上玩转Meta Llama3-8B

2024年4月18日&#xff0c;meta开源了Llama 3大模型[1]&#xff0c;虽然只有8B[2]和70B[3]两个版本&#xff0c;但Llama 3表现出来的强大能力还是让AI大模型界为之震撼了一番&#xff0c;本人亲测Llama3-70B版本的推理能力十分接近于OpenAI的GPT-4[4]&#xff0c;何况还有一个4…

罗德与施瓦茨RS SMR40 10MHZ-40GHZ信号分析仪

罗德与施瓦茨R&S SMR40 10MHZ-40GHZ信号分析仪 SMR40 被设计为具有脉冲调制功能的 CW 发生器。SMR40 具有 < 10 ms 2 ms /GHz 的极快频率切换时间和 0.1 Hz 的分辨率。SMR40 包含一个电子振荡器&#xff0c;该电路能够创建重复波形。 附加功能&#xff1a; 频率范围&a…

网页使用之如何返回json/xml

后端返回json数据给前端进行渲染的方式比较熟悉&#xff0c;至于返回html页面&#xff0c;返回xml的方式接触逐渐减少&#xff0c;来在项目中熟悉这一点。 返回文本数据 json姿势的返回实属最简单的方式&#xff0c;在SpringBoot应用中&#xff0c;有两种简单的方式 1.直接在…

【stomp 实战】spring websocket用户消息发送源码分析

这一节&#xff0c;我们学习用户消息是如何发送的。 消息的分类 spring websocket将消息分为两种&#xff0c;一种是给指定的用户发送&#xff08;用户消息&#xff09;&#xff0c;一种是广播消息&#xff0c;即给所有用户发送消息。那怎么区分这两种消息呢?那就是用前缀了…

Linux服务器安全基础 - 查看入侵痕迹

1. 常见系统日志 /var/log/cron 记录了系统定时任务相关的日志 /var/log/dmesg 记录了系统在开机时内核自检的信息&#xff0c;也可以使用dmesg命令直接查看内核自检信息 /var/log/secure:记录登录系统存取数据的文件;例如:pop3,ssh,telnet,ftp等都会记录在此. /var/log/btmp:记…

特斯拉与百度合作;字节正全力追赶AI业务;小红书内测自研大模型

特斯拉中国版 FSD 或与百度合作 根据彭博社的报道&#xff0c;特斯拉将通过于百度公司达成地图和导航协议&#xff0c;扫清在中国推出 FSD 功能的关键障碍。 此前&#xff0c;中国汽车工业协会、国家计算机网络应急技术处理协调中心发布《关于汽车数据处理 4 项安全要求检测情…