1
\$\begingroup\$

The strategy pattern is applied in the code below in the payment separation solution. Please evaluate if it is well done according to standards. I would be very grateful for suggestions.

<?php 

interface PaymentMethod
{
    public function processPayment(Module $module, $order_id, array $client);
    public function paymentRepository(Repository $repository);
}


class Module {
    public $currentOrder = 1;
}

class Repository {}


class PaymentA implements PaymentMethod
{
    private $name = 'payment_a';
    private $clientData;
    private $repository;

    public function getName() {
        return $this->name;
    }

    public function paymentRepository(Repository $repository) {
        $this->repository = $repository;
    }

    public function processPayment(
        Module $module,
        $order_id,
        array $client
    )
    {
        $this->clientData = $client;
        
        return $this->responsePayment();

    }

    public function responsePayment() {
        return (array) [
            'status' => 'success',
            'order_id' => 123
        ];
    }

}


class PaymentB implements PaymentMethod
{
    private $name = 'payment_b';
    private $clientData;

    public function getName() {
        return $this->name;
    }

    public function paymentRepository(Repository $repository) {
        $this->repository = $repository;
    }

    public function processPayment(
        Module $module,
        $order_id,
        array $client
    )
    {
        $this->clientData = $client;
        $gateway = 2;

        return $this->responsePayment();

    }

    public function responsePayment() {
        return (array) [
            'status' => 'failed',
            'order_id' => 123
        ];
    }


}



class OrderClient
{
    public function getClient($cart, $type)
    :array
    {
        $data = [
            'amount' => 100,
            'name' => 'Imie',
            'cart' => $cart,
            'type' => $type,
        ];

        return $data;
    }
}



class PaymentFactory
{
    public static function getPaymentMethod(string $type)
    :PaymentMethod
    {
        switch ($type) {
            case "payment_a":
                return new PaymentA();
            case "payment_b":
                return new PaymentB();
            default:
                throw new \Exception("Wrong");
        }
    }
}



class PaymentController
{
    private $module;
    private $repository;
    private $order_client;
    private $payment_method;
    private $data;


    public function __construct(
        Module $module,
        OrderClient $order_client,
        Repository $repository,
        array $data = []
    ) {
        $this->module = $module;
        $this->repository = $repository;
        $this->order_client = $order_client;
        $this->data = $data;
    }



    public function setMethods($payment_method)
    {

        $this->payment_method = $payment_method;
        $this->paymentRepository();
        $this->getPayment();

    }


    public function paymentRepository() {
        $this->payment_method->paymentRepository($this->repository);
    }

    public function getPayment()
    {
        $result = $this->payment_method->processPayment(
            $this->module,
            $this->module->currentOrder,
            $this->order_client->getClient(
                'cart',
                $this->payment_method->getName()
            )
        );

        var_dump($result);

        if($result['status'] === 'success') {
            $this->setCompleteOrder($result);
        }

    }


    public function setCompleteOrder($result) {
        /// send sql complete order
        $this->setRedirectOrder($result['order_id']);
    }

    public function setRedirectOrder($order_id) {
        /// redirect
        return var_dump('redirect ' . $order_id);
    }

}




/// Init

$data = [
    'payment_type' => 'payment_a',
    'payment_gateway' => 10
];


$module = new Module();
$client = new OrderClient();
$repository = new Repository();

$payment_class = PaymentFactory::getPaymentMethod($data['payment_type']);

$controller = new PaymentController(
    $module,
    $client,
    $repository,
    $data
);


$controller->setMethods(
    $payment_class
);

var_dump($controller);
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

It looks like what you did was more like the Factory pattern. In fact, you have a Factory class in your code there.

I found a great explanation here in case you want to look into the differences between the Factory and Strategy patterns.

Strategy pattern would be about you changing behaviours of a class.

Let's say you have Payment class and different ways to pay Visa, MasterCard, Paypal,..

Each payment method would have different actions to process payment. Visa or CardPayment in general would need card information from users and process with card provider, while PayPal would process through PayPal API.

With the strategy pattern, you would have one payment object but the payment would have different methods (A.K.A. behaviours) at runtime.

interface PaymentMethod {
  public static function getPaymentMethod(string $type) {
    ...
  }

  processPayment($order, $client): Receipt
}

class Payment {
  PaymentMethod $method

  function processPaymentMethod($order, $client): PaidReceipt {
     return $method.processPayment($order, $client);
  }

  function setMethod($method) {
    $this->method = $method
  }
}

class Visa implements PaymentMethod {...}
class PayPal implements PaymentMethod {...}

The Factory pattern can be used with this pattern to create the PaymentMethod objects which would be used inside Payment. The client that would interact would be an instance of the Payment class and they would not know any details about the inside method action.

//init

$method = PaymenMethod::getPaymentMethod($data['payment_type'])
$payment = new Payment()
$payment->setPaymentMethod($method)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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