tags:

views:

99

answers:

4

Let's say I have a class Customer, which has a property customerType.

I have another class called something like SpecialContract, which has a Customer and some other properties.

If customer.customerType == SPECIAL, then there is a SpecialContract which has a reference to this particular Customer.

Now I realize that this is a bit hoaky, but I do not want to maintain a relationship from Customer to SpecialContract for a few reasons, one being that most of the time when working with Customers we don't need to load up SpecialContracts and all of the other data associated with SpecialContracts. However, I do always want to know if a Customer has a SpecialContract, and this is achieved through its customerType property.

Ok, here's the hard part. I don't want the client to be able to set customerType, because just doing so will not remove the SpecialContract that applies to the Customer, which would be required. I would rather force the client to call a service method to remove the SpecialContract, which would also set the customerType to NOTSPECIAL all in one transaction.

How can I hide the customerType setter from clients, but still expose it to my service layer class that will be responsible for setting the correct value and also removing the SpecialContract? My service class is not in the same package as the Customer class.

A: 

Why not do a scan on the system at start-up looking for all Customers which have references in SpecialContracts, storing a list of all these Customers somewhere private within, say, the service layer somewhere?

Beau Martínez
I'm not sure that addresses the problem. The problem is maintaining the consistency of Customer.customerType and SpecialContract.customer. If the customerType setter is private, then I can't change it in my service layer when a SpecialContract is destroyed. If it's public, then the client can set Customer.customerType to NOTSPECIAL and persist it without destroying (immediately) the corresponding SpecialContract. I think I have to scrap this approach.
Boden
+1  A: 

Maybe aspect-oriented programming can be of some use here. You can intercept a call to a Customer that passes a Contract, have the before method advice instantiate a Special Contract subclass given certain conditions, and pass that to the method. You just have to design the Contract hierarchy so that it strictly observes the Liskov substitution principle.

AOP could turn this into a bloody impossible mess, but it's a different way to think about it. You can add as many rules as you'd like and turn them off or on declaratively.

duffymo
Interesting, thanks. I think I'd end up turning that into a bloody impossible mess though :)
Boden
+1  A: 

You could create an Interface that Customer implements, and pass an instance of this Interface to the client. This Interface would not expose the contentType modifier to the client. Your service would deal with full-fledged Customer objects and could use the setContentType modifier as defined in the Class.

akf
Very nice idea, thanks!
Boden
+1  A: 

I wouldn't try to hide the setter from your client. Rather, if the client modifies the state of a Customer and tries to persist it, you should perform a check to see if the SpecialContract / customerType was changed inappropriately and perhaps throw an exception if it was. You can then create the method you referred to earlier that is able to update the SpecialContract / customerType appropriately.

Overall I think it would be much safer to perform this check close to the persistence layer so that it's responsible for ensuring the data is correct just before it's saved rather than taking whatever data is sent over and blindly persisting it.

cliff.meyers