适配器
当客户端类需要调用不兼容的提供者类时,使用适配器模式。 让我们想象一个需要调用LegacyEmployee
类中方法的MailingClient
类
|
|
|
MailingClient
已经调用了实现IEmployee
接口的类,但是LegacyEmployee
没有实现它。 我们可以向LegacyEmployee
添加一个新方法来实现IEmployee
接口,但是LegacyEmployee
是遗留代码,无法修改。 我们可以修改MailingClient
类来调用LegacyEmployee
,但是它需要改变每次调用。 格式化代码会在所有地方重复。 此外,MailingClient
将无法再调用实现IEmployee
接口的其他提供者类。
所以解决方案是在另一个独立的类,适配器中编写格式化代码,也称为包装类
|
|||||||||||||
|
|
|
EmployeeAdapter
实现了IEmployee
接口。 MailingClient
调用EmployeeAdapter
。 EmployeeAdapter
格式化数据并调用LegacyEmployee
。 这种类型的适配器称为对象适配器。 另一种类型的适配器是类适配器。
示例
WebGL-2D是一个实现了适配器模式的 JavaScript 库。 该库用于 HTML5 画布元素。 画布元素有两个接口:2d 和 WebGL。 第一个非常易于使用,第二个更复杂但已优化且更快。 WebGL-2D 将 WebGL 接口“适配”到 2d 接口,以便客户端仅调用 2d 接口。
成本
在实现此模式之前三思而后行。 此模式不应在设计时规划。 如果你计划从头开始为项目使用它,这意味着你没有理解此模式。 它应该只用于遗留代码。 这是最不糟糕的解决方案。
创建
它的实现很简单,但可能很昂贵。 你不应该需要重构代码,因为客户端和提供者应该还不能一起工作。
维护
这是最糟糕的部分。 大部分代码都有冗余(但比没有模式要少)。 现代接口应该始终提供与遗留接口需要工作一样多的信息。 如果现代接口缺少某条信息,则可能会对模式提出质疑。
移除
此模式可以轻松移除,因为自动重构操作可以轻松移除它的存在。
建议
- 在适配器类的名称中添加适配器一词,以向其他开发人员指示该模式的使用。
实现
对象适配器
我们的公司是通过合并创建的。 一个员工列表可以在你可以通过CompanyAEmployees
类访问的数据库中找到
/**
* Employees of the Company A.
*/
public class CompanyAEmployees {
/**
* Retrieve the employee information from the database.
*
* @param sqlQuery The SQL query.
* @return The employee object.
*/
public Employee getEmployee(String sqlQuery) {
Employee employee = null;
// Execute the request.
return employee;
}
}
一个员工列表可以在你可以通过CompanyBEmployees
类访问的 LDAP 中找到
/**
* Employees of the Company B.
*/
public class CompanyBEmployees {
/**
* Retrieve the employee information from the LDAP.
*
* @param sqlQuery The SQL query.
* @return The employee object.
*/
public Employee getEmployee(String distinguishedName) {
Employee employee = null;
// Call the LDAP.
return employee;
}
}
为了访问公司 A 的前员工和公司 B 的前员工,我们定义了一个接口,该接口将被两个适配器使用,EmployeeBrowser
/**
* Retrieve information about the employees.
*/
interface EmployeeBrowser {
/**
* Retrieve the employee information.
*
* @param direction The employee direction.
* @param division The employee division.
* @param department The employee departement.
* @param service The employee service.
* @param firstName The employee firstName.
* @param lastName The employee lastName.
*
* @return The employee object.
*/
Employee getEmployee(String direction, String division, String department, String service, String firstName, String lastName);
}
我们为前公司 A 的代码创建一个适配器,CompanyAAdapter
/**
* Adapter for the company A legacy code.
*/
public class CompanyAAdapter implements EmployeeBrowser {
/**
* Retrieve the employee information.
*
* @param direction The employee direction.
* @param division The employee division.
* @param department The employee department.
* @param service The employee service.
* @param firstName The employee firstName.
* @param lastName The employee lastName.
*
* @return The employee object.
*/
public Employee getEmployee(String direction, String division, String department, String service, String firstName, String lastName) {
String distinguishedName = "SELECT *"
+ " FROM t_employee as employee"
+ " WHERE employee.company= 'COMPANY A'"
+ " AND employee.direction = " + direction
+ " AND employee.division = " + division
+ " AND employee.department = " + department
+ " AND employee.service = " + service
+ " AND employee.firstName = " + firstName
+ " AND employee.lastName = " + lastName;
CompanyAEmployees companyAEmployees = new CompanyAEmployees();
return companyAEmployees.getEmployee(distinguishedName);
}
}
我们为前公司 B 的代码创建一个适配器,CompanyBAdapter
/**
* Adapter for the company B legacy code.
*/
public class CompanyBAdapter implements EmployeeBrowser {
/**
* Retrieve the employee information.
*
* @param direction The employee direction.
* @param division The employee division.
* @param department The employee department.
* @param service The employee service.
* @param firstName The employee firstName.
* @param lastName The employee lastName.
*
* @return The employee object.
*/
public Employee getEmployee(String direction, String division, String department, String service, String firstName, String lastName) {
String distinguishedName = "ov1 = " + direction
+ ", ov2 = " + division
+ ", ov3 = " + department
+ ", ov4 = " + service
+ ", cn = " + firstName + lastName;
CompanyBEmployees companyBEmployees = new CompanyBEmployees();
return companyBEmployees.getEmployee(distinguishedName);
}
}
Ruby
class Adaptee
def specific_request
# do something
end
end
class Adapter
def initialize(adaptee)
@adaptee = adaptee
end
def request
@adaptee.specific_request
end
end
client = Adapter.new(Adaptee.new)
client.request
class Adaptee:
def specific_request(self):
return 'Adaptee'
class Adapter:
def __init__(self, adaptee):
self.adaptee = adaptee
def request(self):
return self.adaptee.specific_request()
client = Adapter(Adaptee())
print client.request()
trait Socket220V {
def plug220()
}
trait Socket19V {
def plug19()
}
class Laptop extends Socket19V {
def plug19() {
println("Charging....")
}
}
class LaptopAdapter(laptop: Laptop) extends Socket220V {
def plug220() {
println("Transform1...")
laptop.plug19()
}
}
object Test {
def main(args: Array[String]) {
//you can do it like this:
new LaptopAdapter(new Laptop).plug220()
//or like this (doesn't need LaptopAdapter)
new Laptop with Socket220V {
def plug220() {
println("Transform2...")
this.plug19()
}
} plug220()
}
}
program Adapter;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
(* Its interface *)
TTarget = class abstract
function Request: string; virtual; abstract;
end;
(* A client accessed to this. *)
TAdaptee = class(TTarget)
function Request: string; override;
end;
(* Object Adapter uses composition and can wrap classes or interfaces, or both.*)
(* Redirect call to Adaptee. It is loose coupling of client and adapter.*)
(*
*It can do this since it contains, as a private, encapsulated member,
*the class or interface object instance it wraps.
*)
TObjectAdapter = class
fAdaptee: TAdaptee;
function SpecialRequest: string;
constructor Create(adaptee: TAdaptee);
end;
{ TObjectAdapter }
constructor TObjectAdapter.Create;
begin
fAdaptee := TAdaptee.Create;
end;
function TObjectAdapter.SpecialRequest: string;
begin
Result := fAdaptee.Request;
end;
{ TAdaptee }
function TAdaptee.Request: string;
begin
Result := 'Adaptee';
end;
var
clientObject: TObjectAdapter;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
clientObject := TObjectAdapter.Create(TAdaptee.Create);
WriteLn('Call method Object Adapter: '+clientObject.SpecialRequest);
WriteLn(#13#10+ 'Press any key to continue...');
ReadLn;
clientObject.Free;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.
类适配器
class Adaptee1:
def __init__(self, *args, **kw):
pass
def specific_request(self):
return 'Adaptee1'
class Adaptee2:
def __init__(self, *args, **kw):
pass
def specific_request(self):
return 'Adaptee2'
class Adapter(Adaptee1, Adaptee2):
def __init__(self, *args, **kw):
Adaptee1.__init__(self, *args, **kw)
Adaptee2.__init__(self, *args, **kw)
def request(self):
return Adaptee1.specific_request(self), Adaptee2.specific_request(self)
client = Adapter()
print client.request()
program Adapter;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
(* Its interface *)
TTarget = class abstract
function Request: string; virtual; abstract;
end;
(* A client accessed to this. *)
TAdaptee = class(TTarget)
function Request: string; override;
end;
(* Class Adapter uses inheritance and can only wrap a class.*)
(* This plain old inheritance. *)
(* It cannot wrap an interface since by definition*)
(* it must derive from some base class as Adaptee in example*)
(*
* Can't reuse Class Adapter without rewrite code
* You need implements other adapter with other method in other class.
*)
TClassAdapter = class(TAdaptee)
function SpecialRequest: string;
end;
{ TClassAdapter }
function TClassAdapter.SpecialRequest: string;
begin
//use inherited Request as SpecialRequest
Result:= inherited Request;
end;
{ TAdaptee }
function TAdaptee.Request: string;
begin
Result := 'Adaptee';
end;
var
clientClass:TClassAdapter;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
clientClass:= TClassAdapter.Create;
WriteLn('Call method Class Adapter: '+clientClass.SpecialRequest);
WriteLn(#13#10+ 'Press any key to continue...');
ReadLn;
clientClass.Free;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.