代理模式、装饰模式和适配器模式

代理模式

为其他对象提供一种代理以控制对这个对象的访问。其实就是不直接使用原始对象构造出一个代理对象给客户端使用。

动态代理,将代理者和被代理者直接解耦,一个代理者可以代理多个被代理对象。
静态代理,只能代理实现同一个接口的被代理对象。
系统常见的例子如AIDL就是远程代理。

步骤:

  1. 创建接口,定义一些方法
  2. 原始对象实现接口并重写相关方法
  3. 创建代理对象实现接口并重写相关方法,而且构造函数需要传入一个原始对象,需要持有一个原始对象引用
  4. 客户端创建一个原始对象和一个代理对象,然后通过代理对象去调用原始对象的方法
//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
步骤:

  1. 定义客户端所期待的接口和想调用的方法
  2. 定义目前已存在对象方法即需要被适配对象
  3. 定义一个适配器对象,它将完成适配工作
//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源码设计模式解析与实战》 — 何红辉 关爱民

你可能感兴趣的:(设计模式)