这条其实没什么好说的,每个程序员都遇到过参数大爆炸的情况,面对大量的可选参数,怎么办?
直接上例子。考虑用一个类表示食品外包装的营养成分标签。这些标签中的有几个域是必须的:每份的分量,每罐的含量以及每份的卡路里,还有超过20个的可选域:总脂肪量,饱和脂肪量,转化脂肪,胆固醇等等,大多数产品在某几个域中都会有非零的值。
Public class NutritionFacts { private final int servingSize;//ml required private final int serings;// per container required private final int calories;//optional private final int fat;//g optional private final int sodium;//mg optional private final int carbonhydrate;//g optional public NutritionFacts(int servingSize,int serings){ this(servingSize,servings,0); } public NutritionFacts(int servingSize,int serings,int calories){ this(servingSize,serings,calories,0); } public NutritionFacts(int servingSize,int serings,int calories,fat){ this(servingSize,serings,calories,fat,0); } public NutritionFacts(int servingSize,int serings,int calories,fat,sodium){ this(servingSize,serings,calories,fat,sodium,0); } public NutritionFacts(int servingSize,int serings,int calories,fat,sodium,carbonhydrate){ this.servingSize = servingSize; this.serings = servings; this.calories = calories; this.fat = fat; this.sodium = sodium; this.carbonhydrate = carbonhydrate; } }
这种方式是最常见的,缺点也是显而易见的,代码的可读性非常差,而且非常容易出错。
另外一种常见的方式就是JavaBean的方式,先创建实例,再通过set方法初始化,这种方式的缺点也很明显,破坏了创建对象操作的原子性,在构造过程中对象可能处于不一致的状态。
好了,来看一个两全其美的办法吧:
public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbonhydrate; public static class Builder { private final int servingSize; private final int servings; private int calories = 0; private int fat = 0; private int sodium = 0; private int carbonhydrate = 0; public Builder(int servingSize,int serving){ this.servingSize = servingSize; this.servings = serving; } public Builder calories(int val){ this.calories = val; return this; } public Builder fat(int val){ this.fat = val; return this; } public Builder carbonhyate(int val){ this.carbonhydrate = val; return this; } public Builder sodium(int val){ this.sodium = val; return this; } public NutritionFacts build(){ return new NutritionFacts(this); } } private NutritionFacts(Builder builder){ servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbonhydrate = builder.carbonhydrate; } public static void main(String[] args) { NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build(); } }
怎么样,是不是两个缺点都避免了,安全性和可读性都很好,当然Builder模式也有它自身的不足,创建构建器会产生一定的开销,对性能要求非常严格的情况下就不一定是最完美的解决方案了。
相关推荐
� A ndroid 在设计初期就考虑了与现其有业务的融合,改变以往从计算机为主改成从手机使用为导向。新 生应用如:G oogle 地图及其衍生应用、 GMail 、 GTalk 等。 � GPS 卫星导航功能,手机照相, MP3 ,蓝芽等均...
8-4-10 在ModelMaker中改进控件 8-4-11 在ModelMaker中继续编辑你的代码 8-4-12 重载构造器Create 8-4-13 实现Create,非用户节代码 8-4-14 即时代码生成 8-4-15 文档化你的控件8-4-16 创建一个帮助文件 8-4-17 在图...
第2章 生成、打包、部署和管理应用程序及类型 2.1 .NET Framework部署目标 2.2 将类型生成到模块中 2.2.1 响应文件 2.3 元数据概述 2.4 将模块合并成程序集 2.4.1 使用Visual Studio IDE将程序集添加到项目中...
第2章 Excel概述 2.1 关于对象 2.2 工作簿 2.2.1 工作表 2.2.2 图表工作表 2.2.3 XLM宏工作表 2.2.4 Excel 5/95对话框编辑表 2.3 Excel的用户界面 2.3.1 功能区的引入 2.3.2 快捷菜单 2.3.3 ...
我们把该类的构造器使用Private修饰,从而把该 类的所有构造器隐藏起来。 –2.则需要提供一个public方法作为该类的访问点,用于创建该类的对象,且必须使用static修饰 –3.该类还必须缓存已经创建的对象,必须...
在对由三部分组成的 Spring 系列 的第 1 部分进行总结时,我使用了一个示例,演示了如何通过 Spring IOC 容器注入应用程序的依赖关系(而不是将它们构建进来)。 我用开启在线信用帐户的用例作为起点。对于该实现,...
│ 高并发编程第二阶段28讲、使用ThreadLocal重新实现一个上下文设计模式.mp4 │ 高并发编程第二阶段29讲、多线程Balking设计模式-上.mp4 │ 高并发编程第二阶段30讲、多线程Balking设计模式-下.mp4 │ 高并发...
│ 高并发编程第二阶段28讲、使用ThreadLocal重新实现一个上下文设计模式.mp4 │ 高并发编程第二阶段29讲、多线程Balking设计模式-上.mp4 │ 高并发编程第二阶段30讲、多线程Balking设计模式-下.mp4 │ 高并发...
5.2.2 对象--一个构造函数的例子 5.3 函数类型--一个函数和闭包的例子 5.4 神奇的null和undefined 5.4.1 null 5.4.2 undefined--独一无二的类型 5.5 正则表达式 5.5.1 正则表达式常量 ...
5.7.5 构造器链:使用this调用另一个构造器 168 5.8 静态成员 172 5.8.1 静态字段 172 5.8.2 静态方法 174 5.8.3 静态构造器 175 5.8.4 静态属性 176 5.8.5 静态类 177 5.9 扩展方法 ...
一个“.java”原文件中是否可以包括多个类(不是内部类)? 53.掌握内部类和接口的概念 54.StringTokenizer类的使用 55.数据结构,如何遍历List中的元素? 如果要按照键值保存或者访问数据,使用什么数据结构? ...
但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地...
7.3.3 让方法有多个参数 163 7.4 返回值:汽车超速了吗? 164 7.4.1 写一个有返回值的方法 164 7.4.2 调用有返回值的方法 165 7.4.3 发生了什么?如何使用方法的返回值? 166 7.4.4 使用return结束方法 166 ...
resume_fucntion()调用的返回值是 lua_yield()的第一个传入参数.当你想要继续一个 协程的时候,你只需要调用 resume() 在你的 lua_State() 上,因为它已经在执行一个函数 (即先前出入的入口函数),所以你不需要再次传入...
5.7.5 使用this调用另一个构造器 5.8 静态成员 5.8.1 静态字段 5.8.2 静态方法 5.8.3 静态构造器 5.8.4 静态属性 5.8.5 静态类 5.9 扩展方法 5.10 封装数据 5.10.1 const 5.10.2 readonly 5.11 嵌套类 ...
第2章基本bean装配 2.1容纳你的bean 2.1.1beanfactory介绍 2.1.2使用应用上下文 2.1.3bean的生命 2.2创建bean 2.2.1声明一个简单的bean 2.2.2通过构造函数注入 2.3注入bean属性 2.3.1注入简单的数值 2.3.2...
第2章 生成、打包、部署和管理应用程序及类型 2.1 .NET Framework部署目标 2.2 将类型生成到模块中 2.2.1 响应文件 2.3 元数据概述 2.4 将模块合并成程序集 2.4.1 使用Visual Studio IDE将程序集添加到项目中 ...
第2章 生成、打包、部署和管理应用程序及类型 2.1 .NET Framework部署目标 2.2 将类型生成到模块中 2.2.1 响应文件 2.3 元数据概述 2.4 将模块合并成程序集 2.4.1 使用Visual Studio IDE将程序集添加到项目中...
第2章 使用变量、操作符和表达式 25 2.1 理解语句 25 2.2 使用标识符 26 2.3 使用变量 27 2.3.1 命名变量 27 2.3.2 声明变量 28 2.4 使用基本数据类型 28 2.4.1 未赋值的局部变量 29 2.4.2 显示基本数据类型...