封装形式

访问器方法(“设置程序和获取程序”)尝试隐藏有关如何存储对象中数据的详细信息。实际上,它们是一种以非面向对象的方式存储和检索数据的美化手段。访问器不能有效地封装任何内容,因为以下两段代码之间几乎没有实际区别:

Person bob = new Person();
Colour hair = bob.getHairColour();
hair.setRed( 255 );
和这个:
Person bob = new Person();
Colour hair = bob.hairColour;
hair.red = 255;

这两个代码片段都揭示了一个人与头发紧密耦合的想法。然后,这种紧密的耦合会在整个代码库中展现自己,从而导致软件变脆。即,很难改变人的头发的存储方式。

代替:

Person bob = new Person();
bob.setHairColour( Colour.RED );

这遵循了“告诉,不要问”的前提。换句话说,应该指示对象(由其他对象)执行特定任务。这就是面向对象编程的重点。而且似乎很少有人得到它。

两种情况之间的区别是:

在第一种情况下,鲍勃无法控制自己的头发变成什么样的颜色。非常适合喜欢红发的发型师,而不适合鄙视这种颜色的鲍勃。

在第二种情况下,Bob完全控制了他的头发将变成哪种颜色,因为在未经Bob许可的情况下,系统中没有其他对象可以更改该颜色。

避免此问题的另一种方法是返回不再与Bob耦合的Bob头发颜色的副本(作为新实例)。我发现这是一个优雅的解决方案,因为这意味着存在另一个类希望使用某人的头发进行的行为,该行为不再与该人本身相关联。这降低了重用代码的能力,从而导致代码重复。

隐藏数据类型

在Java中,不能有两个仅在返回类型上有所不同的方法签名,它实际上并没有隐藏对象使用的基础数据类型。如果有的话,您很少会看到以下内容:

public class Person {
private long hColour = 1024;
public Colour getHairColour() {
return new Colour( hColour & 255, hColour << 8 & 255, hColour << 16 & 255 );
}
}

通常,各个变量通过使用相应的访问器逐字公开其数据类型,并且需要重构以对其进行更改:

public class Person {
private long hColour = 1024;
public long getHairColour() {
return hColour;
}
/** Cannot exist in Java: compile error. */
public Colour getHairColour() {
return new Colour( hColour & 255, hColour << 8 & 255, hColour<< 16 & 255 );
}
}

虽然它提供了一定程度的抽象,但它是薄薄的面纱,对于松散耦合没有任何作用。

告诉,不要问

有关此方法的更多信息,请阅读告诉,不要问。

档案范例

考虑以下代码,该代码与ColinD的答案略有修改:

public class File {
private String type = "";
public String getType() {
return this.type;
}
public void setType( String type ) {
if( type = null ) {
type = "";
}
this.type = type;
}
public boolean isValidType( String type ) {
return getType().equalsIgnoreCase( type );
}
}

getType()这种情况下的方法是多余的,并且(在实践中)将不可避免地导致重复的代码,例如:

public void arbitraryMethod( File file ) {
if( file.getType() == "JPEG" ) {
// Code.
}
}
public void anotherArbitraryMethod( File file ) {
if( file.getType() == "WP" ) {
// Code.
}
}

问题:

数据类型。该type属性不能轻易地从String更改为整数(或其他类)。

隐含协议。这是耗时的抽象从特定类型(PNG,JPEG,TIFF,EPS一般的() ,IMAGE,)。DOCUMENTSPREADSHEET

引入错误。更改隐含协议不会产生编译器错误,这可能会导致错误。

通过阻止其他类请求数据来完全避免该问题:

public void arbitraryMethod( File file ) {
if( file.isValidType( "JPEG" ) ) {
// Code.
}
}

这意味着将getaccessor方法更改为private:

public class File {
public final static String TYPE_IMAGE = "IMAGE";
private String type = "";
private String getType() {
return this.type;
}
public void setType( String type ) {
if( type == null ) {
type = "";
}
else if(
type.equalsIgnoreCase( "JPEG" ) ||
type.equalsIgnoreCase( "JPG" ) ||
type.equalsIgnoreCase( "PNG" ) ) {
type = File.TYPE_IMAGE;
}
this.type = type;
}
public boolean isValidType( String type ) {
// Coerce the given type to a generic type.
//
File f = new File( this );
f.setType( type );
// Check if the generic type is valid.
//
return isValidGenericType( f.getType() );
}
}

当File类将隐式协议从特定类型(例如JPEG)转换为通用类型(例如IMAGE)时,系统中的其他代码都不会中断。系统中的所有代码必须使用isValidType方法,它不给类型调用对象,但讲述的File类来验证类型。