Data field encapsulation and why is this important

  • The most important application of visibility (= accessibility) modifiers is:

      • data field encapsulation

  • Data field encapsulation is:

      • Making data fields in an object inaccessible (= private) to other classes

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

  • Why is this important:

      • If a data field is not private, program written by other programmers can tamper with the data field(s)

      • When other programs use a data field in an object directly, changing the implementation of the object is more difficult

What do you mean by:   change 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 many 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")

What can happen if you expose data fields (= public access)

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

public class Card
{
    public  String suit;
    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 you expose data fields (= public access)

This will allow programmers to write code that uses the data field directly:

public class Card
{
    public  String suit;
    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 you expose data fields (= 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 data fields are defined as private

public class Card
{
    private String suit;
    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 these data fields ?

Supporting data field encapsulation

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

public class Card
{
    private String suit;
    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 read a data field, we must provide a (public) mutator method:

public class Card
{
    private String suit;
    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;
    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;
    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 also update 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()  // Accessor method
    {   String[] suitToString = {"Spades", "Hearts", "Diamonds", "Clubs"};
        return suitToString[suit]; // Translates 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:   all 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()  // Accessor method
    {   String[] suitToString = {"Spades", "Hearts", "Diamonds", "Clubs"};
        return suitToString[suit]; // Translates 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/03-classes/19-encapsulation/ORIG + SOLUTION

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 data fields as private
      2. Provide a (public) accessor method and/or (public) mutator method to access 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 !