11.1. Adaptation

 <  Day Day Up  >  

Sam stopped by for coffee. "You know, I forgot one thing."

"What's that?" I asked.

"I'd really like to keep customers' addresses in the database," he said.

"Well, we don't have a database. That's an implementation issue you shouldn't be concerned with," I replied.

"OK, you got me. I want to be able to keep track of a customer's address so that I can send him mail," Sam stated.

"I think we can do that. You can have the staff enter each customer's address off your cards," I said.

"Yeah, but I also want to check whether my staff entered the addresses correctly. If they enter the wrong Zip Code, the post office might send the mail back. That's a waste," he stated emphatically.

"OK, we'll put Zip Code verification into the CD rental system," I said. "I'll look for a Zip Code verification system."

Then I asked, "What should the system do if the Zip Code is incorrect?"

He said, "Correct it," looking at me as if I were asking the dumbest question he had heard in the last year.

I followed it up with, "What should the system do if the Zip Code cannot be found?"

"Then I guess the user must have made a mistake, so we ought to ask him to correct it," he answered .

"What if the address is not in the Zip Code system yet?" I asked.

"Well, maybe you should keep track of that and try verifying it later," Sam replied.

Based on his responses, I came up with the following preliminary work case for the Zip Code verification system. A work case, as you might recall from Chapter 4, is a use case where the user is not a human, but another method:



Lookup_Zip_Code_for_address

  1. User supplies an address.

  2. If Zip Code is found for address, System replaces Zip Code in the address.

  3. Otherwise, System reports error

Of course, we need an Address to verify:

 class Address         {         CommonString line_1;         CommonString line_2;         CommonString city;         State state;         ZipCode zip_code;         } 

A class interface derived directly from the use case might look like Example 11-1.

Example 11-1. ZipCodeCorrectionService
 class ZipCodeCorrectionService     correct_zip_code_in_address(Address address_to_correct)         throws ZipCodeNotFoundException         // puts correct zip code into address_to_correct 

It is not ZipCodeCorrectionService 's responsibility to keep track of whether the system has verified the ZipCode . The best place to put that responsibility is in Address itself. The condition is a state of Address . So Address gets another attribute, appropriately set in the constructor. [*] We place the call to correct_zip_code_in_address( ) inside the verify_zip_code( ) method of Address :, as shown in Example 11-2.

[*] One reader questioned whether ZipCode should keep track of its own validity. You could take that approach. However, since you can determine the validity of a ZipCode only in the context of an Address , it seems more appropriate for the Address to keep the state.

Example 11-2. Address class
 class Address     {     boolean zip_code_verified = false;     static ZipCodeCorrectionService zip_code_correction =         new ZipCodeCorrectionService( );     verify_zip_code( ) throws ZipCodeNotFoundException         {         zip_code_correction.correct_zip_code_in_address(this);         zip_code_verified = true;         }     } 

Why keep a state of verification in Address ? You are going to ask the user again for the Zip Code, right? Who said the verify_zip_code( ) method is being called from a program that inputs the Zip Code from the user? Perhaps the method is being called to verify the Zip Code in a record in a database. Asking the database for a correction is tough. A service should not depend on the context in which it is called.

The correct_zip_code_in_address( ) method performs two operations that ought to be separated. The method looks up a ZipCode for an Address and then replaces the ZipCode in the Address . Separating these two operations creates another interface, ZipCodeVerificationService , as shown in Example 11-3.

Example 11-3. ZipCodeVerificationService interface
 interface ZipCodeVerificationService     {     ZipCode find_zip_code_for_address(Address address_to_check)         throws ZipCodeNotFoundException     } 

The method in this interface simply finds and returns the ZipCode for an Address . The correct_zip_code_in_address( ) method calls an implementation of this interface and puts the returned ZipCode into the Address , as shown in Example 11-4.

Example 11-4. ZipCodeCorrectionService
 class ZipCodeCorrectionService     {     static ZipCodeVerificationService zip_code_verification =         new ZipCodeVerificationServiceImplementation( );     correct_zip_code_in_address(Address address_to_correct)         throws ZipCodeNotFoundException         {         address_to_correct.zip_code = zip_code_verification.             find_zip_code_for_address(address_to_correct)         }     } 

At this time, Tim and I are not sure which implementation will provide ZipCodeVerificationService . We could purchase a Zip Code CD-ROM, subscribe to a Zip Code web service, or create an HTTP command for the U.S. Postal Service web site and decode the HTML response.

Whatever implementation we pick we will adapt to the ZipCodeVerificationService interface. Suppose that a third-party implementation already exists that performs a Zip Code lookup. The method in that module might look like this:

 String find_zip_code(String address1, String address2, String city, String     state);         // returns null if not found 

We show in Example 11-5 an implementation of ZipCodeVerificationService (Example 11-3) that calls this find_zip_code( ) method.

Example 11-5. ZipCodeVerificationServiceImplementation
 class ZipCodeVerificationServiceImplementation     {     ZipCode find_zip_code_for_address(Address address_to_check)         throws ZipCodeNotFoundException         {         String zip = find_zip_code(address_to_check.line_1,             address_to_check.line_2, address_to_check.city,             address_to_check.state);         if (zip == null)             throw new ZipCodeNotFoundException( );         ZipCode zipcode = new ZipCode( );         zipcode.from_string(zip);         return zipcode;         }     } 

ADOPT AND ADAPT

Create the interface you desire and adapt the implementation to it .


 <  Day Day Up  >  


Prefactoring
Prefactoring: Extreme Abstraction, Extreme Separation, Extreme Readability
ISBN: 0596008740
EAN: 2147483647
Year: 2005
Pages: 175
Authors: Ken Pugh

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