设计模式-4.建造者模式

建造者模式:

  建造模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。当构造方法参数过多时使用建造者模式。

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,通俗的说就是:建造者模式就是如何一步步构建一个包含多个组成部件的对象,相同的构建过程可以创建不同的产品。

1. 简单的构造模式

UML类图:

具体代码实现:

被建造的对象-----Computer.java

/**
 * 产品类--被建造的对象
 */
public class Computer {
    private String cpu ; // cpu
    private String hardDisk ; //硬盘
    private String mainBoard ; // 主板
    private String memory ; // 内存

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public String getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }

    public String getMainBoard() {
        return mainBoard;
    }

    public void setMainBoard(String mainBoard) {
        this.mainBoard = mainBoard;
    }

    public String getMemory() {
        return memory;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }
}

抽象的建造者-----Builder.java

/**
 * 抽象的建造者,即装电脑的步骤
 * 至于安装什么型号的主板,不是我关心,而是具体的建造者关心的
 */
public interface Builder {
    // 安装主板
    void createMainBoard(String mainBoard) ;
    // 安装 cpu
    void createCpu(String cpu) ;
    // 安装硬盘
    void createhardDisk(String hardDisk) ;
    // 安装内存
    void createMemory(String memory) ;
    // 组成电脑
    Computer createComputer() ;
}

具体建造者 -----AssemblerBuilder.java 

public class AssemblerBuilder implements Builder {
    Computer computer = new Computer();
    @Override
    public void createMainBoard(String mainBoard) {
        computer.setMainBoard(mainBoard);
    }

    @Override
    public void createCpu(String cpu) {
        computer.setCpu(cpu);
    }

    @Override
    public void createhardDisk(String hardDisk) {
        computer.setHardDisk(hardDisk);
    }

    @Override
    public void createMemory(String memory) {
        computer.setMemory(memory);
    }

    @Override
    public Computer createComputer() {
        return computer;
    }
}
/**
 * 声明一个导演类「指挥者,这里可以装电脑的老板」,用来指挥组装过程,也就是组装电脑的流程
 */
public class Director {
    private Builder builder;
    // 使用多态,装机工很多,老板可以指挥各个装几个
    public Director(Builder builder){
        this.builder = builder;
    }
    // 老板最后只想获得装成的成品
    public Computer createComputer(String cpu,String hardDisk,String mainBoard,String memory){
        // 具体工作是装机工去做
        this.builder.createMainBoard(mainBoard);
        this.builder.createCpu(cpu);
        this.builder.createMemory(memory);
        this.builder.createhardDisk(hardDisk);
        return this.builder.createComputer();
    }
}

复制代码

测试:

public class Test {
    public static void main(String[] args) {
        // 装机员小美
        Builder builder = new AssemblerBuilder();
        // 老板把小明的需求转给小美
        Director director = new Director(builder);
        // 老板最后拿到成品电脑,工作小美去做
        Computer computer = director.createComputer("Intel 酷睿i9 7900X","三星M9T 2TB (HN-M201RAD)","技嘉AORUS Z270X-Gaming 7","科赋Cras II 红灯 16GB DDR4 3000");
        System.out.println("小明使用的电脑是:\n"+computer.getMainBoard()+"主板\n"+computer.getCpu()+"CPU\n"+computer.getHardDisk()+"硬盘\n"+computer.getMemory()+"内存\n");
    }
}

 

建造者模式的优缺点

  • 优点
    1. 使创建产品的步骤「把创建产品步骤放在不同的方法中(AssemblerBuilder.java中的各个方法),更加清晰直观」和产品本身分离,即使用相同的创建过程创建出不同的产品。
    2. 每个建造者都是独立的互不影响,这样就达到解耦的目的,所以如果想要替换现有的建造者那非常方便,添加一个实现即可。
  • 缺点
    1. 只适用于产品具有相同的特点「过程和步骤」,如果产品之间差异非常大,则不适用「使用范围受限」
    2. 万一那天产品内部发生改变,那多个建造者都要修改,成本太大

建造者模式的使用场景

  1. 如果一个对象有非常复杂的内部结构「这些产品通常有很多属性」,那么使用建造者模式
  2. 如果想把复杂对象的创建和使用分离开来,那么使用建造者模式「使用相同的创建步骤可以创建不同的产品」

 

 建造者模式的另一种写法:

