【设计模式】学习笔记(二)——创建型设计模式
目录
- 一、创建型设计模式介绍
- 二、工厂模式
- 三、单例模式
- 四、原型模式
- 五、创建者模式
一、创建型设计模式介绍
概念:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
分类:
- 工厂模式(Factory Pattern)
- 单例模式(Singleton Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
二、工厂模式
概念:它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
而三种不同的工厂模式也描述不同的应用场景
2.1 简单工厂模式
概念:定义一个工厂类,根据不同的参数,创建并返回不同的类。其中这些类具有一个公共的父类或是一个接口。简单工厂模式不属于GoF四人组提出的23种设计模式,它是最简单的工厂模式。非常适合我们从此处学习设计模式。
优点:解耦,代码更容易维护
缺点:违反了开闭原则
结构:
-
抽象产品:其作为具体产品的父类,负责定义产品的公共接口
-
具体产品:有多个,都是继承与抽象产品类,工厂就是创建该类对象
-
具体工厂:内部有是个精通的方法,根据参数选择创建的对象
适用场景:
- 客户如果只知道传入工厂类的参数,对于如何创建对象的逻辑不关心时;
- 当工厂类负责创建的对象(具体产品)比较少时。
代码示例
假设现在我们是一家快餐工厂,专门生产快餐
/**
* 抽象产品类:快餐
*/
abstract class FastFood {
abstract void show();
}
我们的产品有KFC和MDL
/**
* 具体产品类
*/
class KFC extends FastFood {
@Override
void show() {
System.out.println("生产了KFC");
}
}
class MDL extends FastFood {
@Override
void show() {
System.out.println("生产了MDL");
}
}
快餐工厂可以根据用户的需求来创建对应的品牌
/**
* 快餐工厂
*/
public class FastFoodFactory {
/***
* 用于实现不同类型快餐品牌的创建
* @param brand 类型
* @return 快餐品牌
*/
public static FastFood GetFastFood(String brand) {
switch (brand) {
case "KFC":
return new KFC();
case "Mac":
return new Mac();
default:
throw new IllegalArgumentException("没有该品牌");
}
}
}
于是我们迎来了我们的第一位客人
/**
* 学生
*/
public class Student {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.print("您想吃什么:");
String brand=input.next();
FastFood kfc = FastFoodFactory.GetFastFood(brand);
kfc.show();
}
}
2.2 工厂方法模式
简介:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。主要是为了解决简单工厂模式不满足开闭原则的缺点
优点:有良好的扩展性(完成满足开闭原则)
缺点:容易发生类爆炸
结构:
-
抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
-
具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
-
抽象产品:定义了产品的规范,描述了产品的主要特征和功能。
-
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
适用场景:当一个类不知道它所必须创建对象的类或一个类希望由子类来指定它所创建的对象时
代码示例
//还是刚刚的快餐店,有的客人问店里有没有汉堡🍔卖?
//那我们得满足客人这一需求,就新开了一家制作汉堡的抽象工厂
/**
* fastfoodFactory:抽象工厂
*/
public interface fastfoodFactory{
//创建汉堡对象的方法
Fastfood createhamburger();
}
//有了快餐工厂后我们又问客人需要什么样的汉堡?比如是鸡腿堡呢还是牛肉堡呢?
//那前提是我们得有生产这两种汉堡的工厂吧。
/**
* 鸡腿堡工厂(具体工厂):专门用来生产鸡腿汉堡
*/
public class ChickenburgerFactory implements fastfoodFactory{
public Chickenburger createHamburger(){
return new Chickenburger();
}
}
/**
* 牛肉堡工厂(具体工厂):专门用来生产牛肉汉堡
*/
public class BeefburgerFactory implements fastfoodFactory{
public Beefburger createHamburger(){
return new Beefburger();
}
}
// 有了这两家制作不同类型的汉堡工厂后呢,我们还得知道什么是汉堡🍔
/**
* 汉堡(抽象产品)
*/
abstract class Hamburger{
//展示汉堡信息
abstract void show();
}
// 如何我们再看看两种不同的汉堡
/**
* 牛肉堡(具体产品)
*/
public class Beefburger extends hamburger{
@Override
void show() {
System.out.println("生产了牛肉堡");
}
}
/**
* 鸡肉堡(具体产品)
*/
public class Chickenburger extends hamburger{
@Override
void show() {
System.out.println("生产了鸡腿堡");
}
}
// 万事俱备,我们来模拟一下客户点餐吧
public static void main(String[] arge){
/*创建汉堡工厂类*/
fastfoodFactory factory = new ChickenburgerFactory();
Hamburger hamburger = factory.createhamburger();
hamburger.show();//打印结果:生产了鸡腿堡
factory = new BeefburgerFactory();
Hamburger hamburger = factory.createhamburger();
hamburger.show();//打印结果:生产了牛肉堡
}
2.3 抽象工厂模式
前面介绍的工厂模式都是对同一系列的产品进行描述,比如汉堡厂只生产汉堡,畜牧场只养动物。
这些工厂只生产同种类型产品,同种产品称为同等级产品。但是生活中大多数的工厂都是综合性工厂,能生产多等级(种类)的产品,比如电器厂即能生产电视机又能生产洗衣机或者空调。
简介:创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就得能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版,工厂方法模式只能生产一个等级产品,而抽象工厂模式可以生产多个等级的产品
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一产品族中的对象。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
结构:
-
抽象工厂:提供了创建产品的接口,它包括多个创建产品的方法,可以创建多个不同等级的产品。
-
具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
-
抽象产品:定义了产品的规范,描述了产品的主要特征和功能,抽象工厂模式有多个抽象产品。
-
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间多对一的关系。
适用场景:
-
系统中有多个产品族,而系统一次只可能消费其中一族产品
-
同属于同一个产品族的产品一起使用时。
代码示例
//还是刚刚的快餐店,现在客户说它不仅想吃汉堡🍔还想吃薯条🍟
//和刚刚一样我们又需要一家快餐工厂吧。
/**
* 抽象工厂 快餐工厂
*/
public abstract class FastFoodFactory {
//生产汉堡
public abstract Ham CreateHam();
//生产薯条
public abstract Chips CreateChips();
/***
*根据brand类型返回不同的工厂
* @param brand 工厂类型 品牌
* @return 实体工厂
*/
public static FastFoodFactory GetFactory(String brand){
switch(brand){
case "KFC":
return new KFCFactory();
case "Mac":
return new MacFactory();
default:
throw new IllegalArgumentException("不存在的工厂类型");
}
}
}
//与之前不同的是我们这里将薯条和汉堡归为同一产品族中的物品。
//在抽象工厂中我们又定义了具体工厂的创建方法。
//可以用来创建KFC快餐工厂(具体工厂)和Mac快餐工厂(具体工厂)
//虚拟产品和具体产品跟上面工厂方法中差不多这里就不列举了
//模拟一下客户点餐
public class Client {
public static void main(String[] args) {
/**创建食品工厂*/
Scanner input=new Scanner(System.in);
System.out.print("您想吃什么:");
String brand=input.next();//输入KFC
/**根据品牌生成实体工厂*/
FastFoodFactory factory=FastFoodFactory.GetFactory(brand);
factory.CreateChips().info();//打印麦当劳汉堡
factory.CreateHam().Show();//打印肯德基汉堡
}
}
2.4 扩展:万能工厂
其实是对简单工厂的一个改变,在我们使用简单工厂的时候
/**
* 快餐工厂
*/
public class FastFoodFactory {
/***
* 用于实现不同类型快餐品牌的创建
* @param brand 类型
* @return 快餐品牌
*/
public static FastFood GetFastFood(String brand) {
switch (brand) {
case "KFC":
return new KFC();
case "Mac":
return new Mac();
default:
throw new IllegalArgumentException("没有该品牌");
}
}
}
我们发现在添加新产品的时候必须在switch修改,否则无法选择,太繁琐了。但我们可以利用反射来动态的获取对象类信息,将字符串直接转换成一个对象。
/***
* 用于实现不同类型快餐品牌的创建
* @param brand 类型
* @return 快餐品牌
*/
public static FastFood GetFastFoodPro(String brand) {
try {
return (FastFood) Class.forName("DP02.demo21." + brand).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
现在我们扩展一个类,就无需关心工厂类了,符合OCP原则。修改抽象工厂方法基本一样。
三、单例模式
3.1 单例模式简介
采取一定方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。这是设计模式中最简单的一种,没准无意中就使用到过。
适用场景:
-
非常耗资源的对象创建时(比如读取大文件)
-
资源的创建比较昂贵(比如数据库的连接)
-
逻辑上只应该有一个(比如winform中某些窗口只应打开一次)
3.2 单例模式的实现方式
单例模式主要分为:
1)饿汉模式
2)懒汉模式
标红为推荐使用的方式
3.2.1 饿汉模式
饿汉模式是指在类的加载的时候就创建一个实例。饿汉模式又分两种实现方式:
1)通过静态常量实现
优点:写法比较简单,就是在类转载的时候就完成实例化。避免了线程同步问题。
缺点:是在类转载的时候就完成实例化,如果从头到尾未使用过这个实例,则会照成内存的浪费。
结论:这种单例模式可用,可能造成资源浪费,所以一般在确定一定会用到这个类时采用。
代码示例
步骤如下:
1)构造器私有化(防止 new)
2)类的内部创建对象
3)向外暴露一个静态的公共方法。getInstance
class Singleton{
//1.构造器私有化,外部不能new
private Singleton(){
}
//2.本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3.提供一个公有的静态方法,放回实例对象
public static Singleton getInstance(){
return instance;
}
}
2)通过静态代码块实现。
这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也就是类转载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面一样
结论:这种单例模式可用,但是会造成资源浪费
代码示例
1)构造器私有化(防止 new)
2)类的内部声名静态对象
3)在静态代码块中,创建单例对象
4)提供一个公有的静态方法,放回实例对象
class Singleton{
private static Singleton instance;
private Singleton(){
}
static {// 在静态代码块中,创建单例对象
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
3.2.2 懒汉模式
懒汉模式是指在调用方法的时候进行实例化的工作。实现方式有六种:
1)线程不安全
优点:起到了懒加载的效果,但是只能在单线程下使用。
缺点:如果在多线程下,一个线程进入了if(singletion == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式
结论:在实际开发中,不要使用这种方式(多线程环境下,线程不安全)
代码示例
实现步骤
1)构造器私有化(防止 new)
2)类的内部声名静态对象
3)提供一个静态的公有方法,当使用到该方法时,才去创建 instance
class Singleton{
private static Singleton instance;
private Singleton(){
}
//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
//即懒汉式
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
2)线程安全,同步方法
优点:解决了线程不安全问题
缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想要获得该类实例,直接return就行了。
结论:在实际开发中,不推荐使用这种方法(方法进行同步效率太低)
代码示例
实现步骤
1)构造器私有化(防止 new)
2)类的内部声名静态对象
3)
class Singleton{
private static Singleton instance;
private Singleton(){
}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
//即懒汉式
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
3)线程安全,同步代码块
这种方法,本意是对上一种实现方法的改进,因为前面方法效率太低,改为同步产生实例化的代码块。但这种同步方法并不能起到线程同步的作用。跟第一种实现方法情形一致,假如一个线程进入了if(singletion == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。
结论:在实际开发中,不能使用这种方式
代码示例
实现步骤
1)构造器私有化(防止 new)
2)类的内部声名静态对象
3)提供一个静态的公有方法,在代码块中加入同步处理的代码(synchronized)
class Singleton{
private static Singleton singleton;
private Singleton(){
}
//提供一个静态的公有方法,在代码块中加入同步处理的代码(synchronized)
//即懒汉式
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
singleton = new Singleton();
}
}
return singleton;
}
}
4)双重检查
优点:线程安全,延迟加载,效率较高
缺点:无!!!
结论:在实际开发中,推荐使用这种单例设计模式
代码示例
实现步骤
1)构造器私有化(防止 new)
2)类的内部声名静态对象并用volatile(用来确保将变量的更新操作通知到其他线程)关键字修饰
3)提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
class Singleton{
private static volatile Singleton instance;
private Singleton(){
}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
public static synchronized Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){//当第一个线程执行完对象实例化操作后
if(instance == null) {//后面的线程来到这里时判断
instance = new Singleton();
}
//else 到下面返回 instance
}
}
//而当再后面的线程来时在最上方的判断语句中就直接来到这里返回instance
return instance;
}
}
5)静态内部类
优点:
- 线程安全(在类进行初始化时,别的线程是无法进来的。)
- 延迟加载(外部类的装载不会导致静态内部类的装载)
- 效率高
缺点:无 !!!
结论:实际开发中,推荐使用这种单例设计模式
代码示例
实现步骤
1)构造器私有化(防止 new)
2)类的内部声名静态对象
3)写一个静态内部类,该类中有一个静态属性外部类的静态常量
4)提供一个静态的公有方法,直接返回静态内部类常量属性
class Singleton{
private static Singleton instance;
private Singleton(){
}
//写一个静态内部类,该类中有一个静态属性 Singleton
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE
public static synchronized Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
6)枚举
这是借助JDK1.5中添加的枚举来实现单例模式。
优点:保证了线程安全、防止了反序列化重新创建新的对象
缺点:无 !!!
结论:推荐使用
代码示例
//使用枚举,可以实现单例,推荐
enum Singleton{
INSTANCE;//属性
public void sayOK(){
System.out.println("ok~");
}
}
3.2.3 懒汉和饿汉的区别
区别 | 饿汉 | 懒汉 |
---|---|---|
线程 | 安全 | 不安全(不过有解决方案) |
资源加载 | 占据一定的内存相应的在调用时速度也会更快 | 第一次掉用时要初始化如果要做的工作比较多性能上会有些延迟 |
四、原型模式
4.1 原型模式简介
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
结构:
- 抽象原型类:规定了具体原型对象必须实现的 clone() 方法。
- 具体原型类:实现抽象原型类的 clone() 方法,它是被复刻的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
适用场景:
- 对象的创建非常复制,可以适用原型模式快捷的创建对象。
- 性能和安全要求比较高。
4.2 原型模式实现
原型模式的克隆分为浅克隆和深克隆
浅克隆:只克隆原对象中的基本类型数据,非基本数据类型数据的指向的还是原堆中地址
深克隆:将对象完全克隆,属性中引用的其他对象不再指向原有对象地址
Java中的Object类中提供了 clone() 方法来实现浅克隆。Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable 接口的子类实现就是具体的原型类。
浅克隆
实现步骤:
// 1.需要克隆的类实现 Cloneable 接口
// 2.重新Clone方法
public class Realizetype implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//测试一下
public static void main(String[] arge) throws CloneNotSupportedException {
Realizetype realizetyp = new Realizetype();
Realizetype clone = (Realizetype) realizetyp.clone();
}
}
深克隆
实现深克隆的方法有很多种,这里我们使用的是序列化+反序列化来实现深克隆
import java.io.*;
public class Realizetype implements Cloneable{
public static void main(String[] arge) throws Exception {
//创建原型对象
Student student = new Student();
//创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:/xxx.txt"));
//写对象
oos.writeObject(student);
//释放资源
oos.close();
//创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:/xxx.txt"));
//读取对象
Student student1 = (Student) ois.readObject();
//释放资源
oos.close();
}
}
//实现序列号接口
class Student implements Serializable {
}
五、创建者模式
5.1 创建者模式介绍
概念:将一个复杂对象的构建与分离,使得同样的构建过程可以创建不同的表示。
结构:
-
抽象创建者(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的对象部件的创建。
-
具体创建者(ConcreteBuilder):实现 Burider 接口,完成复杂产品的各个部分的具体创建方法。在构建过程后,提供产品的实例。
-
产品类(Product):要创建的复杂对象
-
指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
优点:
- 封装性好 : 创建 和 使用 分离 ;
- 扩展性好 : 建造类之间 相互独立 , 在 一定程度上解耦 ;
缺点:
- 增加类数量 : 产生多余的 Builder 对象 ;
- 内部修改困难 : 如果 产品内部发生变化 , 建造者也要相应修改 ;
适用场景:
- 结构复杂 : 对象 有 非常复杂的内部结构 , 有很多属性 ;
- 分离创建和使用 : 想把 复杂对象 的 创建 和 使用 分离 ;
- 当创造一个对象 需要很多步骤时 , 适合使用建造者模式 ;
- 当创造一个对象 只需要一个简单的方法就可以完成 , 适合使用工厂模式
5.2 创建者模式实现
假设要创建一个双层牛肉鸡腿堡🍔,这个肉(meat)和配料(dosing)非常复杂,采用创建者方式。
点击查看代码
/**
* 汉堡类
*/
public class Hamburger {
// 配料部件,这里使用字符串作为部件,真正使用是传入对象作为部件
private String meat;//肉
private String dosing;//配料
public Hamburger(String meat, String dosing) {
this.meat = meat;
this.dosing = dosing;
}
public Hamburger() {
}
public String getMeat() {
return meat;
}
public void setMeat(String meat) {
this.meat = meat;
}
public String getDosing() {
return dosing;
}
public void setDosing(String dosing) {
this.dosing = dosing;
}
@Override
public String toString() {
return "Hamburger{" +
"meat='" + meat + '\'' +
", dosing='" + dosing + '\'' +
'}';
}
public static class Beefburger {
}
}
/**
* 抽象创建者
*/
public abstract class Builder {
// 将hamburger对象创建在抽象创建者中,实现类就可以对这个类进行创建部件
Hamburger hamburger = new Hamburger();
abstract void setmeat();
abstract void setdosing();
abstract Hamburger createHamburger();
}
/**
* 牛肉堡创造者类
*/
public class Beefburger extends Builder{
@Override
void setbeef() {
hamburger.setMeat("牛肉");
}
@Override
void setdosing() {
hamburger.setDosing("烧烤酱");
}
@Override
Hamburger createHamburger() {
return hamburger;
}
}
/**
* 鸡腿堡创造者类
*/
public class Chickenburger extends Builder{
@Override
void setbeef() {
hamburger.setMeat("鸡肉");
}
@Override
void setdosing() {
hamburger.setDosing("沙拉酱");
}
@Override
Hamburger createHamburger() {
return hamburger;
}
}
/**
* 指挥者类
*/
public class Director {
private Builder builder;
// 初始化创建者
public Director(Builder builder){
this.builder = builder;
}
// 构建方法,装配部件
public Hamburger construct(){
builder.setbeef();
builder.setdosing();
Hamburger hamburger = builder.createHamburger();
return hamburger;
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 鸡腿堡创建
Chickenburger chickenburger = new Chickenburger();
Director director = new Director(chickenburger);
Hamburger hamburger = director.construct();
// 牛肉堡创建
Beefburger beefburger = new Beefburger();
Director director1 = new Director(beefburger);
Hamburger hamburger1 = director1.construct();
System.out.println(hamburger);
System.out.println(hamburger1);
}
}
/*测试结果
Hamburger{meat='鸡肉', dosing='沙拉酱'}
Hamburger{meat='牛肉', dosing='烧烤酱'}*/
可以看出,指挥者类对于产品的创建有着至关重要的作用,Builder只是提供了部件的创建,而真正决定怎么创建的,需要由指挥者类(Director)来决定
当部件比较少的时候,可以将指挥者类合并到抽象创建者类里面,但这样就违背了设计原则中的单一职责原则
/**
* 抽象创建者
*/
public abstract class Builder {
// 将hamburger对象创建在抽象创建者中,实现类就可以对这个类进行创建部件
Hamburger hamburger = new Hamburger();
abstract void setmeat();
abstract void setdosing();
abstract Hamburger createHamburger();
public Hamburger construct(){
this.setmeat();
this.setdosing();
Hamburger hamburger = this.createHamburger();
return hamburger;
}
}
5.3 创建者模式扩展
有时候我们还会遇到这样的问题
//当我们对象属性定义过多时,我们可以使用创建者模式进行链式赋值
//增加其代码的可读性。操作简单,重构前:
public class Hamburger {
private String meat;
private String dosing;
private String vegetable;
private String bread;
public String getMeat() {
return meat;
}
public void setMeat(String meat) {
this.meat = meat;
}
public String getDosing() {
return dosing;
}
public void setDosing(String dosing) {
this.dosing = dosing;
}
public String getBread() {
return bread;
}
public void setBread(String bread) {
this.bread = bread;
}
public String getVegetable() {
return vegetable;
}
public void setVegetable(String vegetable) {
this.vegetable = vegetable;
}
public Hamburger(String meat, String dosing, String vegetable, String bread) {
this.meat = meat;
this.dosing = dosing;
this.vegetable = vegetable;
this.bread = bread;
}
@Override
public String toString() {
return "Hamburger{" +
"meat='" + meat + '\'' +
", dosing='" + dosing + '\'' +
", vegetable='" + vegetable + '\'' +
", bread='" + bread + '\'' +
'}';
}
}
/**
* 测试类
*/
public class Client{
public static void main(String[] args) {
Hamburger hamburger=new Hamburger("牛肉","烧烤酱","青菜","普通面包");
System.out.println(hamburger);
}
}
//测试结果
//Hamburger{meat='牛肉', dosing='烧烤酱', vegetable='青菜', bread='普通面包'}
重构后
/**
* 静态内部创建者类改进后
*/
public class Hamburger {
private String meat;
private String dosing;
private String vegetable;
private String bread;
// 将构造方法私有化,采用创建者实现构建
private Hamburger(Builder builder){
this.meat = builder.meat;
this.dosing = builder.dosing;
this.vegetable = builder.vegetable;
this.bread = builder.bread;
}
// 创建一个静态内部创建者类
public static class Builder{
private String meat;
private String dosing;
private String vegetable;
private String bread;
// 分别创建属性
public Builder setMeat(String val) {
meat = val;
return this;
}
public Builder setDosing(String val) {
dosing = val;
return this;
}
public Builder setVegetable(String val) {
vegetable = val;
return this;
}
public Builder setBread(String val) {
bread = val;
return this;
}
// 外部类的构造方式已经私有了,所以通过内部类方法返回一个Phone对象
public Hamburger build(){
// 内部类可以直接调用外部类的私有构造器
// 再将内部类这个对象传给私有构造器,让他来进行构造
return new Hamburger(this);
}
}
@Override
public String toString() {
return "Builder{" +
"meat='" + meat + '\'' +
", dosing='" + dosing + '\'' +
", vegetable='" + vegetable + '\'' +
", bread='" + bread + '\'' +
'}';
}
}
通过改进后,我们就可以通过调用静态内部类的方法,来实现构造器方法
由于内部类每设置一个属性就返回 Builder 所有可以连接赋值
并且还可以选择性的构造,不易造成错误
5.4 工厂方法模式VS建造者模式
工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。
5.5 抽象工厂模式VS建造者模式
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。
建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
此文章只作为学习过程记录!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示