Effective Java Item 14: You can’t change the representation without changing the API

This is taken from Effective Java by Joshua Bloch-

<strong>Item 14 (or Item 16 in the Third Edition): In public classes, use accessor methods, not public fields</strong>

// Degenerate classes like this should not be public!

class Point { public double x; public double y; }

Because the data fields of such classes are accessed directly, these classes do not offer the benefits of encapsulation (Item 13).

You can’t change the representation without changing the API

What does the author mean by the last sentence? This statement is used many times in the same item. Please suggest.

The term exported API or API is to be interpreted as suggested by the author in the book

An exported API consists of the API elements that are accessible outside of the package that defines the API.

Answer1:

Well, this is fairly simple, assuming Point class.

class Point { public double x; public double y; }

Now, essentially x and y are representation of the Point in 2d plane. If one will decide to use it will look as following, for example:

Point p; p.x = 5; p.y = 10;

Since x and y declared public they accessible by everyone, therefore if one day you will decide to switch point representation to the radius and the angle on 2D plane, e.g.

class Point { public double r; public double angle; }

The code from the above will have to be also changed, meaning clients which uses your Point object will have to re-compile theirs code. Hence by declaring x and y as public you restricted yourself as those declaration now part of the Point API.

However better approach will be to encapsulate internal representation of the point into private point state and expose only required functionality:

class Point { private double x; private double y; // Computes norm2 of the point public double norm2() { return Math.sqrt(x*x + y*y); } }

Now one to use your Point class will be able to use only public API's in that case norm method, in a way similar to this:

Point p; // Init coordinates double norm = p.norm();

Finally if you would like to change internal representation, the client code won't be affected by your change contrary to the previous example.

Answer2:

The API consists of all the public methods and members.

The data members are part of the representation (or implementation).

Therefore, if you make the data members public, changing the representation also changes the API.

If, for example, you used public getters instead of public data members, you could change the representation without changing the API.

For example, here are two different representations with the same API:

class Point { private double x; private double y; public double getX () {return this.x;} public double getY () {return this.y;} } class Point { private InnerPoint p; public double getX () {return p.x;} public double getY () {return p.y;} }

This is only possible due to the data members being private (and therefore not part of the API).

Answer3:

You can't rename the fields or change them to private to provide encapsulation.

The code using this API is written using point.x rather than point.getX()

Answer4:

It means when you have public fields your fields (your representation) are the API itself and when you change the fields the API changes as well.

Had you public getters for private fields, you would be free to play with the private fields you have and your API (your public methods) could remain just as they were.

Answer5:

The author means that you cannot change how data is stored and decisions about how data is represented like what kind of container you use without changing the API. For example if you decide that you want to use a point class rather than a double to represent x and y, you will need to change all the consumers of your class (changing the API of your class).

Answer6:

You can’t change the representation without changing the API

In the context means that once shared if you tend to change the attributes of the class defined as such. It's not feasible without changing the existing API definition. For example :-

class Point { public double x; public double y; // accessors double getX() { return this.x; } double getY() { return this.y; } } class Graph { void draw(Point point) { double x = point.x; // what if you decide this should be 0 if y is not 0? }

Instead, if you would have used the getX() getter there, you could have put that logic within Point class as

double getX() { if(p == 0) return 0; return this.x }

without any changes in the implementation in Graph.

人吐槽 人点赞

Recommend

Comment

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:Effective Java Item 14: You can’t change the representation without changing the API