代理模式、裝飾模式和介面卡模式
阿新 • • 發佈:2019-02-09
代理模式
為其他物件提供一種代理以控制對這個物件的訪問。其實就是不直接使用原始物件構造出一個代理物件給客戶端使用。
動態代理,將代理者和被代理者直接解耦,一個代理者可以代理多個被代理物件。
靜態代理,只能代理實現同一個介面的被代理物件。
系統常見的例子如AIDL就是遠端代理。
步驟:
- 建立介面,定義一些方法
- 原始物件實現介面並重寫相關方法
- 建立代理物件實現介面並重寫相關方法,而且建構函式需要傳入一個原始物件,需要持有一個原始物件引用
- 客戶端建立一個原始物件和一個代理物件,然後通過代理物件去呼叫原始物件的方法
//1.建立介面
public interface ILawsuit {
//提交申請
void submit();
// 進行舉證
void burden();
//開始辯護
void defend();
//訴訟完成
void finish();
}
//2.建立原始物件
public class XiaoMin implements ILawsuit{
@Override
public void submit() {
//老闆拖欠小民的工資,小民申請仲裁
System.out.println("老闆年底拖欠工資,特此申請仲裁!");
}
@Override
public void burden() {
//小民提交證據
System.out.println("這是合同書和過去一年的銀行工資流水!");
}
@Override
public void defend() {
//鐵證如山
System.out.println("證據確鑿,不需要再說什麼!");
}
@Override
public void finish() {
//結果贏了
System.out.println("訴訟成功,判決老闆即日起七天內結算工資!" );
}
}
//3.建立代理物件
public class Lawyer implements ILawsuit{
private ILawsuit mLawsuit; //持有一個具體被代理者的引用
public Lawyer(ILawsuit lawsuit) {
this.mLawsuit = lawsuit; //傳入原始物件
}
@Override
public void submit() {
mLawsuit.submit();
}
@Override
public void burden() {
mLawsuit.burden();
}
@Override
public void defend() {
mLawsuit.defend();
}
@Override
public void finish() {
mLawsuit.finish();
}
}
//4.客戶端呼叫
public class Client {
public static void main(String[] args) {
//構造出訴訟人小民
ILawsuit xiaomin = new XiaoMin();
//構造一個代理律師,並將小民傳遞進去
ILawsuit lawyer = new Lawyer(xiaomin);
//律師提交申請
lawyer.submit();
//律師進行舉證
lawyer.burden();
//律師代小民辯護
lawyer.defend();
//完成訴訟
lawyer.finish();
}
}
//5.輸出結果
老闆年底拖欠工資,特此申請仲裁!
這是合同書和過去一年的銀行工資流水!
證據確鑿,不需要再說什麼!
訴訟成功,判決老闆即日起七天內結算工資!
裝飾模式
動態的給一個物件新增一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
裝飾模式是以對客戶端透明的方式擴充套件物件的功能,是繼承關係的一個替代方案。
其實就是建立幾個裝飾器,然後裝飾器裡面持有你要裝飾物件的引用,在呼叫被裝飾物件的方法前後增加我們想對它增加的方法,就是這樣。
系統中常見的例子就是 Context,ContextWrapper這些
步驟:
1. 建立抽象元件,一個抽象類是你具體要裝飾的物件的抽象類,裡面定義一些抽象方法
2. 建立具體元件,即一個具體的需要裝飾的類,繼承自上面的抽象元件,並實現抽象方法
3. 建立抽象裝飾者,一個抽象類繼承自抽象元件,並持有一個抽象元件的物件,實現抽象方法
4. 建立具體裝飾者,繼承自抽象裝飾者,實現抽象方法時加入需要裝飾的方法,起到裝飾的作用
5. 客戶端先建立具體元件,然後再建立具體裝飾者並傳入具體元件,最後呼叫具體方法實現裝飾效果
//1.建立抽象元件
public abstract class Person {
/**
* Person下有一個穿著的抽象方法
*/
public abstract void dressed();
}
//2.建立具體元件
public class Boy extends Person{
@Override
public void dressed() {
System.out.println("穿了內衣內褲");
}
}
//3.建立抽象裝飾者
public class PersonCloth extends Person{
protected Person mPerson; //持有一個Person類的引用
public PersonCloth(Person mPerson) {
super();
this.mPerson = mPerson;
}
@Override
public void dressed() {
mPerson.dressed();
}
}
//4.建立具體裝飾者
public class ExpensiveCloth extends PersonCloth{
public ExpensiveCloth(Person mPerson) {
super(mPerson);
}
/**
* 穿短袖
*/
private void dressShirt(){
System.out.println("穿件短袖");
}
/**
* 穿牛仔褲
*/
private void dressLeather(){
System.out.println("穿牛皮衣");
}
/**
* 穿鞋子
*/
private void dressJean(){
System.out.println("穿牛仔褲");
}
@Override
public void dressed() { //重寫的方法
super.dressed();
dressShirt(); //起到了裝飾的作用
dressLeather();
dressJean();
}
}
//5.客戶端
public class Client {
public static void main(String[] args) {
//首先有一個男孩
Person person = new Boy();
//
PersonCloth personCloth = new ExpensiveCloth(person);
personCloth.dressed();
System.out.println("--------------");
}
}
//6.輸出
穿了內衣內褲
穿件短袖
穿牛皮衣
穿牛仔褲
--------------
介面卡模式
介面卡模式把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配無法在一起工作的兩個類可以在一起工作。
系統常見的例子就是listview和它的adapter
步驟:
- 定義客戶端所期待的介面和想呼叫的方法
- 定義目前已存在物件方法即需要被適配物件
- 定義一個介面卡物件,它將完成適配工作
//Target角色,客戶端所期待返回的物件
public interface FiveVolt {
public int getVolt5();
}
//Adaptee角色,現有的物件需要被適配
public class Volt220 {
public int getVolt220(){
return 220;
}
}
//Adapter角色,介面卡,將Adaptee轉換成客戶端需要的樣子
public class VoltAdapter extends Volt220 implements FiveVolt{ //繼承自被適配物件實現期待物件介面
@Override
public int getVolt5() {
return 5;
}
}
//客戶端呼叫
public class Test {
public static void main(String[] args) {
VoltAdapter adapter = new VoltAdapter();
System.out.println("輸出電壓:" + adapter.getVolt5());
}
}
//輸出
輸出電壓:5
三者的區別,代理模式不改變原始物件的功能,裝飾器模式會增強原始物件的功能,介面卡模式會改變原始物件對外暴露的介面
參考 《Android原始碼設計模式解析與實戰》 — 何紅輝 關愛民