慎用缺省构造函数的一种场景

本文通过示例来谈谈慎用缺省构造函数的一种设计场景。——以JAVA为例展开讨论。

为了便于讨论,我们假定需要建模一个Student,包括姓名和出生地两个属性。我们看到不少下面的代码:

public class Student {
	private String name = null;
	private String birthPlace = null;

	public Student() {
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setBirthPlace(String birthPlace) {
		this.birthPlace = birthPlace;
	}

	public String getName() {
		return name;
	}

	public String getBirthPlace() {
		return birthPlace;
	}
}

使用的例子:

import org.junit.Test;

public class StudentTest {

    @Test
    public void test() {
        final String NAME = "John";
        final String BIRTH_PLACE = "Hawaii";
        
        Student student = new Student();
        student.setName(NAME);
        student.setBirthPlace(BIRTH_PLACE);
        
        assert(NAME.equals(student.getName()));
        assert(BIRTH_PLACE.equals(student.getBirthPlace()));
    }

}

通常的使用方法就是先用缺省构造函数new出一个对象,然后再调用每个属性的setter方法。

对于以上的设计方法,其适合的语义是:

  • 对象的每个属性可以有缺省值,而且缺省值是有意义的;
  • 对象的属性值是可变的,即可以通过setter来修改当前的属性值。

符合这种语义的对象非常多,比如表示(二维)平面上的一个点Point2d就适合用上面的设计方法。

本文讨论的是另外一种情况,即有如下语义要求:

  • 对应的每个属性没有合适的缺省值;
  • 一旦要创建一个对象,那么此时它的各个属性取值也是明确的;
  • 属性的值不可更改。

对于我们前面给出的Student例子,我们假定Name不能修改,如果有新的名字,就需要新增一个属性(如aliasName)来表示;而出生地也是固定的。对于这种情况,虽然前面给出的代码也能够较好地工作,但从设计语义上来讲,是不太合适的。

对于这种情况,通常推荐如下的做法:

  • 不提供缺省构造函数(C++中必须要定义或声明一个private的缺省构造函数);
  • 提供带参数的构造函数,参数列表包括了必须在创建对象时就要指定的属性值;
  • 对于不可修改属性值的数据成员,不能提供getter方法。

因此,前面的class Student需要重构成下面的代码:

public class NewStudent {
	private String name = null;
	private String birthPlace = null;

	public NewStudent(String name, String birthPlace) {
		this.name = name;
		this.birthPlace = birthPlace;
	}

	public String getName() {
		return name;
	}

	public String getBirthPlace() {
		return birthPlace;
	}
}

使用示例:

