This is a discussion on How to organize-class/object relationship within the Software Patterns forums, part of the Testing category; I have to construct a service that client programmers will use, eventually, client programmer can see the service through one ...
|
|||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
How to organize-class/object relationship
I have to construct a service that client programmers will use,
eventually, client programmer can see the service through one interface and one class that will create and return references to particular implementation of that interface. public interface Customer { // decreases the customer account by value of volume void getMoney(double volume) // increases the customer account by value of volume void putMoney(double volume) // returns unique customer id String id(); } public class CustomerCreator { // creates particular impl. of the Customer based on id public Customer createCustomer(String id); public void destroy(Customer cust); } // handles Customer whose id's are "3[0-9].*" // This is a facade to subsystem that handles the group of these customers class CustomerImplOfType3 implements Customer { public void getMoney(double volume){} public void putMoney(double volume){} public String id(){} } // handles Customer whose id's are "7[0-9].*" // This is a facade to subsystem that handles the group of these customers class CustomerImplOfType7 implements Customer { public void getMoney(double volume){} public void putMoney(double volume){} public String id(){} } Based on "id" value, there are completely different ways(implementations) for handling customers and different subsystems are involved. CustomerCreator has to decide from which implementation to make instance. Customer implementations (Facades to subsystems) will increase over time and existing ones will change. Also I want to have possability to implement new CustomerImpls and to do not have to recompile neither the framework classes, neither the existing implementations (if they're still valid). CustomerCreator.createCustomer will throw "Notsupported" if there is no impelmentation that can handle given id. One approach is to create an array of prototypes of CustomerImpl, all of them will implement boolean canYouHandle(String id) and the CustomerCreator object shall iterate and ask every prototype, and to clone that one that will answer "yes(true)" So the implemenatation will look something like this: ---charging framework package--- package chargingfw; // Client programmers will use this interface to manipulate the customers public interface Customer { // decreases the customer account by value of volume void getMoney(double volume); // increases the customer account by value of volume void putMoney(double volume); // returns unique customer id String id(); } // subsystem programmers will use this interface to integrate subsystems in the application public interface CustomerFacadeBase extends Customer { public boolean canYouHandle(String id); public CustomerFacadeBase instance(String id); } public class CustomerCreator { ArrayList<CustomerFacadeBase> custPrototypes; public CustomerCreator(String[] listOfImpls) { for (each i in listOfImpls) { //load corresponding classes // create prototype instance custPrototypes.add(currenProto); } } // creates particular impl. of the Customer based on id Customer createCustomer(String id) throws Unsupported { for (each i in custPrototypes) { if (i.canYouHandle(id)) return i.instance(id); } throw new Unsupported(id); } void destroy(Customer cust); } ---Subsystem3 Facade Implemenation package--- // handles Customer whose id's are "3[0-9].*" // This is a facade to subsystem that handles these customers final class CustomerImplOfType3 implements CustomerFacadeBase { public CustomerImplOfType3(String id) { _id = id; init_subsystem(); } public void getMoney(double volume){} public void putMoney(double volume){} public String id(){} public CustomerFacadeBase instance(String id) { return new CustomerImplOfType7(id); } public boolean canYouHandle(String id) { if (id like "3[0-9].*") return true; return false; } private Subsystem3 ss; } ---Subsystem7 Facade Implemenation package--- // handles Customer whose id's are "7[0-9].*" // This is a facade to subsystem that handles these customers final class CustomerImplOfType7 implements CustomerFacadeBase { public CustomerImplOfType7(String id) { _id = id; init_subsystem(); } public void getMoney(double volume) {} public void putMoney(double volume){} public String id(){} public CustomerFacadeBase instance(String id) { return new CustomerImplOfType7(id); } public canYouHandle(String id) { if (id like "7[0-9].*") return true; return false; } private Subsystem7 ss; String _id; } It would be better if only one object instance per customer exists in the application, and all manipulation to go through that inctance for particular customer. ---client code--- // client code shall be multithreaded, import chargingfw; main() { String[] ssFacades = //subsystem facade class names CustomerCreator cr = new CustomerCreator(ssFacades); Customer cust = cr.createCustomer("3124455"); cust.getMoney(10); ... ... cr.destroy(cust); } My questions are: Is this approach good? Any suggestions for better design? Issues? Thanks, Ivan Sijakovski |
|
|||
|
Re: How to organize-class/object relationship
"ishijak" <ishijak@gmail.com> schrieb im Newsbeitrag news:1107784849.988717.113990@c13g2000cwb.googlegroups.com... > I have to construct a service that client programmers will use, > eventually, client programmer can see the service through one interface > and one class that will create and return references to particular > implementation of that interface. > > public interface Customer > { > // decreases the customer account by value of volume > void getMoney(double volume) > > // increases the customer account by value of volume > void putMoney(double volume) > > // returns unique customer id > String id(); > } > > public class CustomerCreator > { > // creates particular impl. of the Customer based on id > public Customer createCustomer(String id); > > public void destroy(Customer cust); > } > > > // handles Customer whose id's are "3[0-9].*" > // This is a facade to subsystem that handles the group of these > customers > class CustomerImplOfType3 implements Customer > { > public void getMoney(double volume){} > public void putMoney(double volume){} > public String id(){} > } > > > // handles Customer whose id's are "7[0-9].*" > // This is a facade to subsystem that handles the group of these > customers > class CustomerImplOfType7 implements Customer > { > public void getMoney(double volume){} > public void putMoney(double volume){} > public String id(){} > } > > Based on "id" value, there are completely different > ways(implementations) for handling customers and different subsystems > are involved. CustomerCreator has to decide from which implementation > to make instance. Customer implementations (Facades to subsystems) will > increase over time and existing ones will change. Also I want to have > possability to implement new CustomerImpls and to do not have to > recompile neither the framework classes, neither the existing > implementations (if they're still valid). > CustomerCreator.createCustomer will throw "Notsupported" if there is no > impelmentation that can handle given id. > > > One approach is to create an array of prototypes of CustomerImpl, all > of them will implement boolean canYouHandle(String id) and the > CustomerCreator object shall iterate and ask every prototype, and to > clone that one that will answer "yes(true)" > > So the implemenatation will look something like this: <snip/> > My questions are: > Is this approach good? > Any suggestions for better design? > Issues? If you have only a small set of sub systems, then I'd probably just have that many createCustomerTypeX(String id) methods and determine the appropriate method programmatically "if (id.startsWith("3") ... else if...". If it's more complex I'd have a factory for each subsystem and class CustomerCreator (better CustomerFactory) just delegates to the appropriate subsystem factory; the simplest approach would be to just iterate through all factories and ask each in turn whether it feels like handling this particular id (for creation) or instance (for deletion). You might also consider to put the delete method into the Customer interface because the customer can easily know its factory. Drawback is a certain degree of asymmetry between creation and deletion. Kind regards robert |
|
|||
|
Re: How to organize-class/object relationship
I think that is a reasonable approach.
Another option you might concider is meta data. Instead of i.canYouHandle(String Id) you could use configuration files to associate an id or pattern with a typename. <customerTypes> <add pattern="3[0-9].*" typeName="CustomerImplOfType3"/> ... </customerTypes> This could also become a source of (mis)configuration errors so sometimes its not worth adding flexibility where it isn't needed. However in this case perhaps it is appropriate, expecially with "magic numbers." Today it is 3[0-9], but tomorrow when decide to convert all there existing data to use an alpha prefix instead it becomes C[0-9], not only do you have to modify the code its also distributed across many class files. If you decide it is so unlikely to change you would rather modify the source code than maintain config files then using a if/else/switch statements in the factory would at least centralize the type mapping functionality. canYouHandle does not seem complex enough in this scenario to distribute the function to the various individual objects. If logic begins to get more complex and/or seperate properties are used to determine membership than asking the object canYouHandle might be more appropriate, and you should make canYouHandle virtual so if it for example you find that 3[0-9]* is actually 3([0-9]|[A-Z])* you can simply replace this method instead of creating a new implementation. - Kurt |