java.lang.reflect
even need them, especially dependency-injection tools (DI). Rarely they get JavaDoc, they are said to be "self-documenting" :-) This is also a problem when programming quickly via auto-complete in an IDE like Eclipse. The mass of names that show up when searching for a method is a real show-stopper. We'd liked only the really needed methods to be public!/**
* The inevitable ubiquitous undocumented anemic object, generated by some IDE.
* Any property can be modified from outside. This class encapsulates nothing.
* Public setters, once released in a big project, might be called by reflection
* and are not disposable anymore without risk.
*/
public class Contact
{
private String personName;
private boolean inCountry;
private String phoneNumber;
private String realm;
private int ranking;
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public boolean isInCountry() {
return inCountry;
}
public void setInCountry(boolean inCountry) {
this.inCountry = inCountry;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public int getRanking() {
return ranking;
}
public void setRanking(int ranking) {
this.ranking = ranking;
}
}
Much shorter, well-documented, much more encapsulation, less runtime-risks: an immutable object!/**
* An immutable value-object (data-transfer-object).
* No property can be modified from outside. This class encapsulates read-only data.
* Quick to read, easy to understand, safe against abuse, well-documented.
*/
public class Contact
{
/** The person this contact aims at. */
public final String personName;
/** True when the person is easily reachable in country. */
public final boolean inCountry;
/** The phone connection to the person. */
public final String phoneNumber;
/** The area of expertise the person can be asked about. */
public final String realm;
/** High when the person is a real expert in realm, low otherwise. */
public final int ranking;
public Contact(
String personName,
boolean inCountry,
String phoneNumber,
String realm,
int ranking)
{
this.personName = personName;
this.inCountry = inCountry;
this.phoneNumber = phoneNumber;
this.realm = realm;
this.ranking = ranking;
}
}
final
access modifier ensures that the field is not changed any more after construction.protected
or package-visible
. I decided for the package-visible
variant here, because I wanted to force any class that provides write-access to be in the same package. As we can see, this is immutable, no setters are present. Fields are not final, but well encapsulated. In the public constructor you could assert certain values to be not null.
package sample;
/**
* An immutable value-object (data-transfer-object).
* No property can be modified from outside. This class encapsulates read-only data.
* Package-visible fields prevent access from sub-classes outside this package.
*/
public class ContactData
{
String personName;
boolean inCountry;
String phoneNumber;
String realm;
int ranking;
/** Read-only constructor. */
public ContactData(
String personName,
boolean inCountry,
String phoneNumber,
String realm,
int ranking)
{
this.personName = personName;
this.inCountry = inCountry;
this.phoneNumber = phoneNumber;
this.realm = realm;
this.ranking = ranking;
}
/** Facilitate a write-access sub-class in same package. */
ContactData() {
}
/** @return the person this contact aims at. */
public String getPersonName() {
return personName;
}
/** @return true when the person is easily reachable in country. */
public boolean isInCountry() {
return inCountry;
}
/** @return the phone connection to the person. */
public String getPhoneNumber() {
return phoneNumber;
}
/** @return the area of expertise the person can be asked about. */
public String getRealm() {
return realm;
}
/** @return high when the person is a real expert in realm, low otherwise. */
public int getRanking() {
return ranking;
}
}
Now also dependency injection should be happy.
package sample;
/**
* A mutable data-transfer-object that provides write-access to all properties.
* In fact this does not encapsulate anything, but it reuses its super-class.
* So you can decide later whether a write-layer makes sense.
*/
public class ContactModel extends ContactData
{
/** For new objects getting values from UI. */
public ContactModel() {
}
/** For objects getting values from persistence. */
public ContactModel(ContactData data) {
super(
data.getPersonName(),
data.isInCountry(),
data.getPhoneNumber(),
data.getRealm(),
data.getRanking());
}
/** Sets the person this contact aims at. */
public void setPersonName(String personName) {
this.personName = personName;
}
/** Sets whether the person is easily reachable in country. */
public void setInCountry(boolean inCountry) {
this.inCountry = inCountry;
}
/** Sets the phone connection to the person. */
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
/** Sets the area of expertise the person can be asked about. */
public void setRealm(String realm) {
this.realm = realm;
}
/** Sets high when the person is a real expert in realm, low otherwise. */
public void setRanking(int ranking) {
this.ranking = ranking;
}
}
ɔ⃝ Fritz Ritzberger, 2014-09-01