3.4 Access Modifiers

only for RuBoard

Everything that comprises a class is associated with an access modifier that determines the scope or visibility of the entity in question. This is where the art of object design lies. Beyond the semantics of declaring member data and methods , an understanding of these access modifiers is crucial. Each modifier has a few basic guidelines geared toward designing robust, object-oriented code. Figure 3-2 shows the relationships between the four basic modifiers: Public , Private , Protected , and Friend .

Figure 3-2. Access modifier relationships
figs/oop_0302.gif
Public

Public classes are visible to everyone and not restricted in any way. Public members are visible inside and outside the class in which they were declared.

Member variables are not typically defined with public scope because this definition would allow unrestricted access to an object's state. In solid OO designs, member variables are kept private.

Private

Private classes can only be nested within another class and are completely restricted outside of that scope; it is not possible to declare a standalone class with this modifier. Private classes encapsulate functionality that is specific to the class where they were declared.

Private member variables are accessible only within the current class where they were declared. Even derived classes do not have access to Private members; they can be accessed through properties.

Private is the most restrictive modifier.

Protected

Protected access is similar to Private . Like private classes, protected classes can be nested only within another class. Unlike private classes, protected classes are accessible from derived classes.

Protected member variables are also accessible from derived classes. Think of protected member data as "private within the inheritance tree." This modifier should be used only in rare circumstances when it is applied to member data.

Friend

Friend classes are available only within the scope of the program where they are defined. They are suitable for encapsulating functionality that is shared across an assembly.

Friend variables and methods are available from all classes defined in the same assembly, but they are not visible externally. It is common to use Friend access at the method level to allow inter-object communication. However, declaring member variables with Friend access should be a rare event. Allowing another class to have such intimate access to member data is not advised.

Protected Friend

This modifier has the attributes of both Protected and Friend .

Shared

Shared is an access modifier specific to member data and methods; classes cannot be shared. Shared member function methods and member data are not associated with a particular class instance (although they can be called through a class instance). The String class, for instance, contains a shared method named Format that is used to format strings:

 Dim newString As String newString = String.Format("Formatted Number: {0}", num.ToString( )) 

Shared has the same meaning as static in C#, C++, and Java.

When using access modifiers, you should treat member data differently than member functions. Visual Basic, like all languages, gives developers a certain amount of rope to hang themselves . For instance, member data can be declared with all the access modifiers that were discussed (such as Public , Private , Protected , and Friend ). These modifiers have their place when it comes to class and method declarations; however, member data for classes should always be private .

Remember that this rule does not apply to constants or enumerations belonging to a class. These constants and enumerations are public and shared by default and define qualities that apply to every class instance.

3.4.1 Public Methods

Public methods and properties define your object's interfacei.e., how users will interact with your object. It designates unrestricted access. With that said, this modifier should be used as little as possible. Public interfaces should be minimal to allow flexible class designs. [1] This means using the fewest number of public methods (with the fewest number of parameters) required to meet the object's design goals.

[1] In this context, the term "interface" refers to the public methods and properties exposed by a class.

Hiding as much information as possible should be a paramount concern when designing a class, because hidden information can be changed easily without affecting the clients of the class. OOP emphasizes the idea of separating the interface from the implementation. Public interfaces are one way to express an implementation, so take care when determining what the outside world will see.

For instance, exposing a ConnectToDatabase method on an object would not be a good idea. A client should not be concerned with the fact that a database even exists; this behavior should be abstracted away in the application's data services tier . If the data source becomes an XML file at a later date, this method would have no meaning in the new context. Simply removing the method definition could render derived classes useless.

Before making a method public, determine if the class can handle the work instead. If a class requires the client to make a sequence of calls to accomplish a task, the abstraction is probably flawed. A method should not be made public simply because "it makes things easier." It can be a short-term solution like duct tape, but in the long run, the object hierarchy ends up having more holes in it than a piece of Swiss cheese.

Public interfaces represent a contract of sorts. Remember that once code that uses the public interface of an object is written, that interface should be considered published . What happens to all objects that rely on the existence of a published interface when that interface is changed, a parameter is added, or the return type is changed? The relationship is destroyed . Code won't compile, and many classes need to be rewritten as a result.

Don't change published interfaces.

3.4.2 Private Methods

Private methods are used for behaviors that should not be exposed outside of the class. They usually handle details that clients should not have to worry about. They simplify an abstraction, which is the primary goal of any class design.

