2

I have a communication class that incapsulates all the apis of a remote application. This class happens to be a delegate class because it is interchangeable with another one (the remote application has two different channels).

This class has a number of topics (eg: acknowledge, people, invoices, duedates, payment methods, queues), and each topic has a number of methods (setOne, getOne, getAll, doSomething...). The number of topics is raising rapidly recently, from 1-2 to 6 and possibly more in the future.

Considering that the class itself needs some scaffolding methods (configuration, startup, authentication...) and each topic needs some auxiliary protected method, the total projected number of method is rasing beyond my confort zone.

If this class wasn't itself a delegate class, I would have implemented this solution: a class for each topic, each making use of the common class, and if necessary of the others. But the client code wants to be given just ONE class to which make requests.

One option is to make a single delegate class with lots of relay methods to composite objects. But I don't feel this is very far from swallowing the frog and just have a big class full of stuff.

Are there other solutions?

I'm working in php and I colud leverage the ___CALL meta method: class accepts any message and then looks up (via reflection) if it has an auxiliary class to relay the calling. This could be smart, but I would leave this solution for emergencies.

4
  • What prevents the delegate class from simply being a composition class containing all the other smaller classes? Is that what you're already doing? That would qualify it as a "View Model" class, of sorts, which is a perfectly acceptable technique. You haven't told us what problem, if any, you're trying to solve yet (I don't mean the "problem" of too many responsibilities, I mean the actual problem that this is causing in your business domain). – Robert Harvey Oct 30 '15 at 5:37
  • When you say it has different channels, do you mean there are two ways of communicating, but the data passed is essentially the same? For example, you could get data via a JSON call to a webservice or via a SQL query to a database. To me these are different 'channels' but return essentially the same data, albeit in a different format. – JDT Oct 30 '15 at 8:15
  • @Robert Harvey: no problem with composition, but I don't like the idea of stuffing my class with simple relay methods; it would be of little benefit over hosting the real method in the file. The only problem I want to address is lines of code and number of methods inside a single class. – Vittorio Zamparella Oct 31 '15 at 12:37
  • @JDT: yes, you got it right. An old api via POST and a new via JsonRpc, which begin beeing essentially the same. – Vittorio Zamparella Oct 31 '15 at 12:39
1

You need to write methods in three dimensions, so to speak: Channel, topic and operation. I once solved a similar problem by combining the the commands from [1] with (abstract) factories [2].

The basic idea is to write one Command-Class for each combination of (channel, topic, operation) which all have a common interface. In your case something like

Response sendRequest()

seems reasonable.

Furthermore every Command-Object needs all resources readily available as member to perform it's task. The details of acquiring those resources and setting up a specific command with it, is encapsulated in the corresponding factories. With clever type hierarchies of the actual commands and factories you can separate common from specialized code.

Let me do a bit of sketching and try to clarify what I mean:
Let's assume you want to list all (operation) people (topic) with last name 'Jackson' (operation) as an XML (channel) request, the client code would look something like this:

$xmlCommandFactory = CommandFactories.createFactory('XML'); // returns specific factory for channel; Specific factories share same interface
$peopleCommandFactory = xmlCommandFactory->createPeopleFactory(); // returns specialieced factory for topic
$command = peopleCommandFactory->createListByLastName('Jackson'); // creates specific command with specific parameter
$response = command.sendRequest(); // executes command

This makes for a lot of abstraction and boiler plate code. However, the beauty of the multiple layers is, that each layer deals with only one dimension. For example if I wanted the same thing as a Json-Request the code would look like this:

$xmlCommandFactory = CommandFactories.createFactory('JSON'); // returns specific factory for channel; Specific factories share same interface
$peopleCommandFactory = xmlCommandFactory->createPeopleFactory(); // returns specialieced factory for topic
$command = peopleCommandFactory->createListByLastName('Jackson'); // creates specific command with specific parameter
$response = command.sendRequest(); // executes command

This is also true for the actual implementation. createFactory($type), for example, only deals with the decision of which factory to instantiate for the requested channel.
Another advantage is scalability. You merely add new, small command-classes, instead of maintaining one big monolithic piece of code. This should also help you when writing tests, as smaller chunks of encapsulated code are inherently easier to test.
Last but not least you can decouple the decision making (what to get how and with which parameters) from the actual execution, by passing commands and/or factories around. This might turn out to be beneficial or not.

[1] https://sourcemaking.com/design_patterns/command
[2] https://sourcemaking.com/design_patterns/abstract_factory

2
  • This application of factory pattern is brilliant. Although I knew all the pieces you proposed, the combination strikes me. This pattern would also easily accomodate this: channel one serves only two topics, while channel two is growing with more and more topics. I have two observations: First: I personally would skip the last layer $response = command.sendRequest() because .sendRequest is actually the only method I could ever issue. Therefore it could be well incorporated into the creation of the command. – Vittorio Zamparella Oct 31 '15 at 12:54
  • Second: how to accomodate for transversal use from one topic to another? Ie: to send and invoice I need to send a person. Shall I (Invoice command) just use the factory and make it give me a People remote command? – Vittorio Zamparella Oct 31 '15 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.