设计原则是指导我们代码设计的一些经验总结,也就是“心法”;面向对象就是我们的“武器”;设计模式就是“招式”。
以心法为基础,以武器运用招式应对复杂的编程问题。
为什么麦当劳那么受欢迎?
表妹:哥啊,我想吃麦当劳
我:你为啥那么喜欢吃麦当劳呢?
表妹:因为它好吃呀,而且每个门店吃的味道都差不多,不像某县小吃,每个地方吃的味道都有区别。
我:那你知道为什么嘛?
表妹:因为麦当劳有一套非常完善的工作流程,每个门店都必须遵守这套规范…
这不就是我们设计模式中的【建造者模式】嘛?
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
我们以煲汤为例子,我们知道,主汤料和水是煲汤必须的,配料是可放可不放的,有些人喜欢吃原汁原味,可以不放盐,有些肉比较油,那么,也可以不放油。
我们来看看具体的代码实现:
public class Soup {
private static final int MAX_INGREDIENTS = 10;
private static final int MAX_OIL = 8;
private static final int MAX_SALT = 5;
private String mainIngredient; // 主料必须
private String water; // 水必须
private int ingredients; // 配料可选
private int oil; // 油可选
private int salt; // 盐可选
public Soup(String main, String water, Integer ingredients, Integer oil, Integer salt) {
if (StringUtils.isBlank(main)) {
throw new IllegalArgumentException("main should not be empty");
}
this.mainIngredient = main;
if (StringUtils.isBlank(water)) {
throw new IllegalArgumentException("water should not be empty");
}
this.water = water;
if (ingredients != null) {
if (ingredients < 0) {
throw new IllegalArgumentException("ingredients should not be positive");
}
this.ingredients = ingredients;
}
if (oil != null) {
if (oil < 0) {
throw new IllegalArgumentException("oil should not be positive");
}
this.oil = oil;
}
if (salt != null) {
if (salt < 0) {
throw new IllegalArgumentException("salt should not be positive");
}
this.salt = salt;
}
}
// 省略get方法
}
// 今天想吃鱼头豆腐汤
Soup fishHeadTofuSoup = new Soup("鱼头", "山泉水", 10, 6, 3);
大家可以看到,这个构造函数有5个参数,参数列表太长,导致代码在可读性和易用性上都会变差。
而且这么长的参数列表,参数类型一样的都连在一起,在使用构造函数的时候,就很容易搞错各参数的顺序,传递进错误的参数值,导致非常隐蔽的bug。上面这个例子中,配料和盐都是int类型,万一我一不小心,把这两个参数的位置互换了,变成放3克的配料,放10克的盐,那还能吃嘛?
有些同学可能会说,你这个类在构造对象的时候,有些属性是可选可不选的,这些属性可以通过set()函数来设置。
是的,我们来看一下,这种方法的实现效果:
public class Soup {
private static final int MAX_INGREDIENTS = 10;
private static final int MAX_OIL = 8;
private static final int MAX_SALT = 5;
private String mainIngredient; // 主料必须
private String water; // 水必须
private int ingredients; // 配料可选
private int oil; // 油可选
private int salt; // 盐可选
public Soup(String main, String water) {
if (StringUtils.isBlank(main)) {
throw new IllegalArgumentException("main should not be empty");
}
this.mainIngredient = main;
if (StringUtils.