PHP - 使用接口,策略模式和可选方法参数

时间:2016-10-28 09:37:16

标签: php laravel laravel-5

我想知道我是否能得到一些帮助。

我有一个像这样的界面

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

然后,此接口的2个示例实现如下

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 = 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);
    }
}

最后,在我的控制器中使用以下代码将它们放在一起。

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

问题是,如果用户没有输入端口,则意味着自动分配端口变量,即21或22,就像在2个实现中一样。

它似乎不起作用,但它没有抛出任何错误

4 个答案:

答案 0 :(得分:4)

但是你不应该在BackupStrategy的构造函数中实现这个开关。

有了你的方法,你违反了S.O.L.I.D原则中的“开/关”原则。

每当您需要添加另一个“备份策略”时,您需要修改 BackupStrategy类,将逻辑添加到构造函数中。 多数民众赞成不好。

您可以制作子画面,每个子画面实现每个备份策略类的实现(LOL),并且仅从BackupStrategy类中提取必要的内容。

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'));

甚至这个:

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'));

然后你可以在运行时实现切换。

您也可以在BackupStrategy类中创建一个setStrategy方法,在运行时设置或更改备份策略:

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

}

现在,您可以在运行时创建一个具有一个备份策略的服务,甚至可以在运行时更改策略! Chekit out:

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


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

BackupStrategy类是所有封装算法汇聚的地方,但不要忘记所有这些中的“封装”

策略模式中最重要的是封装了一系列可在运行时使用的算法!

希望它可以帮到你!

答案 1 :(得分:1)

除了Simon和Laurent。

您正在使用接口,因此实施应该匹配。

可能的解决方案:

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

但就个人而言,我不喜欢这种做法。接口中的可选项意味着您应该在每个实现中进行验证,而不是信任实现。

其次,我建议使用类型声明(PHP7),例如:

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

此方法需要一个整数作为参数(必须),一个布尔值作为return(必须)。使用$ bar,您确定此var类型是一个整数。

有关详细信息,请参阅:http://php.net/manual/en/migration70.new-features.php

答案 2 :(得分:0)

您正在调用一个不存在的testConnection();方法。你真正想要的是testConn();

检查错误报告设置,因为这肯定会引发错误。

答案 3 :(得分:0)

您始终使用BackupStrategy->testConn($request, $port)方法设置端口。因此,如果某人没有给出一个端口,它将传递一个空字符串。

我会实现一个后备功能。

@simon说的是,你在控制器中使用了错误的方法名称。