当我看到建造者模式时,第一个想到的就是lombok的@builder的注解。

由于是用Builder模式来创建某个对象,因此就没有必要再定义一个Builder接口,直接提供一个具体的建造者类就可以了。
对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,干脆去掉“导演者”,把导演者的功能和Client的功能合并起来,也就是说,Client这个时候就相当于导演者,它来指导构建器类去构建需要的复杂对象。

先看下面这个例子该如何处理:

public class User{
 
    String name;
    int age;
    String email;
    String address;
 
    public User(){
    }
    
    //想要有名字和邮箱的构造器
    public User(String name, String email){
        this.name = name;
        this.email = email;
    }
 
    //想要有名字和地址的构造器
    public User(String name, String address){
        this.name = name;
        this.address = address;
    }
}

 

在上面代码中,很容易可以发现,在我们正常的需求下,Java构造器的编写将会出问题,由于参数个数和类型一样无法构成重载,所以这样写是不行的,那么我们可以通过Builder模式解决这种情况。

public class User {
 
	String name;
	int age;
	String phone;
	String email;
	String address;
 
    //注意无参构造器私有,避免外界使用构造器创建User对象
	private User() {
	}
 
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", phone=" + phone + ",                 
                email=" + email + ", address=" + address
				+ "]";
	}
 
	public static class Builder {
 
		private String name;
		private int age;
		private String phone;
		private String email;
		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 setPhone(String phone) {
			this.phone = phone;
			return this;
		}
 
		public Builder setEmail(String email) {
			this.email = email;
			return this;
		}
 
		public Builder setAddress(String address) {
			this.address = address;
			return this;
		}
 
		public User build() {
			User user = new User();
			user.name = name;
			user.age = age;
			user.email = email;
			user.phone = phone;
			user.address = address;
			return user;
		}
	}
}

 

根据上面的代码,我们可以看出来,就是在User内部创建一个内部类,并且拥有和User一样的字段(属性),并且提供SET方法,最重要的是要提供一个能够返回User对象的方法(build),这样才能通过Builder来创建User对象。

Builder设计模式还有一个好处,那便是我们可以随意组合输入的参数,不仅避免了重载出错的问题,还不需要写过多的构造器。

下面我们一起看看写完Builder模式类之后如何来调用:
 

public class UserTest {
	
	public static void main(String[] args) {
		User u = new User.Builder().setName("bob").setAge(22).build();
		System.out.println(u);
	}
	
}

 

看到这个写法是不是很熟悉,和我们使用lombok中得@builder 注解构造对象的方式是一样的。我们看一下lombok中@builder反编译后的代码

@Builder
public class User {
    private final Integer code = 200;
    private String username;
    private String password;
}

// 编译后:
public class User {
    private String username;
    private String password;
    User(String username, String password) {
        this.username = username; this.password = password;
    }
    public static User.UserBuilder builder() {
        return new User.UserBuilder();
    }

    public static class UserBuilder {
        private String username;
        private String password;
        UserBuilder() {}

        public User.UserBuilder username(String username) {
            this.username = username;
            return this;
        }
        public User.UserBuilder password(String password) {
            this.password = password;
            return this;
        }
        public User build() {
            return new User(this.username, this.password);
        }
        public String toString() {
            return "User.UserBuilder(username=" + this.username + ", password=" + this.password + ")";
        }
    }
}

使用builder模式的好处:

1. 通过构造函数传参的方式来进行构建(臃肿 不能灵活地只设置某些参数)

2.写很多构造方法。而且容易吧两个属性的参数写错位置等等;(重载很多的构造器,然后可以保证数据的一致性,比较安全)

3.写一堆setter方法,缺点就是够早的过程会被分到几个调用中。构造可以出现不一致的状态。(而且代码很啰嗦)

4.采用builder模式的话,当一个类的参数很多的时候。

(使用javabean模式,调用一个无参的构造器,然后调用setter方法来设置每个必要的参数。但是javabean自身有着严重的缺点,因为构造过程被分到几个调用中,在构造javabean可能处于不一致的状态,类无法仅仅通过检验构造器参数的有效性来保证一致性。也就是set的过程中其实很多时候并不能保证一致性,因为set已经算是分开执行了)

build模式 既能保证像重叠构造器那样的安全,也能实现JavaBean模式那样的可读性。 (不用操心线程)
 

 

基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值