我想知道我是否可以得到一些帮助。
我有一个像这样的接口
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
}
}
因为我需要在运行时指定'service'和port,所以我使用'strategy pattern'来实现这一点,像这样。
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,就像在两个实现。
它似乎不工作,但它没有抛出任何错误
但是你不应该在BackupStrategy的构造函数中实现这个开关。
你的做法违反了s.o.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:
$service = new BackupStrategy(new FTPBackup());
$service->testConn($request, $request->input('port'));
$service->setStrategy(new SFTPBackup());
$service->testConn($request, $request->input('port'));
BackupStrategy类是所有封装算法收敛的地方,但不要忘记在所有这些中"封装" !
策略模式中最重要的是可以在运行时使用的一系列算法的封装!
希望它能帮助你!
除了Simon和Laurent。
你正在使用接口,所以实现应该匹配。
一个可能的解决方案:
interface BackupContract {
public function testConn($request, $port = 0);
}
但就我个人而言,我不喜欢这种方法。接口中的可选内容意味着您应该尽可能地验证每个实现,而不是信任实现。
其次,我建议使用类型声明(PHP7),例如:public function foo(int $bar) : bool
{
return true;
}
这个方法需要一个整数作为参数(必须)和一个布尔值作为返回(必须)。使用$bar,你可以确定这个var类型是一个整数。
查看更多信息:http://php.net/manual/en/migration70.new-features.php
您总是在BackupStrategy->testConn($request, $port)
方法中设置端口。如果没有指定端口,它会传递一个空字符串
我将实现一个回退函数。
@simon说,你在控制器中使用了错误的方法名
您正在调用一个不存在的testConnection();
方法。实际上你要调用的是testConn();
检查你的错误报告设置,因为这肯定会抛出一个错误。