为什么策略设计模式和适配器相互关联? 在我看来,适配器操纵某种方法的结果来满足另一个方法的输入需求。策略决定行为。
适配器模式基本上允许类一起工作,而由于不兼容的接口,它们自己不能一起工作。 Adapter 将一个类的接口转换成另一个类可以使用的东西。
类似于出国旅行需要携带电源适配器才能使用墙上的插座。
另一方面,策略模式采用一组算法,并使它们可以互换(通过从公共接口扩展)。这样,无论哪个班级要使用该策略,都可以轻松地将其与组中的另一个策略互换。
换句话说,Adapter 不会以任何方式添加行为,它只是修改现有接口以允许其他一些类访问现有功能。
另一方面,策略模式封装了不同的行为,并允许它们在运行时切换。
一个例子总是好的,让我们看一下适配器的用例。假设您正在使用一些您无法修改的包,它包含以下文件:
class DatabaseManager
{
private Connection $connection;
public function connect(Connection $connection)
{
$this->connection = $connection->establish();
}
}
class MysqlConnection implements Connection
{
public function establish(){
// connect to mysql...
}
}
在你的回购协议中,你有以下代码:
class YourService
{
public function connectDB()
{
$db = new DatabaseManager();
$db->connect(new MysqlConnection());
}
}
一切正常,但是您需要将连接更改为 SqlLiteConnection 并添加必须导入不同的包才能使用它。导入的文件如下所示:
class SqlLiteConnection
{
public function prepareConnection(){
// first prepare the connection...
return $preparedConnection;
}
public function executeConnection($preparedConnection){
// then connect ...
$preparedConnection->execute();
}
}
SqlLiteConnection 的接口(方法名)与MysqlConnection 不同,所以你使用起来有问题:
class YourService
{
public function connectDB()
{
$db = new DatabaseManager();
$db->connect(new SqlLiteConnection()); // error! method `establish` does not exist in SqlLiteConnection.
}
}
您无法修改 SqlLiteConnection 包,因此要让它工作,您需要创建一个适配器:
class SqlLiteAdapter implements Connection
{
public function establish($sqlConnection)
{
$preparedConnection = $sqlConnection->prepareConnection();
$sqlConnection->executeConnection(preparedConnection);
}
}
现在可以了!
class YourService
{
public function connectDB()
{
$db = new DatabaseManager();
$db->connect(new SqlLiteAdapter(new SqlLiteConnection())); //works!
}
}
如您所见,适配器只是用作将
establish
映射到方法prepareConnection
和executeConnection
的别名。这是适配器的目的,它不添加功能,而只是adapts
您需要的接口。类似于允许您在欧盟插座中使用美国插头的旅行适配器。
另一方面,策略模式将具有与上述类似的实现,但您不会简单地在适配器中映射一些功能,而是会为每个策略添加您独特的逻辑。
Adapter 是在不修改行为的情况下使用现有功能。策略根据当时正在使用的具体类修改行为。