Take a hypothetical CreditCard object. This object contains data that not everyone in the company should see, so before the object persists itself to the database, it must encrypt all of its member data. However, a developer should not have to know this detail. What if the Encrypt method is not called before the call Save ? The data would be unencrypted when it was written to the database, available to all prying eyes.

The appropriate way to handle this situation is to have a private method that is called from Save and handles the encryption, as shown in the following code:

 Public Class CreditCard         Private ccNumber As String  Private Sub Encrypt( )  '  Secret algorthim   End Function  Public Function Save( ) As Boolean  Encrypt( )  '       'Persist to database here       '     End Function         Public ReadOnly Property CardNumber( ) As String       Get         Return ccNumber       End Get     End Property     End Class 

This solution frees the developer from one more implementation detail. Breaking the encryption routine out into a private method, rather than doing it right from Save , is good modular design. It allows you to substitute new encryption routines without having to rewrite any code. Remember, the more you can hide from the users of your objects, the better (even if that user is you).

3.4.3 Protected Methods

Protected methods are available from the class where they are declared, as well as from any derived classes. In terms of visibility, protected methods lie somewhere between public and private. They aren't as restrictive as private methods, but they aren't quite as open as public methods. Like the Public modifier, Protected should be used with caution. Does a child class definitely need access to the parent implementation? Nine times out of ten, the answer is No.

However, the best reason to use a protected method is when a child class needs to do the same thing as a parent class, but in a different way. Consider the CreditCard class. As with the Encrypt routine, there is also a routine that validates the card number. Like Encrypt , the validation routine will be called within the class, perhaps when the class is created:

 Public Class CreditCard       Private ccNumber As String       Private Sub Encrypt( )     'Secret algorthim   End Sub       Public Function Save( ) As Boolean     Encrypt( )     '     'Persist to database here     '   End Function       Public ReadOnly Property CardNumber( ) As String     Get       Return ccNumber     End Get   End Property       Protected Overridable Function Validate( ) As Boolean     'Validate number here   End Function     End Class 

Ignore the Overridable keyword until the next chapter. For now, just understand that it means a derived class has permission to rewrite the method.

Derived classes want to validate a credit card in different ways. Visa, for instance, has components that can be used to verify their cards. A Visa card class might call these routines during Validate , but a MasterCard object would not. Because the method is protected and overridable, a derived class can write its own version. The Validate routine remains hidden outside of the class hierarchy, but the ccNumber data member remains private. Derived classes use the public CardNumber property to access the number.

3.4.4 Friend Methods

Friend access provides a way for classes to communicate with one another on an assembly-wide basis. This communication is usually necessary when you don't want to expose a relationship through a public class interface. It is not uncommon for the Friend modifier to be discussed in terms of family secrets. Everyone in the assembly knows, but client code doesn'tmuch as the whole family knows that dad has a new toupee, but not everyone in the outside world knows (because it's a really well-made toupee from Hong Kong).

One scenario involves two classes: ShoppingCart and Order . These classes run the shopping cart and order processing portions of an Internet commerce site. Both ShoppingCart and Order need to access the items they contain: a collection of Item objects.

Suppose you always want an Item to be associated with either a ShoppingCart or an Order . That is, it can't exist by itself; it has to have a relation to either an order or the shopping cart. You can create this association by giving the item class constructor (see Section 3.7 later in this chapter) Friend access:

 Public Class Item          Friend Sub New(...)             'Initialize object here         End Sub     End Class 

This access prevents code outside the assembly from creating an Item . However, orders and shopping carts can create items all day long. The item class might also have several methods with friend-level access that could be called between ShoppingCart and Order . Friend access is similar to Protected access between two unrelated classes.

You should watch out for some things in this situation. Classes that participate in relationships like these are known as cliques and should be kept to a minimum to prevent dependencies. Each new relationship adds complexity to the overall system.

3.4.5 Protected Friend Methods

The Protected Friend modifier provides both protected and friend visibility. It is almost like a union of the two. As shown in Figure 3-3, nonderived classes in another assembly have friend access; however, in the declaring assembly, derived classes have protected access.

Figure 3-3. Protected Friend access
figs/oop_0303.gif
only for RuBoard


Object-Oriented Programming with Visual Basic. Net
Object-Oriented Programming with Visual Basic .NET
ISBN: 0596001460
EAN: 2147483647
Year: 2001
Pages: 112
Authors: J.P. Hamilton

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net