Data field encapsulation and why is this important

  • The most important application of the privite visibility (= accessibility) modifier is:

      • data field encapsulation

  • Data field encapsulation is:

      • Make a data fields in an object not directly accessible to other classes

        (which will prevent other classes from using the data fields directly)

  • Why is allowing direct access to data fields in an object undesirable:

      1. Direct access to data fields allows 3rd party programs to tamper with (= update) the data in the field(s) (security)

      2. Direct access to data fields prevents you from making improvements

        • When some program  P  use a data field in an object directly, changing the implementation of the object can cause program  P  to fail

What do you mean by:   changing the implementation of an object

  • A object has

      • Properties and they are represented by instance variables in the object

  • Change implementation = change the way we represent the properties of an object


  • Very important fact:

      • Properties of objects can be represented in different ways

    Example: the suit of a playing card can be represented as

           (1)  String suit;  ("Spades", "Hearts", 
                               "Diamonds", "Clubs")
       or:
      
           (2)  int    suit;  (0 = "Spades",   1 = "Hearts", 
                               2 = "Diamonds", 3 = "Clubs")

    Representing the suit as an int value make it easier to rank playing cards

What can happen if we expose data fields to direct (= public) access

Suppose we made the data fields in the Card class public:

public class Card
{
    public  String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    public  String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.suit.compareTo("Spades") == 0 ) ... } }

What can happen if we expose data fields to direct (= public) access

This will allow a program (myProg) to use the data fields directly:

public class Card
{
    public  String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    public  String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.suit.compareTo("Spades") == 0 ) ... } }

What can happen if we expose data fields to direct (= public) access

Then changing the implementation of the Card class will cause errors in the user program:

public class Card
{
    public  int    suit;   // 0="Spades", 1="Hearts", 2="Diamonds", 3="Clubs"
    public  String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.suit.compareTo("Spades") == 0 ) ... // Error: compareTo() } ^^^^^^ int does not have a compareTo() method ! }

Supporting data field encapsulation

Data field encapsulation requires that all data fields are defined as private:

public class Card
{
    private String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    private String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }

    public String getSuit()
    {
        return suit;
    }

    public void setSuit(String newSuit)
    {
        suit = newSuit;
    }
}

$64,000 question:   how can other classes use/access the data fields ?

Supporting data field encapsulation

When other classes needs to read some data field, we must provide a (public) accessor method:

public class Card
{
    private String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    private String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }

    public String getSuit()   // Accessor or "getter" method
    {
        return suit;
    }

    public void setSuit(String newSuit)
    {
        suit = newSuit;
    }
}

 

Supporting data field encapsulation

When other classes needs to write a data field, we must provide a (public) mutator method:

public class Card
{
    private String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    private String rank;

    Card(...) // Constructor to create a Card< object
    {
        ...
    }

    public String getSuit()   // Accessor or "getter" method
    {
        return suit;
    }

    public void setSuit(String newSuit) // Mutator or "setter" method
    {
        suit = newSuit;
    }
}

How will this help ???

How data field encapsulation allow us to change object implementation

Suppose we made the data fields in the Card class private:

public class Card
{
    private String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    private String rank;

    Card(...) { ... } // Constructor to create a Card< object

    public String getSuit()  // Accessor method
    {
        return suit;
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.suit.compareTo("Spades") == 0 ) ... } }

 

How data field encapsulation allow us to change object implementation

Then:   other classes must use an accessor/mutator method to access a data field:

public class Card
{
    private String suit;   // "Spades", "Hearts", "Diamonds", "Clubs"
    private String rank;

    Card(...) { ... } // Constructor to create a Card< object

    public String getSuit()  // Accessor method
    {
        return suit;
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.getSuit().compareTo("Spades") == 0 ) ... } }

 

How data field encapsulation allow us to change object implementation

Suppose we want to change the implementaion of the Card object:

public class Card
{
    private int    suit;   // 0="Spades", 1="Hearts", 2="Diamonds", 3="Clubs"
    private String rank;

    Card(...) { ... } // Constructor to create a Card< object

    public String getSuit()  // Accessor method
    {
        return suit;
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.getSuit().compareTo("Spades") == 0 ) ... } }

 

How data field encapsulation allow us to change object implementation

We can maintain compatibility by updating the accessor/mutator methods:

public class Card
{
    private int    suit;   // 0="Spades", 1="Hearts", 2="Diamonds", 3="Clubs"
    private String rank;

    Card(...) { ... } // Constructor to create a Card< object

    public String getSuit()  // Adjust accessor method
    {   String[] suitToString = {"Spades", "Hearts", "Diamonds", "Clubs"};
        return suitToString[suit]; // Translates suit number to string !
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.getSuit().compareTo("Spades") == 0 ) ... } }

 

How data field encapsulation allow us to change object implementation

Result:   other classes that use the Card class will still work correctly:

public class Card
{
    private int    suit;   // 0="Spades", 1="Hearts", 2="Diamonds", 3="Clubs"
    private String rank;

    Card(...) { ... } // Constructor to create a Card< object

    public String getSuit()  // Adjust accessor method
    {   String[] suitToString = {"Spades", "Hearts", "Diamonds", "Clubs"};
        return suitToString[suit]; // Translates suit number to string !
    }
}


public class myProg { public static void main(String[] args) { Card c1 = new Card( ... ); if ( c1.getSuit().compareTo("Spades") == 0 ) ... No error ! } ^^^^^^^^^^^ this will work like it used to ! }

DEMO: demo/10-classes/19-encapsulation/repr-1 + repr-2/Demo.java + Card.java

Summary

  • Data field encapsulation is:

      • Making data fields in an object inaccessible to other classes

  • Data field encapsulation is achieved In Java by:

      1. Specify all data fields as private

      2. Provide a (public) accessor method and/or (public) mutator method to access each of the data field

  • Advantage:

      • We can change the implementation of an object and still maintain compatibility with existing Java programs by:

        • Providing updated accessor/mutator methods that achieve the same effect as the old implementation !