Special

Clearance Sale!

We've been publishing for over five years now and it's time to clear out our inventory of back issues, so we're slashing prices!

RBD Magazines

Check out this amazing clearance sale of all our past issues. Missing some issues? This is a great time to complete your RBD collection. Save up to 40% off the regular price of our printed back issue packages. These prices are only good until the end of the year May 2008 and supplies are limited, so place your order today.

Article Preview


Buy Now

Print:
PDF:

Object-Oriented Thinking

Don't Use Strings

Use Classes That Express Your Design

Issue: 5.6 (September/October 2007)
Author: Charles Yeomans
Article Description: No description available.
Article Length (in bytes): 4,877
Starting Page Number: 41
RBD Number: 5615
Resource File(s): None
Related Web Link(s):

http://www.declareSub.com/

Known Limitations: None

Excerpt of article text...

If you have properties or variables in your code like TelephoneNumber as String, replace them with TelephoneNumber objects. You can get the compiler to do more work for you, and probably simplify your code. It is, of course, quite convenient to add String properties to a class to represent telephone numbers, zip codes, or any other sort of data that you need in the course of writing an application. But when you assign to a String variable, how do you know that it's a telephone number? Why, you don't, unless you validate the data to determine whether it has the correct form. Even then, all you know is that the data is syntactically valid. String, Integer, and other such datatypes are often referred to as "primitive" datatypes. You should think of them as building blocks for types that express the intent of your design. In REALbasic, one can define new types using classes, interfaces, or structures. For something like a telephone number, a class is the first choice. An immediate advantage of the introduction of a TelephoneNumber class is that the compiler can now tell you when you attempt to assign a TelephoneNumber to a ZipCode -- although the use of such classes will likely prevent you from making such an error in the first place. We expect, of course, to be converting between TelephoneNumbers and Strings, for storage, display in EditFields, passing to a modem, etc. We can use Operator_Convert to make this quite simple. A subroutine allows us to write dim t as TelephoneNumber = "867-5309". Sub Operator_Convert(theData as String) me.Data = theData End Sub Whether or not you would validate a TelephoneNumber depends on the application. I note, for example, that the Mac OS AddressBook application does not. In a situation where validation is appropriate, you could do the following. Sub Operator_Convert(theData as String) if me.IsValid(theData) then me.Data = theData else raise new UnsupportedFormatException end if End Sub I raise an exception if the String data is invalid. This is, in my opinion, far preferable to an IsValid property that one may or may not check. By raising an exception in response to bad data, we can be sure that an invalid TelephoneNumber object is never created. An Operator_Convert function allows us to write code like this. rs.Field("TelephoneNumber").StringValue = theNumber Here is the function. Function Operator_Convert() as String return me.Data End Function As implemented, a TelephoneNumber object behaves much like a String. In particular, it is immutable; that is, you cannot modify the state of the object once created. This is almost certainly what we want. Once created, you're not likely to need to modify a TelephoneNumber. You will, however, want to pass them around. Because TelephoneNumbers are objects, not structures, they are passed by reference (or, more precisely, references to the objects are passed by value). Because they are immutable, you do not need to worry about aliasing problems, as you do with, say, Date objects. And immutable objects are thread-safe. For some situations, a constructor is better than an Operator_Convert subroutine. Suppose you want to represent postal codes as objects, and you want to support multiple countries. And you want to validate them. This suggests that you might want to have a superclass PostalCode, and subclasses corresponding to countries. Since it is not always possible to infer the country from the postal code -- South Africa and Switzerland both use four-digit codes, for example -- you would probably want to write a class PostalCode, with subclasses corresponding to countries. A PostalCode class might be implemented as follows. Sub Constructor(code as String) if RaiseEvent IsValid(theData) then me.Data = theData else raise new UnsupportedFormatException end if End Sub IsValid is an event to be implemented in subclasses corresponding to countries. To return a string representation of a postal code, we can take the same approach. We add a function (or computed property) Value as String that calls a FormatCode event handler. This allows subclasses to format the code as appropriate. Function Value() as String return RaiseEvent Format(me.Data) End Function Observe that I am not making the Data property available to subclasses except through the event handlers. Part of the point of using events is to prevent superclasses from becoming dependent on or coupled to subclasses, and not making the Data property available is in keeping with this idea. Finally, I point out that using classes like TelephoneNumber instead of Strings forces you to consider your design more carefully, to get the right abstractions. As an exercise, you might ask yourself what an Address object should look like. For example, should City be a separate class?

...End of Excerpt. Please purchase the magazine to read the full article.

Article copyrighted by REALbasic Developer magazine. All rights reserved.


 


|

 


Weblog Commenting and Trackback by HaloScan.com