	@Test
	public void testNewStudent() {
		final String NAME = "John";
		final String BIRTH_PLACE = "Hawaii";

		NewStudent student = new NewStudent(NAME, BIRTH_PLACE);

		assert(NAME.equals(student.getName()));
		assert(BIRTH_PLACE.equals(student.getBirthPlace()));
	}

额外的好处:通过设计优化,我们在创建对象时,有3条语句变成了1条语句;如此,大脑的思考成本显著降低。

——要知道,通常一个项目都有大量的代码,数千上万是非常常见的事情。当遍地充斥着各种各样低质量语义的代码时,整个项目就会产生大量的无效代码,这对于项目维护是一件很可怕的事情。

我们写的每一行代码,都是在向读者(包括你自己)表达一种设计思想。可以工作的代码未必是质量优秀的代码,显然我们要追求的是后者。

慎用缺省构造函数的一种场景,布布扣,bubuko.com

时间: 2024-12-27 09:14:20

慎用缺省构造函数的一种场景的相关文章

C++基础:缺省构造函数

缺省构造函数,又称默认构造函数,是C++以及其他的一些面向对象的程序设计语言中,对象的不需要参数即可调用的构造函数.下面将针对缺省构造函数的定义.使用.以及注意问题等方面简要探讨. 1.缺省构造函数是怎样的形式?是如何定义的? 在C++的一个类中,如果构造函数没有参数,或者构造函数的所有参数都有默认值,就可以称其为缺省构造函数.一个类中,只能有一个缺省构造函数. 对于如下代码:构造函数MyClass()没有参数,就是MyClass的缺省(默认)构造函数. class MyClass { publ

[转载]关于隐式提供缺省构造函数的一个误区

很多C++的教材中都讲:“如果一个定义一个类,并且不提供任何构造函数的话,那么编译器将会隐式的提供一个缺省构造函数”. 以下节录ISO C++ 99的文档的原文: The default constructor (12.1), copy constructor and copy assignment operator (12.8), and destructor (12.4) are special member functions. The implementation will implic

More Effective C++----(4)避免无用的缺省构造函数 & (5)谨慎定义类型转换函数

Item M4:避免无用的缺省构造函数 缺省构造函数(指没有参数的构造函数)在C++语言中是一种让你无中生有的方法.构造函数能初始化对象,而缺省构造函数则可以不利用任何在建立对象时的外部数据就能初始化对象.有时这样的方法是不错的.例如一些行为特性与数字相仿的对象被初始化为空值或不确定的值也是合理的,还有比如链表.哈希表.图等等数据结构也可以被初始化为空容器. 但不是所有的对象都属于上述类型,对于很多对象来说,不利用外部数据进行完全的初始化是不合理的.比如一个没有输入姓名的地址簿对象,就没有任何意

最适合使用RxJava处理的四种场景

下面我们开始介绍RxJava最适合使用的四种场景,代码示例基于RxJava1 场景一: 单请求异步处理 由于在Android UI线程中不能做一些耗时操作,比如网络请求,大文件保存等,所以在开发中经常会碰到异步处理的情况,我们最典型的使用场景是RxJava+Retrofit处理网络请求 MyService myService = retrofit.create(MyService.class);myService.getSomething() .subscribeOn(Schedulers.io

(转)extern关键字两种场景的使用

第一种场景 -- extern extern关键字的作用是声明变量和函数为外部链接,即该变量或函数名在其它文件中可见.用其声明的变量或函数应该在别的文件或同一文件的其它地方定义. 例如语句:extern int a;仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间.变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误.通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明.例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需

为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?

名词解释 1.缺省构造函数:类的构造函数无参或参数默认值统称为缺省构造函数. 2.初始化列表:与其它函数不同,构造函数除了有名字,参数列表和函数体外还可以有初始化列表.列表以冒号开始后跟以逗号隔开的初始化字段.类成员是在构造函数的初始化列表创建好的,在创建类成员的同时,给成员变量一个初始化值. 在解释原因之前,需要了解构造函数是如何执行的 构造函数的执行过程 首先,构造函数的执行分为三步.先创建函数的形参(如果没有形参这步可以省略),然后执行初始化列表(即使没有初试化列表),最后执行函数体的内容

SharedPreferences 的另一种场景的用法

SharedPreferences 的另一种场景的用法 昨天,下班在家想做什么来着,然后想用SharedPreferences存点数据,但是不知道咋地突然想到,SharedPreferences是应用启动时一次性加到内存里的.适合少量的存储,多的话还是用数据库吧.实际项目中都是数据库,我私下写写demo就不搞那么麻烦了=.= 然后,问题来了,如果我要使用SharedPreferences,如何在比较小的单位里存储更多的信息. 好了,正题. 1. 昨天谷歌提供了国内的 android develo

C++中的const对象与缺省构造函数问题

先看一个“奇怪”的错误: #include <iostream> #include <stdlib.h> using namespace std; class A{ private: int sad; public: void f() const; void f1(); //A(int); //A(); }; void A::f() const{ cout<<"dfsdfds"; } void A::f1(){ cout<<"f

Spring-- Ioc 容器Bean实例化的几种场景

Bean实例化的几种场景 1.BeanDefinitionRegistryPostProcessor实例化:标准BeanFactoryPostProcessor的扩展,BeanFactoryPostProcessor的作用是用来进一步定义注册的BeanDefinition,IoC容器本质就是Bean管理,所以BeanFactoryPostProcessor本身也是Bean,要对BeanFactoryPostProcessor的BeanDefinition进一步定义就通过BeanDefinitio