介面卡
當客戶端類需要呼叫不相容的提供者類時,使用介面卡模式。 讓我們想象一個需要呼叫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.


