Java链式调用-Builder模式

39 篇文章 0 订阅
1 篇文章 0 订阅

过去写链式调用感觉又臭又长,这种编码方式的代码看着很不爽,且不明白调用的顺序。而且老师教的时候就已经习惯了,“一行一句,分号结尾”。现在呢,感觉又要极力推崇链式调用了,因为它还真方便!当你慢慢熟悉之后就会发现这样写无论在可读性和代码量上都有优势。

在讲链式调用之前,还是先说一下,java的一个设计模式吧 – Builder模式

Builder模式

Builder模式是一种一步一步创建一个复杂对象的设计模式,这种设计模式的精髓就主要有两点:其一,用户使用简单,并且可以在不需要知道内部构建细节的情况下,就可以构建出复杂的对象模型;其二,对于设计者来说,这是一个解耦的过程,这种设计模式可以将构建的过程和具体的表示分离开来。

Builder模式的使用场景

  • 相同的方法,不同的执行顺序,产生不同的时间结果
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不同时
  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候用建造者模式非常适合
  • 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值

链式调用

链式调用的变形太多了,先看比较经典的

package builder;

/**
 * Builder模式,链式调用Demo<br>
 * 
 * @author junehappylove
 *
 */
public class User {

	private final String firstName;
	private final String lastName;
	private final int age;
	private final String phone;
	private final String address;

	private User(UserBuilder builder) {
		this.firstName = builder.firstName;
		this.lastName = builder.lastName;
		this.age = builder.age;
		this.phone = builder.phone;
		this.address = builder.address;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public int getAge() {
		return age;
	}

	public String getPhone() {
		return phone;
	}

	public String getAddress() {
		return address;
	}
	
	//Builder
	public static class UserBuilder {
		private final String firstName;
		private final String lastName;
		private int age;
		private String phone;
		private String address;

		public UserBuilder(String firstName, String lastName) {
			this.firstName = firstName;
			this.lastName = lastName;
		}

		public UserBuilder age(int age) {
			this.age = age;
			return this;
		}

		public UserBuilder phone(String phone) {
			this.phone = phone;
			return this;
		}

		public UserBuilder address(String address) {
			this.address = address;
			return this;
		}

		public User build() {
			// 由于Builder是非线程安全的,所以如果要在Builder内部类中检查一个参数的合法性,
			// 必需要在对象创建完成之后再检查
			User user = new User(this);
			if (user.getAge() < 0 || user.getAge() > 255) {
				throw new IllegalStateException("Age out of range:" + user.getAge());// 线程安全
			}
			return user;
		}
	}

	public static void main(String[] args) {
		User june = new User.UserBuilder("Wang", "wei").age(18).address("qdao").build();
		System.out.println(june.getAddress());
	}
}

有几个重要的地方需要强调一下:

  • User类的构造方法是私有的。也就是说调用者不能直接创建User对象。
  • User类的属性都是不可变的。所有的属性都添加了final修饰符,并且在构造方法中设置了值。并且,对外只提供getters方法。
  • Builder模式使用了链式调用。可读性更佳。
  • Builder的内部类构造方法中只接收必传的参数,并且该必传的参数使用了final修饰符。

再看一下一些变种的链式调用:

public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public static Builder builder() {
        return new Builder();
    }

    private User(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
    }

    public static class Builder {
        private String username;
        private String password;

        public Builder setUserName(String username) {
            this.username = username;
            return this;
        }
        public Builder setPassword(String password){
            this.password=password;
            return this;
        }
        public User build() {
            return new User(this);
        }

        @Override
        public String toString() {
            return "Builder{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public static void main(String[] args) {
        Builder builder = new User.Builder();
        builder.setUserName("lss0555")
                .setPassword("12345")
                .build();
        //或者
        User user = new User.Builder().setUserName("lss0555").setPassword("123123").build();
        //或者
        User user1 = User.builder().setUserName("lss0555").setPassword("654321").build();

        System.out.println("builder结果:"+builder.toString());
        System.out.println("User结果:"+user.toString());
        System.out.println("User2结果:"+user1.toString());
    }
}

上面这个大架子基本不变,但是

  • User的属性,没有用final修饰
  • 提供了setters方法
  • 提供了一个静态的builder方法,用于在User中获取Builder对象

应用

