1

I am looking for the best pattern to apply in my problem. I have an interface that defines my service class functionality

interface NegotiationInterface {
    abstract public function resetNegotiation(Negotiation $negotiantion);
} 

A main class implements it

public class NegotiationService implements NegotiationInterface {

    public function __construct(…Some Dependencies…)
    {
    ….        
    }

    public function resetNegotiation(Negotiation $negotiantion){
    …. //All business logic
    }
}

NegotiationService is registered under DI container(Symfony based) and used all over application by its service id.

$negotiationService = $this->container->get(“negotiation_service”);
$negotiationService->resetNegotiation($negotiation);

However some of our clients(negotiation contains the client info), require an additional step after calling resetNegotiation, for example our common business logic + calling a webservice. I reached at decorator pattern but I am not sure if it would be the best approach while using DI. If so how would I apply together with DI. I would like to have those extra steps loaded dynamically according to client.

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
dextervip
  • 4,999
  • 16
  • 65
  • 93
  • At this point, there are two good answers to your question. Please take a look at them and accept one if the answers that helped you. Alternately, do comment on the answers for further clarification. That said, I have provided an example with the composite pattern which I believe should work very well in your case.. – Chetan Kinger Nov 12 '17 at 04:23

2 Answers2

1

I have to do such classes a lot at work, and we usually go with Adapters (correct me if I'm wrong on the design pattern). In your case, your adapter would look like this :

public class NegotiationServiceAdapter implements NegotiationInterface {

    protected $negotiationService;

    public function __construct(NegotiationService $negotiationService)
    {
        $this->negotiationService = $negotiationService;
    }

    public function resetNegotiation(Negotiation $negotiation){
        $this->negotiationService->resetNegotiation($negotiation);

        //Rest of your custom code for that client
    }
}

Notice that I added the "generic" NegotiationService used by everyone in the constructor, and then in the implemented function, you execute the code of this instance first (or last, depends on your case) and then your custom code.

RaphBlanchet
  • 575
  • 6
  • 23
  • Let's say I have a customers client A and B. so client A require call a webservice method and B require export a file. How would I implement it? I was thinking about Decorator but I am not sure about it. NegotiationA, NegotiationB injecting Negotiation. – dextervip Nov 03 '17 at 20:14
  • @dextervip You were close when you decided to go with the decorator pattern. Take a look at my answer for a better approach. – Chetan Kinger Nov 04 '17 at 07:52
0

I reached at decorator pattern but I am not sure if it would be the best approach while using DI

The Composite pattern would be a better fit for this use-case as compared to the Decorator pattern. I would make the following changes to your code :

  1. Rename the resetNegotiation method to execute in NegotiationInterface and NegotiationService.
  2. Add an array or a list (that can hold NegotiationInterface instances) to NegotiationService as an instance variable.
  3. Make the constructor in NegotiationService ask for an additional list/array parameter and initialize it in the constructor.

  4. In the execute method of NegotiationService, iterate through the list and call execute on each NegotiationInterface in it.

Once you've made the above changes, you can create different implementations of NegotiationInterface add them to an array/list and pass this into NegotiationService which will simply iterate through each instance one by one and call execute on each of the instances.

For example :

$resetNegotiation = new ResetNegotiationNegotiationInterfaceImpl();
$callWebservice = new CallWebServiceNegotiationInterfaceImpl();
$negotiationInterfacesClient1 = array($resetNegotiation, $callWebservice);
$negotiationServiceClient1 = new NegotiationService($dependencies, $negotiationInterfacesClient1);
negotiationServiceClient1.execute($negotiation);

$exportFile = new ExportFileNegotiationInterfaceImpl();
$negotiationInterfacesClient2 = array($resetNegotiation, $exportFile);
$negotiationServiceClient2 = new NegotiationService($dependencies,$negotiationInterfacesClient2);
negotiationServiceClient2.execute($negotiation);

Where :

  • ResetNegotiationNegotiationInterfaceImpl implements NegotiationInterface and contains code to reset the service in the execute method. This is reused by client and client2.
  • CallWebServiceNegotiationInterfaceImpl implements NegotiationInterface and contains code to call the webservice in the execute method.
  • ExportFileNegotiationInterfaceImpl implements NegotiationInterface and contains code to export a file in the the execute method.
Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82