Part 1 | Part 2
Defensive Copy is used in situations like when your class contain objects of other classes as its components and when those component classes are mutable.
It is programming technique whose purpose is to prevent the leaking out of references of component objects in your class to outside classes ( i.e client classes of your class.) so that client cannot use that references to change the internals (private attributes) of your class.
Note: Though it is named as Defensive Copy but it's purpose is not to copy the objects. It's purpose is to protect references in your class from outside access, hence it is a programming technique which uses the copying of object.
Lets first see what is the problem for which Defensive Copy is used.
Problem
Consider the following program.
Engine.java
Car.java
Client.java
In above code Car class contains an object of type Engine as its component and both Car and Engine classes are mutable classes.
In the constructor of Car you are doing shallow copy by copying only the value of reference variable otherEngine.
Similar thing you are doing in setEngine() method.
Now comes to main() method of Client class and note following statement:
Here you are changing engine location on engine object. But this statement has also changed the engine location of engine of car object, even you have not touched the car object . This is shown in following output:
Output:
Have you identified the problem?
The Car class is leaking the reference of its engine to its Client class. This is because you have done shallow copy in the constructor of Car. Due to which reference variable engine in main() and engine attribute of Car class both are refering to same Engine object. Therefore when you changed engine location of engine in main() , the engine location of engine of car also got changed.
Thus you have changed the private member of Car outside of it and without even touching its object, violating private member constraints.
Similar thing can happen through the setter and getter methods of Car as:
Reference leaking by Setters
Now change main() method of Client class as:
Output:
As seen from the output using setter on engine2 is also changing loaction of engine of car object.
change main()method of Client class as:
Output:
Now here getter has leaked out the reference of engine of car to Client class which we have stored in engine2 object. Later we have changed this engine2 which is also reflected in car object.
Lets see how Defensive copy solves this problem.
Solution
The Engine and Client classes are same as above, only Car class is changed to implement defensive copy technique.
Car.java
Client.java
In defensive copy you do not return or accept references of components directly in your methods. But instead you create a copy of your component object and use / return reference of this copy. Due to this original references of your components remains encapsulated in your class and cannot be accessed by outside classes.
Here in above code defensive copy is used at three places:
» Car constructor
» setEngine()
» getEngine()
Output:
As you are seeing now that this time engine location of engine in car object did not get changed by changing engine location in engine object.
Also try the two main() methods in section Reference leaking by Setters and Reference leaking by Getters to see the effect of setter and getter. You will find same output as above:
Output:
Part 1 | Part 2
Defensive Copy is used in situations like when your class contain objects of other classes as its components and when those component classes are mutable.
It is programming technique whose purpose is to prevent the leaking out of references of component objects in your class to outside classes ( i.e client classes of your class.) so that client cannot use that references to change the internals (private attributes) of your class.
Note: Though it is named as Defensive Copy but it's purpose is not to copy the objects. It's purpose is to protect references in your class from outside access, hence it is a programming technique which uses the copying of object.
Lets first see what is the problem for which Defensive Copy is used.
Problem
Consider the following program.
Engine.java
class Engine {
private String engineLocation;
Engine(String engineLocation){
this.engineLocation=engineLocation;
}
public void setEngineLocation(String engineLocation){
this.engineLocation=engineLocation;
}
public String getEngineLocation(){
return engineLocation;
}
}
private String engineLocation;
Engine(String engineLocation){
this.engineLocation=engineLocation;
}
public void setEngineLocation(String engineLocation){
this.engineLocation=engineLocation;
}
public String getEngineLocation(){
return engineLocation;
}
}
Car.java
class Car {
private String make;
private Engine engine;
Car(String make,Engine otherEngine){
this.make=make;
this.engine = otherEngine; /*Shallow copy. Leaking a reference*/
}
public void setMake(String make){
this.make=make;
}
public String getMake(){
return make;
}
public void setEngine(Engine otherEngine){
this.engine = otherEngine; /*Leaking a reference*/
}
public Engine getEngine(){
return engine; /*Leaking a reference*/
}
}
private String make;
private Engine engine;
Car(String make,Engine otherEngine){
this.make=make;
this.engine = otherEngine; /*Shallow copy. Leaking a reference*/
}
public void setMake(String make){
this.make=make;
}
public String getMake(){
return make;
}
public void setEngine(Engine otherEngine){
this.engine = otherEngine; /*Leaking a reference*/
}
public Engine getEngine(){
return engine; /*Leaking a reference*/
}
}
Client.java
/*Violating private variable constraint through Constructor*/
public class Client{
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
/*Violating private variable constraint*/
engine.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
}
public class Client{
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
/*Violating private variable constraint*/
engine.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
}
In above code Car class contains an object of type Engine as its component and both Car and Engine classes are mutable classes.
In the constructor of Car you are doing shallow copy by copying only the value of reference variable otherEngine.
Similar thing you are doing in setEngine() method.
Now comes to main() method of Client class and note following statement:
engine.setEngineLocation("Back");
Here you are changing engine location on engine object. But this statement has also changed the engine location of engine of car object, even you have not touched the car object . This is shown in following output:
Output:
Car Engine Location Before =Front
Car Engine Location After =back
Have you identified the problem?
The Car class is leaking the reference of its engine to its Client class. This is because you have done shallow copy in the constructor of Car. Due to which reference variable engine in main() and engine attribute of Car class both are refering to same Engine object. Therefore when you changed engine location of engine in main() , the engine location of engine of car also got changed.
Thus you have changed the private member of Car outside of it and without even touching its object, violating private member constraints.
Similar thing can happen through the setter and getter methods of Car as:
Reference leaking by Setters
Now change main() method of Client class as:
/*Violating private variable constraint through Setter Method*/
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
Engine engine2= new Engine("Front");
car.setEngine(engine2);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
/*Violating private variable constraint*/
engine2.setEngineLocation("back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
Engine engine2= new Engine("Front");
car.setEngine(engine2);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
/*Violating private variable constraint*/
engine2.setEngineLocation("back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
Output:
Car Engine Location Before =Front
Car Engine Location After =back
As seen from the output using setter on engine2 is also changing loaction of engine of car object.
Reference leaking by Getters.
change main()method of Client class as:
/*Violating private variable constraint through Getter Method*/
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
/*Violating private variable constraint*/
Engine engine2= car.getEngine();
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
engine2.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
/*Violating private variable constraint*/
Engine engine2= car.getEngine();
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
engine2.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
Output:
Car Engine Location Before =Front
Car Engine Location After =back
Now here getter has leaked out the reference of engine of car to Client class which we have stored in engine2 object. Later we have changed this engine2 which is also reflected in car object.
Lets see how Defensive copy solves this problem.
Solution
The Engine and Client classes are same as above, only Car class is changed to implement defensive copy technique.
Engine.java
class Engine {
private String engineLocation;
Engine(String engineLocation){
this.engineLocation=engineLocation;
}
public void setEngineLocation(String engineLocation){
this.engineLocation=engineLocation;
}
public String getEngineLocation(){
return engineLocation;
}
}
private String engineLocation;
Engine(String engineLocation){
this.engineLocation=engineLocation;
}
public void setEngineLocation(String engineLocation){
this.engineLocation=engineLocation;
}
public String getEngineLocation(){
return engineLocation;
}
}
Car.java
class Car {
private String make;
private Engine engine;
Car(String make,Engine otherEngine){
this.make=make;
/*Using Defensive Copy*/
this.engine = new Engine(otherEngine.getEngineLocation());
}
public void setMake(String make){
this.make=make;
}
public String getMake(){
return make;
}
public void setEngine(Engine otherEngine){
/*Using Defensive Copy*/
this.engine = new Engine(otherEngine.getEngineLocation());
}
public Engine getEngine(){
/*Using Defensive Copy*/
Engine engineTemp=new Engine(engine.getEngineLocation());
return engineTemp;
}
}
private String make;
private Engine engine;
Car(String make,Engine otherEngine){
this.make=make;
/*Using Defensive Copy*/
this.engine = new Engine(otherEngine.getEngineLocation());
}
public void setMake(String make){
this.make=make;
}
public String getMake(){
return make;
}
public void setEngine(Engine otherEngine){
/*Using Defensive Copy*/
this.engine = new Engine(otherEngine.getEngineLocation());
}
public Engine getEngine(){
/*Using Defensive Copy*/
Engine engineTemp=new Engine(engine.getEngineLocation());
return engineTemp;
}
}
Client.java
public class Client{
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
engine.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
public static void main(String args[]){
Engine engine= new Engine("Front");
Car car = new Car("Maruti",engine);
System.out.println("Car Engine Location Before ="+car.getEngine().getEngineLocation());
engine.setEngineLocation("Back");
System.out.println("Car Engine Location After ="+car.getEngine().getEngineLocation());
}
In defensive copy you do not return or accept references of components directly in your methods. But instead you create a copy of your component object and use / return reference of this copy. Due to this original references of your components remains encapsulated in your class and cannot be accessed by outside classes.
Here in above code defensive copy is used at three places:
» Car constructor
» setEngine()
» getEngine()
Output:
Car Engine Location Before =Front
Car Engine Location After =Front
As you are seeing now that this time engine location of engine in car object did not get changed by changing engine location in engine object.
Also try the two main() methods in section Reference leaking by Setters and Reference leaking by Getters to see the effect of setter and getter. You will find same output as above:
Output:
Car Engine Location Before =Front
Car Engine Location After =Front
Car Engine Location After =Front
Thus in above example you have used defensive to prevent the exposure of private member of class to outside classes.
Part 1 | Part 2
I would like to know your comments and if you liked the article then please share it on social networking buttons.
No comments:
Post a Comment