CSC/ECE 517 Fall 2012/ch1 1w15 rt: Difference between revisions
Line 974: | Line 974: | ||
Access control provides powerful mechanism to implement various OO features and it can find its use in several applications. Having a proper understanding of different access control methods and using the proper access control techniques can help to control ambiguity and leads to easy maintainability of the code. However, if not used with caution, access control can lead to unexpected behavior. It is always important to use the right access control to avoid ambiguity and ease the maintainability of code. | Access control provides powerful mechanism to implement various OO features and it can find its use in several applications. Having a proper understanding of different access control methods and using the proper access control techniques can help to control ambiguity and leads to easy maintainability of the code. However, if not used with caution, access control can lead to unexpected behavior. It is always important to use the right access control to avoid ambiguity and ease the maintainability of code. | ||
=References= | =References= |
Revision as of 12:04, 14 September 2012
Access Control in O-O Languages
Introduction to Access control
In object oriented programming <ref name="Object oriented programming"> Object Oriented Programming</ref>, access control refers to the control of visibility of data and methods. The main idea behind access control is to restrict access to certain parts of the code to external entities. Access control implements and handles O-O features like encapsulation <ref name = "Encapsulation"> Encapsulation</ref> and inheritance <ref name = "Inheritance"> Inheritance </ref> by providing varying levels of access to code. The use of access control becomes necessary in any practical environment where selective access is a key criterion. For example, only the instructor can be allowed to modify grades of students but all students should be given access to retrieve and view their respective grades.
Access control in different object oriented languages and the underlying details will be covered in this topic.
Overview of Access Control Mechanisms
Each O-O language has a specific implementation of access control mechanisms. However, a plethora of the most widely used O-O languages share similar features while implementing access control. Access control mechanisms are applicable to class members like variables and functions. Some level of access control can be applied at the class level. The three basic types of access control implementation which is common to some static and dynamic O-O languages <ref name = "Static and dynamic O-O languages"> [1] </ref> [like C++, C#, Java and Ruby] are
Public : Methods or attributes that are declared to be public can be accessed from any class. This is the least restrictive access control method. For example, we may want everyone in a company to know the names of people working along with them. Thus public access is given to employee's name.
Private : This mechanism makes the data or method to be visible only in the class in which it is declared. The support is not extended to sub classes. This is the most restrictive access control method. In any application, methods which implement the core functionality or require administrator access are declared to be private thereby enforcing limited access. For example, only a manager can be given the authority to review an employee’s performance and award bonus and promotions.
Protected : The use of protected access allows access of data and methods to be modified by members belonging to the same family. This means that this support is extended to subclasses. Protected access control can be used to support the single interface, multiple implementation concept. For example, a super class may have a protected method called ComputeArea(). We can have many subclasses like Triangle, Rectangle etc inherit the super class and override the method ComputeArea() to provide their own specific implementation. In a more practical scenario, a person might be allowed to view the medical history of immediate family members. However, people outside the family will not be allowed access to view this medical history.
Access Control in O-O Features
Programming languages implement access control in different ways. The most prominent two ways are encapsulation and inheritance. We present a few of the languages that use access control and their implementation.
Encapsulation
In object-oriented programming, objects interact with each other by messages. The only thing that an object knows about another object is the object's interface. Each object's data and logic is hidden from other objects. In other words, the interface encapsulates the object's code and data. The below code snippets show how access control is implemented using encapsulation in various languages.
Java
In Java, access control is achieved using the modifiers public, private and protected. If a class is not declared with any modifier, then the default access becomes package-private i.e, any object within the package should be able to access this class.
Public Keyword – Other classes can modify public fields unless its declared as final <ref name = "Final keyword">Final </ref>. The syntax for declaring a variable/method public is as follows
public int x; public void print_Hello()
In the example shown below, the variable studentName is public and hence can be accessed in another class. Similarly, public methods like getName() etc become accessible by other classes.
Private Keyword – This keyword makes the class members private. Private members can only be accessed from within the class. They are not visible even in subclasses. However, visibility and access of private members is extended to nested classes. The syntax for declaring a variable/method private is as follows
private String EmpID; private void getEmpDetails()
In the example code below, the method setID is declared to be private. Hence, it cannot be accessed outside or in any subclass of the class Student.
Protected Keyword – This keyword when used before a class member makes that member visible to the elements residing in that class and its subclasses. However if the subclass is in a different package, then the protected member is visible only through inheritance. It cannot be accessed by the object of the parent class as the definition is in another package. The syntax for declaring a variable/method protected is as follows
protected int sides; protected void setArea(int sides)
In the example code below, the method setName is declared as protected. Hence, it can be accessed in any subclass of Student.
Default access level/Package – When no specific access control keyword is given, then the method or variable becomes accessible to all classes under a particular package. In the following example, the integer “packageVar” becomes accessible to all classes included in the package ‘TestPackage1’.
package TestPackage1 public class Student { public String studentName; public int studentID; private String unityIDpassword; int packageVar; public String getName() { return studentName; } public int getID() { return studentID; } protected void setName(String s) { studentName = s; } private void setID(int y) { studentID = y; } public static void main(String[] args) { Student Stu1 = new Student(); Stu1.setName("ABCD"); Stu1.setID(1230013); System.out.println(Stu1.getName() + Stu1.getID()); } } public class Student2 { public static void main(String[] args) { Student Stu2 = new Student(); Stu2.studentName = "Mickey"; //Public variable of another class can be accessed Stu2.packageVar = 5; //Default access level } }
C++
In C++, we have the three modifiers presented in the overview along with a special type of access control called friend. The behavior of public, private and protected modifiers is similar to its Java counterparts.
Friend - A function or class can access the private and protected members of a class if it is declared as a friend of that class.
class Number { int a,b; friend int canAccess(Number numb); // Declaring canAccess() to be a friend public: int add(int,int); protected: int diff(int,int); private: int prod(int,int); int add(int a,int b) { return a+b; } int diff(int a,int b) { if (a>b) return a-b; else return b-a; } int prod(int a,int b) { return a*b; } }; public static void main() { Number num; int a=10, b=20; cout << "Sum =" << num.add(a,b); cout << "Difference =" << num.diff(a,b); //cout << "Product = " << num.prod(a,b); // this will throw an error if the comments are removed } // Friend function int canAccess(Number numb) { cout<< "Product for a friend = " << numb.prod(10,20) }
More about friend functions
If a class is declared as a friend in another class, the friend class can access all the private members of the class. This can also be limited in such a way that only few private members of the class can be accessed. By using friend functions or classes, we can provide a flexibility of letting a friend class access restricted members of a class and still keeping the restricted members closed for access by any other class. This will be useful in a few cases.
Ruby
Ruby provides the three levels of access controls, private, public and protected with the default being public access. The behavior of public and protected access control is similar to other languages like C++ and Java.
However, private methods can be called only within the context of the current object. Other object’s private method cannot be invoked. Private methods can be overridden by the sub-classes.In most cases, private methods are used to provide internal functionality to the class. So we need to use a cautious approach in using private methods. If they are overridden by the subclass, we tend to get unexpected behavior in the program.
Note: Private methods cannot be called outside of the class. Private methods can be called only using the “send” method.
class Number def initialize(a,b) @number1 = a @number2 = b end def num1 @number1 end def num2 @number2 end def add(a) puts a.num1+a.num2 end def diff(a) puts a.num1-a.num2 end public:add public:diff protected:num1 #private:num2 end Num1=Number.new(50,60) Num1.add(Num1) Num1.diff(Num1)
This program runs successfully and prints the output as long as the private method is not accessed. Here, the private method is num2 and should not be invoked in the current context of the object.
in `add': private method `num2' called for #<Number:0x436e18 @number1=50, @number2=60> (NoMethodError)
However, the private method num2 can be accessed using the send method. The syntax for accessing the method is a.send(:num2)
C#
It has 5 specific levels of access control at the class member level.
1. Public : Public access is the least restrictive access level and class members can be accessed anywhere.
2. Private : Private is the most restrictive access level where members are accessed only in the body of the class in which they are declared. This support is also extended to nested classes.
3. Protected : The protected keyword is a member access modifier i.e, it cannot be applied at a class level. A protected member is accessible from within the class in which it is declared, and from within any class derived from the class that declared this member.
class Number { public int x =5; public int y =10; public int add() { return x+y; } protected int diff(){ return y-x; } private int prod(){ return x*y; } } class Number1 { public static void Main() { Number num = new Number(); num.add(); //access to add num.diff(); // can't as diff is declared protected num.prod(); // can't access as prod is private } } class Number2 : Number { public static void Main() { Number2 num2 = new Number2(); num2.diff(); // access to protected member } }
4. Internal : It is an access modifier for types and type members. Internal members are accessible only within files in the same assembly.
5. Protected Internal: This access control restricts access of members to the class, subclass within the assembly. The difference between protected internal and internal is that, a subclass of the class derived in another assembly can also access the protected internal method.
File1.cs: class Number3 { internal int x =0; protected internal int y = 0; } File2.cs class Number4 : Number3 { public static void Main() { Number4 num4 = new Number4(); num4.x = 4 // error, as x is declared as internal num4.y = 5 // Allowed. As y is protected internal. } }
PHP
In PHP the visibility of a property or method can be defined by prefixing the declaration with the keywords public, protected or private
1. Private : Private access specifier is used to hide the data member or member function to the outside world so that only the class that defines such data member and member functions have access to them.
2. Public : public access specifier allows the outside world to access/modify the data members directly unlike the private access specifier. In PHP all data members and member functions are public by default.
3. Protected : A protected access specifier is mainly used with inheritance. A data member or member function declared as protected cab be accessed by its class and its base class but not from the outside world (i.e. rest of the script). Thus a protected data member is public for the class that declares it and it’s child class; but is private for the rest of the program.
class Customer { private $name; public $surname; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } public function setSurName($name) { $this->name = $Surname; } public function getSurName() { return $this->Surname; } } } $c = new Customer(); $c->setName("Aron”); echo $c->name; //error, $name cannot be accessed from outside the class //$name can only be accessed from within the class echo $c->getName(); //this works, as the methods of the class have access //to the private data members or methods $c->setSurName("Ramsey"); echo $c->surname; // this will work as it is public.
Note:
Reflection Property in PHP5 helps in accessing protected and private methods.The setAccessible method sets a method to be accessible. So it can allow protected and private methods to be invoked
Python
Python implements access control in a different way from most other languages in that they don’t have specific access control modifiers. By default all members are public and we precede the member name with ‘__’ (a double underscore) to indicate if the member is private. This feature of python is called as Name Mangling.
There is no feature in python to implement the protected access control.
class Number: def __init(self,a,b): // this is a private method self.a = a self.b = b def add(): print self.a + self.b def diff(): print self.b - self.a Num1=Number(50,60) Num1.add() Num1.diff()
Note that in python the __init method is made to be private as default while programming.
More on Name Mangling in Python
Name mangling is a feature of python using which we indicate whether a member is private by just adding underscores, instead of using key words. When we program or debug, it is easier to note that the member is private and thus refrain from accessing it.
Eiffel
Eiffel has a different approach to access control compared to the previous object oriented languages like C++ and Java. It uses selective export, which means that different methods and attributes can have different access levels. Also, we can individually specify the access level for each method or attribute.
class Number feature{NONE} -- indicates nothing can access this code from outside of the class (private) a: INTEGER b: INTEGER initialize is do a := 10 b := 20 end end feature{ANY} -- indicates this method can be accessed from anywhere outside of the class(public) add: INTEGER is do Result := a+b end end feature{Number} -- indicates that this method can be accessed only by members of the class Number diff: INTEGER is do Result := b-a end end
More on feature:
Using feature, we can provide varying levels of access to a code in the class. And also we can provide the names of classes that are only allowed to access that part of the code. In the above example, the different access levels that features provide are explained in the comments.
Inheritance
Inheritance is a term specific to object-oriented programming, where a new class is created from an existing class. Inheritance (often referred to as subclasses) comes from the fact that the subclass (the newly created class) contains the attributes and methods of the parent class. The main advantage of inheritance is the ability to define new attributes and new methods for the subclass which are then applied to the inherited attributes and methods. Access control methods and specifiers play an important role in inheritance.
The following example illustrates this point and shows how access to the data members of a class are specified and controlled by the access modifiers.
UML Diagram of a BankAccount class is shown below.
The data members ‘accountNumber’, ‘routingNumber’ and ‘balance’ are maintained as private. Thus, an instance of a ‘Customer’ Object (say) cannot directly access or modify this data. Customer has to interact with the public behavior bundled in this module which allows him to view his account information and/or withdraw/deposit money i.e. his visibility of the class is only restricted to that which is made public by BankAccount Class
The following examples exhibit the use of the access specifiers and getter methods in inheritance for the mentioned Bank Account example in each O-O language implementation.
Java
public class BankAccount { String accountNumber; private String routingNumber; private Integer balance; //setter methods for accountNumber allows public acccess to it. public void setAccountNumber(String acNo){ this.accountNumber=acNo; } //setter methods for routingNumber allows public acccess to it. public void setRoutingNumber(String rtNo){ this.routingNumber=rtNo; } //setter methods for balance allows only 'protected' access to it (see definition). protected void setBalance(Integer bal){ this.balance=bal; } // Getter method allows accountNumber to be read publicly public String getAccountNumber(){ return this.accountNumber; } // Getter method allows routingNumber to be read publicly public String getRoutingNumber(){ return this.routingNumber; } // Getter method allows balance to be read only in in a 'protected' fashion (see definition). protected Integer getBalance(){ return this.balance; } public void showAccountNumber(){ System.out.println(this.accountNumber); } public void showRoutingNumber(){ System.out.println(this.routingNumber); } public void showBalance(){ System.out.println(this.balance); } public void withdraw(Integer amount){ this.balance-=amount; } public void deposit(Integer amount){ this.balance+=amount; } public static void main(String args[]){ BankAccount Steve = new BankAccount(); //public access to setRoutingNumber/getRoutingNumber Steve.setRoutingNumber("1234"); String steveRtNo=Steve.getRoutingNumber(); System.out.println(steveRtNo); //protected access to the method setBalance/getBalance Steve.setBalance(5000); System.out.println(Steve.getBalance()); } }
Class BankAccount in the above Java code has public getter/setter methods to access the private data member ‘routingNumber’. Thus, we can invoke these methods using an instance of the BankAccount object: Steve. The methods setBalance()/ getBalance() are protected. As can be seen, they behave like public methods if invoked in the same package. Protected methods act like private methods if invoked by any instance of a class outside the package. However, if there is a class ‘InternationalBankAccount’ in a different package such that:
public class InternationalBankAccount extends BankAccount { public String internationalBankAccNo; }
InternationalBankAccount Anna = new InternationalBankAccount(); Anna.setBalance(10000);
The above is a valid syntax and Anna can access protected member functions of the parent class. Data member ‘accountNumber’ has default access specifier. Default access specifier is used in Java to support package driven development. Thus ‘accountNumber’ can be accessed from anywhere within the package. However no classes from other packages can access ‘accountNumber’. Data member balance is a private data member and if it is invoked explicitly as follows,
Steve.balance=1000;
then the output would be an unresolved compilation error of the form:
Unresolved compilation problem: The field bankAccount.balance is not visible
C++
class BankAccount { private: char routingNumber; char accountNumber; protected: int balance; public: BankAccount(char *, char *); void changeAccountNumber(char *); void changeRoutingNumber(char *); void depositMoney(int); void withdrawMoney(int); friend void displayAccountInfo(); } BankAccount::BankAccount(char *rNo, char *accNo) { Strcpy(routingNumber, rNo); Strcpy(accountNumber, accNo); balance = 0; } BankAccount::void changeAccountNumber(char *accNo){ Strcpy(accountNumber, accNo); } BankAccount::void changeRoutingNumber(char *rNo){ Strcpy(routingNumber, rNo); } BankAccount::void depositMoney(int amount) { balance += amount; } BankAccount::void withdrawMoney(int amount) { balance -= amount; } // Friend function can access both the private and protected members // of BankAccount. void displayAccountInfo(BankAccount ba) { cout << “Account Number: ” << ba.accountNumber << endl; cout << “Routing Number: ” << ba.routingNumber << endl; cout << “Account Balance: ” << ba.balance << endl << endl; } // CheckingAccount inherits from BankAccount. Hence it can access only the // public and protected members of BankAccount. It cannot access the private // members of BankAccount. class CheckingAccount: public BankAccount { private: char accountType[20]; public: CheckingAccount(char *, char *); void resetBalance(); } CheckingAccount::CheckingAccount(char *rNo, char *accNo) { Strcpy(accountType, "Checking"); changeRoutingNumber(rNo); changeAccountNumber (accNo); balance = 0; } // Since balance is a protected field, it can be accessed by CheckingAccount CheckingAccount::void resetBalance() { balance = 0; } int main() { CheckingAccount ca("888", "999"); ca.depositMoney(100); displayAccountInfo(ca); ca.withdrawMoney(50); displayAccountInfo(ca); ca.resetBalance(); displayAccountInfo(ca); }
OUTPUT: Account Number: 888 Routing Number: 999 Account Balance: 100 Account Number: 888 Routing Number: 999 Account Balance: 50 Account Number: 888 Routing Number: 999 Account Balance: 0
The data members routingNumber, accountNumber are made private and balance is protected. This makes it impossible to directly access or change routingNumber, accountNumber from outside code. Access to these attributes are strictly through the public methods changeRoutingNumber() and changeAccountNumber(). However, private and protected members are accessible through friend functions, so displayAccountInfo() function is able to access all the mentioned fields. Since balance is protected, it can be accessed from a subclass (CheckingAccount) directly as shown above. But the private members have to be accessed through the functions changeRoutingNumber() and changeAccountNumber() instead of being accessed directly.
Thus, it purely at the discretion of the programmer to allow access to these data members through such accessor functions. In the absence of such accessors, there would be no way for any code outside the class to view/modify the private attributes.
C#
class BankAccount { public BankAccount(string accountNumber, string routingNumber, int balance) { this.accountNumber = accountNumber; this.routingNumber = routingNumber; this.balance = balance; } private string accountNumber; protected string routingNumber; private int balance; // accountNumber is private, so it can only be modified from within this // class. Also, since the following method is private, it can only be called // from within this class. So this field is truly private. private void setAccountNumber(string acNo) { this.accountNumber=acNo; } // routingNumber is protected, so it can be directly modified by objects of // a subclass. But the contents of this field are made accessible as public // so anyone can 'read' the value of this field. public string getRoutingNumber() { return this.routingNumber; } // Provides access to modify the private member balance, but this function // can only be called by subclasses (and from within this class). protected initBalance() { this.balance = 0; } // Provides access to 'read' the contents of the private field to everyone. public void getBalance(int balance) { return this.balance; } } class Customer : BankAccount { Customer(string accountNumber, string routingNumber) { this.accountNumber = accountNumber; this.routingNumber = routingNumber; initBalance(); } } class Startup { public static void main() { Customer cust = new Customer(“999”, “888”, 100); System.console.WriteLine(cust.getBalance); } }
The Customer class inherits from the BankAccount class. All protected data members and methods of BankAccount class are accessible directly by an object of the Customer class. The private fields such as accountNumber and routingNumber are not directly accessible. Thus it is possible to call only the initBalance and getBalance methods from Customer. The initBalance method cannot be called by anyone outside the BankAccount class.
PHP
<?php class bankAccount { private $accountNumber; private $routingNumber; protected $balance; # setter methods for accountNumber allows public acccess to it public function setAccountNumber($acctNumber) { $this->accountNumber = $acctNumber; } # setter methods for routingNumber allows public acccess to it public function setRoutingNumber($routeNumber) { $this-> routingNumber = $routeNumber; } #Getter method allows accountNumber to be read publicly public function getAccountName() { return $this->accountName; } # getter methods for routingNumber to be read publicly public function getRoutingNumber() { return $this-> routingNumber; } } class savingsAccount extends BankAccount{ # setter method for balance public function setBalance($bal;) { $this-> balance = $bal; } # retrieve balance..note that balance is a protected variable. function getBalance() { return $this-> balance } } ?> #Creating objects and initializing variables $ newAcct -> setAccountNumber(“1234343455”) $ newAcct -> setRoutingNumber(“23DDAS25”) $ newAcct -> setBalance(“1234343455”) #Accessing public data member echo "Savings Account Number is " . $ newAcct ->getAccountNumber() . '<br>'; echo "Routing number is = " . $ newAcct -> getRoutingNumber() . '<br>'; #Accessing protected data member echo "Balance in account is is = " . $ newAcct -> getBalance() . '<br>';
The SavingsAccounts class inherits from the BankAccount class. All protected data members and methods of BankAccount class are accessible directly by an object of the SavingsAccounts class. The private fields such as accountNumber and routingNumber are not directly accessible.
Comparison among different O-O languages
Java | C++ | C# | PHP | Ruby | Python | Eiffel | |
---|---|---|---|---|---|---|---|
Public | Can be accessed outside of class | Can be accessed outside of class | Can be accessed outside of class | Can be accessed outside of class | Can be accessed outside of class | Can be accessed outside of class | Can be accessed outside of class |
Protected | Access within the class and sub-classes | Access within the class and subclasses | Access within the class and subclasses | Access within the class and by inherited and parent classes. | Access within the class and subclasses | No protected access | Access can be given to only a few of the classes. |
Private | Cannot be directly accessed from outside the class. Can be accessed by nested classes. | Cannot be directly accessed from outside the class | Cannot be directly accessed from outside the class | Cannot be directly accessed from outside the class | Cannot be directly accessed from outside the class | Cannot be directly accessed from outside the class | Cannot be directly accessed from outside the class |
Special feature | Default access is package. Any class in a package can access if no modifier is given | friend functions(access of private to a specific friend class or method) | internal and protected internal | Reflection Property helps accessing private and protected methods | send method is used to access private members | Name Mangling(use of underscores to indicate access level) | Selective export using "feature" |
Basic guidelines on the usage of Access Control
As a good programming practice, the following guidelines can be used to implement access control mechanisms.
1. Use public access only if an interface for a class so that the data can be sent or modified based on external requirements.
2. Use of private is advisable whenever we program the internal structure of the program, like the constructors. Some languages, like Ruby make their variables private by default so that modifications from external entities are avoided.
3. Use public only for methods and constants that form part of the public API of the class. Certain important or frequently used fields can also be public, but it is common practice to make fields non-public and encapsulate them with public accessor methods.
4. Use protected for fields and methods that aren't required by most programmers using the class, but that may be of interest to anyone creating a subclass as part of a different package. Note that protected members are technically part of the exported API of a class. They should be documented and cannot be changed without potentially breaking code that relies on them.
5. Use the default (languages like Java) for fields and methods that are internal implementation details, but are used by cooperating classes in the same package. You cannot take real advantage of package visibility unless you use the package directive to group your cooperating classes into a package.
6. Use private for fields and methods that are used only inside the class and should be hidden everywhere else.
If you are not sure whether to use protected, package, or private accessibility, it is better to start with overly restrictive member access. You can always relax the access restrictions in future versions of your class, if necessary. Doing the reverse is not a good idea because increasing access restrictions is not a backwards-compatible change.
Design patterns for handling Access Control
The two most commonly used design patterns to handle access control are the private class data design pattern and the decorator design pattern.
Decorator design pattern
Decorator pattern is a design pattern attaches additional responsibilities to an object dynamically. It is required when we need to restrict access to an object’s property or method. The access is restricted based upon some set of rules or parallel set of rules. In such cases instead of having access control in the original object we leave the object unchanged and unaware of any restrictions. Rather we wrap the object in an access control decorator object.
We start with an interface which creates a blue print for the class which will have decorators, then implement that interface with basic functionalities. The constructor of this class assigns the interface type instance to that attribute. This class is the decorator base class. Now you can extend this class and create as many concrete decorator classes. The concrete decorator class will add its own methods. After/before executing its own method the concrete decorator will call the base instance’s method. The key to this decorator design pattern is the binding of method and the base instance happens at runtime based on the object passed as parameter to the constructor.
An example of decorator design pattern would be ice cream. You can create a basic ice-cream and then add flavors to it as you want. This will change the taste of the basic ice cream.
The UML diagram is as follows:
The code for basic ice cream class
public class SimpleIcecream implements Icecream { @Override public String makeIcecream() { return "Basic Icecream"; } }
And the decorator class will be
abstract class IcecreamDecorator implements Icecream { protected Icecream specialIcecream; public IcecreamDecorator(Icecream specialIcecream) { this.specialIcecream = specialIcecream; } public String makeIcecream() { return specialIcecream.makeIcecream(); } }
We can add a flavor as:
public class VanillaDecorator extends IcecreamDecorator { public VanillaDecorator(Icecream specialIcecream) { super(specialIcecream); } public String makeIcecream() { return specialIcecream.makeIcecream() + addVanilla(); } private String addVanilla() { return " + Vanilla flavored"; } }
If we want to add another flavor. We can do so by the code below
public class StrawberryDecorator extends IcecreamDecorator { public StrawberryDecorator(Icecream specialIcecream) { super(specialIcecream); } public String makeIcecream() { return specialIcecream.makeIcecream() + addStrawberry (); } private String addStrawberry () { return " + Strawberry flavored"; } }
We execute the pattern in the following fashion:
public class TestDecorator { public static void main(String args[]) { Icecream icecream = new StrawberryDecorator (new VanillaDecorator (new SimpleIcecream())); System.out.println(icecream.makeIcecream()); } }
The output will be Basic Icecream + Vanilla flavored + Strawberry flavored.
Similarly we can add as many flavors like chocolate or strawberry on top of basic ice cream. Thus we add additional responsibilities dynamically and restrict access to the objects properties.
Private class data design pattern
A class may expose its attributes (class variables) to manipulation when it is no more desirable, for example after the construction is done. Using the private class data design pattern helps in preventing this unwanted manipulation. A class may also have one-time mutable attributes that cannot be declared final. Using this design pattern allows one-time setting of those class attributes. The motivation for this design pattern comes from the design goal of protecting class state by minimizing the visibility of its attributes (data).
The intent of this private class data design pattern is to provide the following:
- Control write access to class attributes
- Separate data from methods that use it
- Encapsulate class data initialization
- Providing new type of final - final after constructor
The private class data design pattern seeks to reduce exposure of attributes by limiting their visibility. It reduces the number of class attributes by encapsulating them in single Data object. It allows the class designer to remove write privilege of attributes that are intended to be set only during construction, even from methods of the target class.The private class data design pattern solves the problems by extracting a data class for the target class and giving the target class instance an instance of the extracted data class. These can be achieved by following these procedures
1. Create data class. Move to data class all attributes that need hiding
2. Create in main class instance of data class
3. Main class must initialize data class through the data class's constructor
4. Expose each attribute (variable or property) of data class through a getter
5. Expose each attribute that will change in further through a setter
The following C# code illustrates an opportunity to use the private class data design pattern. The attributes radius, color, and origin should not change after the Circle() constructor. Note that the visibility is already limited by scoping them as private, but doing methods of class Circle can still modify them. Although marking attributes of classes as const (or final or ReadOnly in other programming languages) restricts their manipulation, the attributes above are set in the constructor and hence cannot be marked as such.
The excess exposure of the attributes creates a type of (undesirable) coupling between methods that access those attributes. To reduce the visibility of the attributes and thus reduce the coupling, we implement the private class data design pattern, as follows:
public class CircleData { private double radius; private Color color; private Point origin; public CircleData(double radius, Color color, Point origin) { this.radius = radius; this.color = color; this.origin = origin; } public double Radius { get { return this.radius; } } public Color Color { get { return this.color; } } public Point Origin { get { return this.origin; } } } public class Circle { private CircleData circleData; public Circle(double radius, Color color, Point origin) { this.circleData = new CircleData(radius, color, origin); } public double Circumference { get { return 2 * this.circleData.Radius * Math.PI; } } public double Diameter { get { return this.circleData.Radius * 2; } } public void Draw(Graphics graphics) { //... } }
The Circle class in the resulting code has an attribute of type CircleData to encapsulate the attributes previously exposed to all of the methods of the class Circle. That encapsulation prevents methods from changing the attributes after the Circle() constructor. Note, however, that any method of Circle can still retrieve the values of the encapsulated attributes.
Advantages and disadvantages of Access Control
Access control means exerting control over who can interact with a particular resource. Hence the proper usage of access control is desirable as it comes with its own merits and demerits.
Advantages of Access Control
Using access control allows a programmer to better protect the members and methods of an object from bad use. This process of protecting data and methods has the following advantages.
Makes maintenance of application easier: Complex and critical applications are difficult to maintain. The cost associated with maintaining the application is higher than that of developing the application properly. The concept of encapsulation which bundles data and related functions together as a unit called class, thus makes maintenance much easier on the class level. The rest of the code is not cluttered up by these data and methods and it also ensures that the rest of the code doesn’t interfere with them
Improves the understandability of the application: Keeping the code clean by using access control methods also leads to self-documentation and understanding. Other programmers having to use that class can figure out more clearly as to which part of the class they are supposed to access and which part they are not
Enhances Security: The access specifier acts as the key strength behind the concept of security and provides access to members of class as needed by users. This prevents unauthorized access. If an application needs to be extended or customized in later stages of development, the task of adding new functions becomes easier without breaking existing code or applications, thereby giving an additional security to the existing application
Disadvantages of Access Control
The disadvantages of access control are not really significant when the advantages are laid down. Nevertheless there are few shortcomings.
Extra lines of code: To implement access control we have to write more lines of code and there is no point in using them when the program requirements are that, it need not have any encapsulation and information hiding
Adds overhead: Access control can be avoided when the use of the system can be significantly simplified by allowing encapsulation to be violated under certain conditions. For example with ad-hoc queries the need of encapsulation is reduced as issues such as maintainability are not critical. Also there are cases where wrong/improper use of access control methods can cause the program to behave abnormally.
Increases compiler complexity: In order to provide techniques for encapsulation, compilers must implement late binding for methods and it makes the compiler more complex
Conclusion
Access control provides powerful mechanism to implement various OO features and it can find its use in several applications. Having a proper understanding of different access control methods and using the proper access control techniques can help to control ambiguity and leads to easy maintainability of the code. However, if not used with caution, access control can lead to unexpected behavior. It is always important to use the right access control to avoid ambiguity and ease the maintainability of code.
References
<references/>
- Object Oriented Programming
- Encapsulation
- Inheritance
- Access Control in Java
- Member Access Control in C++
- C++ friend functions
- Implementing friend functions
- Access Modifiers in C#
- Programming Ruby
- Access Control in Ruby
- Name Mangling in OO Langugages
- Name Mangling in Python
- Class Objects in Python
- Eiffel for Beginners
- More on Eiffel
- Into Eiffel By Ian Joyner
- Static and Dynamic Typing
- PHP5 Class Access Specifiers
- PHP Methods Visibility
- PHP reflection
- Encapsulation
- Access Control in OO Languages
- Programming languages comparision
- Decorator pattern
- Design patterns
- Decorator pattern java