Say I have a class called Truck
and one of the private member variables is of class Wheel
. A getter for the Wheel
variable, getWheel
, would return a reference to it, as follows:
class Truck{
private Wheel wheel;
Truck(){
wheel=new Wheel();
}
Wheel getWheel(){
return this.wheel;
}
}
class Wheel{
int color;
}
Now, whoever calls getWheel
will be able to modify the private member object at will:
class me{
public static void main(String[] args){
Truck ye=new Truck();
Wheel v=ye.getWheel();
v.color=2;
}
}
This would defeat encapsulation, wouldn't it?
What would be the right remedy for this?
The usual approaches are:
Wheel
) Wheel
immutable (any time you want to change it, you create a new one instead, constructed with the new color) Wheel
, return an immutable interface on Wheel
that only exposes getters, no mutation operations public
for the getter. Then classes within the package could set the color of Wheel
, but classes outside the package cannot. (I prefer #3 in this situation for the clear separation, but this works too if you're crossing a visibility boundary.) That third option is one of the reasons why making instance variables (fields) non- private
is often considered poor practice.
Here's #3 in more depth, just because it's more complicated than #1 and #2, not because it's necessarily better (it isn't, design choices are made in context).
A read-only interface, typically public or package-private depending on how you're going to use all of this stuff:
public interface Wheel {
int getColor();
}
The concrete class, typically package-private (could be a private static nested class within Truck
if that's the only place it's used):
class WheelImplementation implements Wheel {
private int color;
WheelImplementation(int color) {
this.color = color;
}
public int getColor() {
return this.color;
}
void setColor(int color) {
this.color = color;
}
}
Truck
, typically same visibility as Wheel
:
public class Truck {
private WheelImplementation wheel;
Truck(){
this.wheel = new WheelImplementation(/*...initial color...*/);
}
Wheel getWheel() {
return this.wheel;
}
}
Sure, that can be defeated through reflection, but generally you design an API for use, rather than for abuse. :-)
You can make a private/package setter for wheel color. Also, initialize the color in the constructor which would help you do that.
And like other answers, returning a copy of Wheel is also a good way to do this.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.