设计模式笔记之构造器模式的使用

<其它设计模式介绍及案例源码下载 >

简介:构造器模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。一个 Builder 类会一步一步构造最终的对象。该 Builder 类无需通过其他对象完成构造,独立于其他对象的。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的子对象的属性经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定,而且组合体对象个属性是稳定不变的

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

实例解析:

        类中有些属性是必须的,有些则是可选的。你将要如何创建你的对象?所有的属性都声明为final,所以你必须在构造器中给它们全部赋值,但是你也想给这个类的客户端忽略可选属性的机会。

public class User {
  private final String firstName;    //required
    private final String lastName;    //required
    private final int age;    //optional
    private final String phone;    //optional
    private final String address;    //optional
    ...
}

 

方案一(通过使用不同个数参数的构造函数,如下): 

public User(String firstName, String lastName) {
  this(firstName, lastName, 0,,"","");
}
 
public User(String firstName, String lastName, int age) {
  this(firstName, lastName, age, "","");
}
 
public User(String firstName, String lastName, int age, String phone) {
  this(firstName, lastName, age, phone, "");
}
 
public User(String firstName, String lastName, int age, String phone, String address) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.phone = phone;
  this.address = address;
}

评价: 当你只有几个属性时还好,但是当属性个数太多时,代码就变的难以理解和维护。并且代码对客户端来说变的很难,如:应该调用哪个构造器?有两个参数的?有三个参数的?那些不用传确切值的参数的默认值是多少?几个类型相同的参数是很令人费解的。第一个String是电话还是地址?等等一系列问题

 

方案二(通过对可选参数设置set、get方法,如下): 

public class User {
  private String firstName; // required
  private String lastName; // required
  private int age; // optional
  private String phone; // optional
 
  public User() {
    this.firstName=firstName;
    this.lastName=lastName;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public String getPhone() {
    return phone;
  }
  public void setPhone(String phone) {
    this.phone = phone;
  }

}

评价:这种方法有两个主要弊端。第一个是类 实例的不一致状态。如果你要用User的多个属性来创建一个User对象,那么在所有的setX方法调用前,对象处于不完全状态。这就意味着客户端的其他 部分可能看到对象,并且假设它已经完成构造了,实际它并没有。方法的第二个缺点是对象的各个属性可以通过set方法一直处于可变状态,丧失了对象稳定不变的优势。

 

方案三(构造器模式); 

public class Users {

	private final String name;
	private final String gender;
	private final int age;
	private final String email;
	
	private Users(UsersBuilder ub) {
		super();
		this.name = ub.name;
		this.gender = ub.gender;
		this.age = ub.age;
		this.email = ub.email;
	}
	public String getName() {
		return name;
	}
	public String getGender() {
		return gender;
	}
	public int getAge() {
		return age;
	}
	public String getEmail() {
		return email;
	}

@Override
	public String toString() {
		return "Users [name=" + name + ", gender=" + gender + ", age=" + age + ", email=" + email + "]";
	}



public static class UsersBuilder {
		final String name;
		final String gender;
		String email;
		int age;
		public UsersBuilder(String name, String gender) {
			super();
			this.name = name;
			this.gender = gender;
		}
		public UsersBuilder setAge(int age) {
			this.age = age;
			return this;
		}
		public UsersBuilder setEmail(String email) {
			this.email = email;
			return this;
		}
		public String getEmail() {
			return email;
		}
		public int getAge() {
			return age;
		}
		public String getName() {
			return name;
		}
		public String getGender() {
			return gender;
		}
		
		public Users build() throws Exception {
			Users user=new Users(this);
			if(user.getAge()>200) {
				throw new Exception("参数格式不正确");
			}
			return user;
		}
	}
}
public class TestClass {

	public static void main(String[] args) {
		UsersBuilder ub=new UsersBuilder("张三","男");
		Users user=null;
		try {
			user=ub.setAge(13).build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(user.getEmail());
	}

}

评价:这种方法能确保,无论什么时候你拿到这个类的一个对象,它的状态都是完整的。重点是,类似于构造器,建造者可以强制其参数的不变性。建造方法可以检查这些不变性, 如果它们无效就抛出Exception异常。关键是可以在从建造者中拷贝参数到对象时检查,并且是在对象字段上检查而不是在构造 器字段。这样做的理由是,既然建造者不是线程安全的,如果我们在实际创建对象前检查参数,参数值可能会在检查和拷贝之间被另一个线程改变。这个阶段的时间 被认为是“易损窗口”。

注意:

  • User的构造器是私有的,这就意味着客户端不能直接创建实例。
  • 这个类是不可变的。所有属性都是final类型并且他们由构造器设置值。此外,我们只提供getter操作。
  • 建造者的构造器只接受两个必须的参数,并且这两个属性是仅有的被设置为final类型的,这样就能保证这些属性在构造器中是被赋值的。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值