  1. 有位老哥,有这样经典的描述

本人在学习Java,直接先学习Netty框架,因为Netty框架是业界最流行的NIO框架之一,在学习的过程中,了解到Netty服务端启动需要先创建服务器启动辅助类ServerBootstrap,它提供了一系列的方法用于设置服务器端启动相关的参数。然而在创建ServerBootstrap实例时,发现ServerBootstrap只有一个无参的构造函数,事实上它需要与多个其它组件或者类交互。ServerBootstrap构造函数没有参数的原因是因为它的参数太多了,而且未来也可能会发生变化。Netty创造者为了解决这个问题,就引入了Builder模式。

  1. 有木有发现,讲Builder模式的链式调用,各路的大神都在使用用户User说事?为啥都不讲个其他的业务场景,哈哈,有部分原因是你抄我,我抄你;更重要的是User确实用的多哦,且翻一翻各路的开源框架中,你就会发现,链式调用一般会用在如下的场景中:
  • 有用户的地方(哈哈,感觉好扯淡啊,没事一会找找)
  • 权限验证系统,如Spring-security,Shiro
  • 数据库驱动/便捷框架,如mysql-connection,druid,mybatis
  • 上面都是猜的,写到这里,搜索发现无数的关于Builder模式和链式调用的文章,几乎千篇一律的拿用户说事,我就在想,需要这么low吗?这么高级的东西,真正的大神会去写User?

找一找,哪些大神在用链式调用,怎么用

  1. Spring-security
    Spring安全框架中的链式调用
    上面是Spring-security安全框架中的用户,它也认为用户是一个复杂的结构,在安全领域,它认为:用户名,密码和权限是必须的,也确实是必须的
package builder;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

/**
 * @author junehappylove
 *
 */
public class SpringSecurityUser {

	public static void main(String[] args) {
		GrantedAuthority aut = new SimpleGrantedAuthority("ADMIN");
		List<GrantedAuthority> auts = new ArrayList<>();
		auts.add(aut);
		UserDetails user1 = new User("june", "123", auts);//用户可以这样建立,其他属性默认为true
		// 但是更多的情况是如下建立一个用户
		User user2 = (User) User.withUsername("june").password("456").authorities("ADMIN")
				.accountExpired(true)
				.disabled(false)
				.accountLocked(false)
				.credentialsExpired(true)
				.build();
		System.out.println(user1.toString());
		System.out.println(user2.toString());
	}
}
  1. quartz
    quartz链式调用
    这个很明显,是一个单独的类,它是用来构建任务的,那么必须找到一个具体的任务类,也就是JobDetailImpl,里面的构造行数都是不推荐使用的,要用任务类,使用下面方法
    quartz链式调用使用方法

哎呀,框架中使用链式调用的地方太多了,像 安全框架shiro-core中的Subject,mybatis中就更多了,SQLBuilder,SQLDeleteBuilder,SQLSelectBuilder,SQLUpdateBuilder,UpdateBuilder等等。

最后,参考的最后一篇文章,这位老哥介绍的很全面,讲到java8之后,如何更加优雅的创建和使用链式调用,并且还介绍了lombok这个牛逼的工具类如何帮助你更加简洁的使用链式调用.


参考:

  • 13
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Javabuilder模式是一种创建对象的设计模式,它通过将对象的构建步骤分离出来,使得构建过程更加灵活和可控。 在builder模式中,我们通常会定义一个Builder类,用于构建对象的各个属性,并最终返回一个完整的对象。具体实现方式包括: 1. 定义一个内部静态类Builder,用于构建对象。 2. 在Builder类中定义与目标对象相同的属性,并提供对应的setter方法。 3. 在Builder类中定义一个build()方法,用于将Builder对象转换为目标对象。 4. 在目标对象的构造函数中,接收Builder对象作为参数,并将Builder对象中的属性赋值给目标对象。 通过这种方式,我们可以通过链式调用Builder对象的setter方法灵活地设置对象的属性,并最终创建出完整的对象。 例如,我们可以使用builder模式来构建一个Person对象: ```java public class Person { private String name; private int age; private String gender; private Person(Builder builder) { this.name = builder.name; this.age = builder.age; this.gender = builder.gender; } public static class Builder { private String name; private int age; private String gender; public Builder setName(String name) { this.name = name; return this; } public Builder setAge(int age) { this.age = age; return this; } public Builder setGender(String gender) { this.gender = gender; return this; } public Person build() { return new Person(this); } } } ``` 使用方式如下: ```java Person person = new Person.Builder() .setName("张三") .setAge(23) .setGender("男") .build(); ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

junehappylove

急急如律令,buibui~~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值