2

I was wondering if i could get a bit of help.

I have an interface like so

interface BackupContract {
    public function testConn($request, $port);
}

Then the 2 example implementations of this interface is as follows

class FTPBackup implements BackupContract {
    public function testConn($request, $port = 21) {
        // code here
    }
}

class SFTPBackup implements BackupContract {
    public function testConn($request, $port = 22) {
        // code here
    }
}

As i need things like 'service' and port designated at runtime, im using 'strategy pattern' to achieve this, like so.

class BackupStrategy {
    private $strategy = NULL;

    public function __construct($service) {

        switch ($service) {
            case "ftp":
                $this->strategy = new FTPBackup();
                break;
            case "sftp":
                $this->strategy = new SFTPBackup();
                break;
        }

    }

    public function testConn($request, $port)
    {
        return $this->strategy->testConn($request, $port);
    }
}

and finally, in my controller im using the following code to put it all together.

$service = new BackupStrategy($request->input('service'));
$service->testConn($request, $request->input('port'));

The problem is, that if a user doesnt enter a port, it is meant to auto assign a port variable, i.e 21 or 22 like in the 2 implementations.

It doesn't seem to be working, but its not throwing any errors

4 Answers 4

5

But you shouldnt implement the switch in the BackupStrategy's constructor.

With your aproach, you are violating the "open/close" principle from the S.O.L.I.D 's principles.

Any time you need to add another "backup strategy" you need to modify the BackupStrategy class, adding the logic to the constructor. Thats not good.

You could make sublcasses, each implementig the implementation (LOL) of each backup strategy classes and only inherating the necessary from BackupStrategy class.

interface BackupContract {
    public function testConn($request, $port);
}

class FTPBackup implements BackupContract {
    public function testConn($request, $port = 21) {
        // code here
    }
}

class SFTPBackup implements BackupContract {
    public function testConn($request, $port = 22) {
        // code here
    }
}

class BackupStrategy
{
    private $strategy;

    public function testConn($request, $port)
    {
        return $this->strategy->testConn($request, $port);
    }
}

class ConcreteFTPBackup extends BackupStrategy
{
    function __construct()
    {
        $this->strategy = new FTPBackup();
    }
}

class ConcreteSFTPBackup extends BackupStrategy
{
    function __construct()
        {
        $this->strategy = new SFTPBackup();
    }
}

$service = new ConcreteFTPBackup();

$serice->testConn($request, $request->input('port'));

Or even this:

interface BackupContract {
    public function testConn($request, $port);
}

class FTPBackup implements BackupContract {
    public function testConn($request, $port = 21) {
        // code here
    }
}

class SFTPBackup implements BackupContract {
    public function testConn($request, $port = 22) {
        // code here
    }
}

class BackupStrategy
{
    private $strategy;

    function __construct(BackupContract $bc)
    {
        $this->strategy = $bc();
    }

    public function testConn($request, $port)
    {
        return $this->strategy->testConn($request, $port);
    }
}


$service = new BackupStrategy(new FTPBackup());

$serice->testConn($request, $request->input('port'));

Then you could implement the switch during runtime.

Also you could make a setStrategy method in BackupStrategy class that set or change the backup strategy during runtime:

public function setStrategy(BackupContract $bc)
{
    $this->strategy = $bc();

}

So now, you can create a service with one backup strategy during runtime, and even change the strategy during runtime also!! Chekit out:

$service = new BackupStrategy(new FTPBackup());
$service->testConn($request, $request->input('port'));


$service->setStrategy(new SFTPBackup());
$service->testConn($request, $request->input('port'));

The BackupStrategy class is where all your encapsulated algorithms will converge, but don forget the "encapsulation" in all this!

The most important in the Strategy Pattern is the encapsulation of a family of algorithms that can be used during runtime!

Hope it helps you!

Sign up to request clarification or add additional context in comments.

1 Comment

why you use brackets on $bc()?
1

In addition to Simon and Laurent.

You're using interfaces, so the implementation should match.

A possible solution:

interface BackupContract {
    public function testConn($request, $port = 0);
}

But personally, I don't prefer this approach. Optional things in interfaces means that you should validate in possible each implementation instead of trusting the implementation.

Secondly, I recommend using type declarations (PHP7), for example:

public function foo(int $bar) : bool
{
    return true;  
}

This method expects an integer as argument (must) and a boolean value as return (must). Using $bar, you are sure that this var type is an integer.

See for more information: http://php.net/manual/en/migration70.new-features.php

Comments

0

You are always setting a port in BackupStrategy->testConn($request, $port) method. So if somebody doesn't give a port, it will pass an empty string.

I would implement a fallback function.

And what @simon said, you are using the wrong method name in your controller.

Comments

0

You are calling a testConnection(); method which doesn't exist. What you actually want to call is testConn();

Check your error reporting settings because this should definitely throw an error.

1 Comment

sorry, i forgot to change that ...it does check testConn()

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.