贵阳网站开发哪家便宜,网站建设域名申请,深圳推广系统,用网站做自我介绍自己个人主页#xff1a;金鳞踏雨 个人简介#xff1a;大家好#xff0c;我是金鳞#xff0c;一个初出茅庐的Java小白 目前状况#xff1a;22届普通本科毕业生#xff0c;几经波折了#xff0c;现在任职于一家国内大型知名日化公司#xff0c;从事Java开发工作 我的博客金鳞踏雨 个人简介大家好我是金鳞一个初出茅庐的Java小白 目前状况22届普通本科毕业生几经波折了现在任职于一家国内大型知名日化公司从事Java开发工作 我的博客这里是CSDN是我学习技术总结知识的地方。希望和各位大佬交流共同进步 ~ 比较简单但是很经常用
个人感悟 为什么会有这种设计模式往往是因为语言或者框架本身的缺陷而导致的。这个语言或者框架本身就不支持这种开发形式我们必须使用一种开发套路来解决这个问题 那为什么有一些设计模式我们在开发中很少见呢因为本身一些框架就提供了这些功能我们使用起来就很简单所以就没有那么重要了 一、原理
Builder 模式中文翻译为建造者模式或者构建者模式也有人叫它生成器模式。
实际上建造者模式的原理和代码实现非常简单掌握起来并不难难点在于应用场景。比如你有没有考虑过这样几个问题直接使用构造函数或者配合 set 方法就能创建对象为什么还需要建造者模式来创建呢建造者模式和工厂模式都可以创建对象那它们两个的区别在哪里呢话不多说我们直接来学习
角色
产品Product表示将要被构建的复杂对象。抽象创建者Abstract Builder定义构建产品的接口通常包含创建和获取产品的方法。具体创建者Concrete Builder实现抽象创建者定义的接口为产品的各个部分提供具体实现。指挥者Director负责调用具体创建者来构建产品的各个部分控制构建过程。
示例代码
我们考虑一个文档编辑器的例子。假设我们需要创建一个复杂的HTML文档它包含了标题、段落和图像等元素。
1、产品Product类 - HTML文档HtmlDocument
public class HtmlDocument {private String header ;private String body ;private String footer ;public void addHeader(String header) {this.header header;}public void addBody(String body) {this.body body;}public void addFooter(String footer) {this.footer footer;}Overridepublic String toString() {return htmlhead header /headbody body /bodyfooter footer /footer/html;}
}
2、抽象创建者Abstract Builder类 - HtmlDocumentBuilder
public abstract class HtmlDocumentBuilder {protected HtmlDocument document;public HtmlDocument getDocument() {return document;}public void createNewHtmlDocument() {document new HtmlDocument();}public abstract void buildHeader();public abstract void buildBody();public abstract void buildFooter();
}
3、具体创建者Concrete Builder类 - ArticleHtmlDocumentBuilder
// 实现抽象
public class ArticleHtmlDocumentBuilder extends HtmlDocumentBuilder {Overridepublic void buildHeader() {document.addHeader(Article Header);}Overridepublic void buildBody() {document.addBody(Article Body);}Overridepublic void buildFooter() {document.addFooter(Article Footer);}
}
4、指挥者Director类 - HtmlDirector
public class HtmlDirector {private HtmlDocumentBuilder builder;public HtmlDirector(HtmlDocumentBuilder builder) {this.builder builder;}public void constructDocument() {builder.createNewHtmlDocument();builder.buildHeader();builder.buildBody();builder.buildFooter();}public HtmlDocument getDocument() {return builder.getDocument();}
}
现在我们可以使用创建者设计模式来构建一个HTML文档对象
public class Main {public static void main(String[] args) {HtmlDocumentBuilder articleBuilder new ArticleHtmlDocumentBuilder();HtmlDirector director new HtmlDirector(articleBuilder);director.constructDocument();HtmlDocument document director.getDocument();System.out.println(Constructed HTML Document: \n document);}
}
在这个例子中我们创建了一个表示HTML文档的产品类HtmlDocument一个抽象的创建者类HtmlDocumentBuilder一个具体的创建者类ArticleHtmlDocumentBuilder和一个指挥者类HtmlDirector。当我们需要创建一个新的HTML文档对象时我们可以使用指挥者类来控制构建过程从而实现了将构建过程与表示过程的分离。
以上是一个创建者设计模式的标准写法事实我们在工作中往往不会写的这么复杂为了创建一个对象我们创建了很多辅助的类总觉得不太合适在这个案例中我们可以使用内部类来简化代码以下是修改后的代码甚至我们还移除了抽象层
public class HtmlDocument {private String header ;private String body ;private String footer ;public void addHeader(String header) {this.header header;}public void addBody(String body) {this.body body;}public void addFooter(String footer) {this.footer footer;}Overridepublic String toString() {return htmlhead header /headbody body /bodyfooter footer /footer/html;}public static class Builder {protected HtmlDocument document;public Builder() {document new HtmlDocument();}public Builder addHeader(String header) {document.addHeader(header);return this;}public Builder addBody(String body) {document.addBody(body);return this;}public Builder addFooter(String footer) {document.addFooter(footer);return this;}public HtmlDocument build() {return document;}}
}
创建一个HTML文档对象
public class Main {public static void main(String[] args) {HtmlDocument.Builder builder new HtmlDocument.Builder();HtmlDocument document builder.addHeader(This is the header).addBody(This is the body).addFooter(This is the footer).build();System.out.println(Constructed HTML Document: \n document);}
}
将创建者类Builder作为HTML文档类HtmlDocument的内部类。
这样做可以让代码更加紧凑。此外我们使用了一种流式接口使得在客户端代码中创建HTML文档对象更加简洁。
二、为什么需要建造者模式
1. 根据复杂的配置项进行定制化构建
首先我们先看一个mybaits中经典的案例这个案例中使用了装饰器和创建者设计模式
public class CacheBuilder {private final String id;private Class? extends Cache implementation;private final ListClass? extends Cache decorators;private Integer size;private Long clearInterval;private boolean readWrite;private Properties properties;private boolean blocking;public CacheBuilder(String id) {this.id id;this.decorators new ArrayList();}public CacheBuilder size(Integer size) {this.size size;return this;}public CacheBuilder clearInterval(Long clearInterval) {this.clearInterval clearInterval;return this;}public CacheBuilder blocking(boolean blocking) {this.blocking blocking;return this;}public CacheBuilder properties(Properties properties) {this.properties properties;return this;}// 构建public Cache build() {// 使用了装饰器模式添加 LruCachesetDefaultImplementations();Cache cache newBaseCacheInstance(implementation, id);setCacheProperties(cache);// 根据配置的装饰器对原有缓存进行增强如增加淘汰策略等if (PerpetualCache.class.equals(cache.getClass())) {// 遍历装饰器使其与目标对象绑定for (Class? extends Cache decorator : decorators) {cache newCacheDecoratorInstance(decorator, cache);setCacheProperties(cache);}cache setStandardDecorators(cache);} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {cache new LoggingCache(cache);}return cache;}
}
我们总结这个案例中的几个特点
1、参数有必填项id有很多可选填的内容通常必选项id通过构造器传入可选项通过方法传递。
2、真正的构建过程需要调用build()方法构建时需要根据已配置的成员变量的内容选择合适的装饰器对目标cache进行增强。
2. 实现不可变对象
创建者设计模式Builder Design Pattern可以实现不可变对象即一旦创建完成对象的状态就不能改变。这有助于保证对象的线程安全和数据完整性。
public final class ImmutablePerson {private final String name;private final int age;private final String address;private ImmutablePerson(Builder builder) {this.name builder.name;this.age builder.age;this.address builder.address;}public String getName() {return name;}public int getAge() {return age;}public String getAddress() {return address;}public static class Builder {private String name;private int age;private String address;public Builder() {}public Builder setName(String name) {this.name name;return this;}public Builder setAge(int age) {this.age age;return this;}public Builder setAddress(String address) {this.address address;return this;}public ImmutablePerson build() {return new ImmutablePerson(this);}}
}
在这个例子中ImmutablePerson 类具有三个属性name、age 和 address。这些属性都是 final 的一旦设置就不能更改。
ImmutablePerson 的构造函数是私有的外部无法直接创建该类的实例。要创建一个 ImmutablePerson 实例需要使用内部的 Builder 类。通过连续调用 Builder 类的方法我们可以为 ImmutablePerson 设置属性。最后通过调用 build() 方法我们创建一个具有指定属性的不可变 ImmutablePerson 实例。
实际上使用建造者模式创建对象还能避免对象存在无效状态。我再举个例子解释一下。比如我们定义了一个长方形类如果不使用建造者模式采用先创建后 set 的方式那就会导致在第一个 set 之后对象处于无效状态。
Rectangle r new Rectange(); // r is invalid
r.setWidth(2); // r is invalid
r.setHeight(3); // r is valid
为了避免这种无效状态的存在我们就需要使用构造函数一次性初始化好所有的成员变量。如果构造函数参数过多我们就需要考虑使用建造者模式先设置建造者的变量然后再一次性地创建对象让对象一直处于有效状态。
实际上如果我们并不是很关心对象是否有短暂的无效状态也不是太在意对象是否是可变的。比如对象只是用来映射数据库读出来的数据那我们直接暴露 set() 方法来设置类的成员变量值是完全没问题的。而且使用建造者模式来构建对象代码实际上是有点重复的。
小结
建造者模式是用来创建一种类型的复杂对象通过设置不同的可选参数“定制化”地创建不同的对象。
我们把类的必填属性放到构造函数中强制创建对象的时候就设置。
如果必填的属性有很多把这些必填属性都放到构造函数中设置那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置那校验这些必填属性是否已经填写的逻辑就无处安放了。如果类的属性之间有一定的依赖关系或者约束条件我们继续使用构造函数配合 set() 方法的设计思路那这些依赖关系或约束条件的校验逻辑就无处安放了。如果我们希望创建不可变对象也就是说对象在创建好之后就不能再修改内部的属性值要实现这个功能我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。
建造者与工厂模式有何区别
实际上其实不用非得把工厂模式、建造者模式分得那么清楚我们需要知道的是每个模式为什么这么设计能解决什么问题。只有了解了这些最本质的东西我们才能不生搬硬套才能灵活应用甚至可以混用各种模式创造出新的模式来解决特定场景的问题。
三、源码应用
创建者设计模式在源码中有广泛的使用常见
1、JDK中如StringBuilder和StringBuffer他们的实现不是完全按照标准的创建者设计模式设计但也是一样的思想
这两个类用于构建和修改字符串。它们实现了创建者模式允许客户端通过方法链来修改字符串。这些类在性能上优于 String 类因为它们允许在同一个对象上执行多次修改而不需要每次修改都创建一个新的对象。
StringBuilder builder new StringBuilder();
builder.append(Hello).append( ).append(World!);
String result builder.toString();
2、在SSM源码中很多类都使用创建者设计模式如Spring中的BeanDefinitionBuilder 类mybatis中的 SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder等因为实现都比较简单就不带着大家一个一个看了。
3、使用lombok简单的实现创建者设计模式
Lombok 是一个 Java 库它可以简化代码提高开发效率尤其是在实现模式和生成常用方法例如 getter、setter、equals、hashCode 和 toString时。
要使用 Lombok 简单地实现创建者设计模式可以使用 Builder 注解。自动生成创建者类和相关方法。
首先引入 Lombok 库。
dependenciesdependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.20/versionscopeprovided/scope/dependency
/dependencies
然后创建一个使用 Lombok 的创建者设计模式的类
Getter
ToString
Builder
public class Person {private String name;private int age;private String address;
}
在上面的示例中我们使用了 Builder 注解来自动生成创建者类和相关方法。此外我们还使用了 Getter 注解来自动生成 getter 方法以及 ToString 注解来自动生成 toString 方法。
自动生成的创建者类创建 Person 对象
Person person Person.builder().name(John Doe).age(30).address(123 Main St).build();
通过 Lombok可以轻松地实现创建者设计模式减少样板代码提高代码可读性。 文章到这里就结束了如果有什么疑问的地方可以在评论区指出~ 希望能和大佬们一起努力诸君顶峰相见 再次感谢各位小伙伴儿们的支持