装饰模式与代理模式的异同

2018-10-30  本文已影响0人  努力做一个最懒的程序员

一、装饰模式

1.定义:

    动态地给一个对象添加一些额外的职责。(就增加功能来说,装饰模式生成子类更为灵活)

2.使用场景:

    需要透明且动态地扩展类的功能。

3.安卓实例:

    Context、ContextImpl、ContextWrapper。

4.例子:

UML
/**
 * 角色
 */
interface Role {

    void decorate();
}

/**
 * 男性角色
 */
class MaleRole implements Role {

    @Override
    public void decorate() {
        System.out.println("初始化男性角色");
    }
}

/**
 * 装备
 */
abstract class Clothes implements Role {

    protected Role mRole;

    public Clothes(Role role) {
        mRole = role;
    }

    @Override
    public void decorate() {
        mRole.decorate();
    }
}

/**
 * 功能宝珠
 */
abstract class Gem implements Role {

    protected Role mRole;

    public Gem(Role role) {
        mRole = role;
    }

    @Override
    public void decorate() {
        mRole.decorate();
    }
}

/**
 * 玄铁甲
 */
class XuanTieJia extends Clothes {

    public XuanTieJia(Role role) {
        super(role);
    }

    @Override
    public void decorate() {
        System.out.println("穿上玄铁甲");
    }
}

/**
 * 火系宝珠
 */
class FireGem extends Gem {

    public FireGem(Role role) {
        super(role);
    }

    @Override
    public void decorate() {
        System.out.println("镶嵌火系宝珠");
    }
}

public class DecorationTest {

    public static final String TAG = DecorationTest.class.getSimpleName();

    public static void main(String[] args) {
        // 初始化角色
        Role role = new MaleRole();
        // 穿个玄铁甲
        XuanTieJia xuanTieJia = new XuanTieJia(role);
        // 给玄铁甲镶嵌个火系宝珠
        FireGem fireGem = new FireGem(xuanTieJia);
        fireGem.decorate();
    }
}

二、代理模式

1.定义:

    为其他对象提供一种代理以控制这个对象的访问。

2.使用场景:

    当无法或不想直接访问某个对象或访问某个对象困难的时候可以通过一个代理对象来间接访问。(为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口)

3.静态代理:

    (1)静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行。在程序运行之前,class已经存在。
    (2)安卓实例:IBinder、Binder、BinderProxy。
    (3)与观察者模式比较:静态代理是一对一的关系;观察者模式为一对多的关系。

4.动态代理:

    (1)动态代理主要是通过反射机制,在运行时动态生成所需代理的class。
    (2)安卓实例:Retorift。

4.例子:

UML
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;

interface Game {

    void play();
}

class LeagueOfLegends implements Game {

    @Override
    public void play() {
        System.out.println(getClass().getSimpleName() + "打野中");
    }
}

/**
 * 静态代理
 */
class LeagueOfLegendsProxy implements Game {

    private Game mGame;
    private String mUserName;
    private String mUserPwd;
    private boolean isLogin;

    LeagueOfLegendsProxy(Game game, String userName, String userPwd) {
        mGame = game;
        mUserName = userName;
        mUserPwd = userPwd;
    }

    @Override
    public void play() {
        if (login(mUserName, mUserPwd)) {
            System.out.println(getClass().getSimpleName() + "登陆成功");
            mGame.play();
            System.out.println(getClass().getSimpleName() + "游戏胜利");
            if (playAgain()) {
                play();
            } else {
                isLogin = false;
                System.out.println(getClass().getSimpleName() + "退出登陆");
            }
        } else {
            System.out.println(getClass().getSimpleName() + "登陆失败");
        }
    }

    private boolean login(String userName, String userPwd) {
        if (isLogin) {
            return true;
        } else {
            System.out.println(getClass().getSimpleName() + "正在登陆对方账户:" + mUserName);
            isLogin = new Random().nextInt(10) % 2 == 0;
        }
        return isLogin;
    }

    private boolean playAgain() {
        return new Random().nextInt(10) % 2 == 0;
    }
}

/**
 * 动态代理
 */
class DynamicProxyHandler implements InvocationHandler {

    private Game mGame;

    DynamicProxyHandler(Game Game) {
        mGame = Game;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(getClass().getSimpleName() + "准备代打");
        Object invoke = method.invoke(mGame, args);
        System.out.println(getClass().getSimpleName() + "代打成功");
        return invoke;
    }
}

public class ProxyTest {

    public static final String TAG = ProxyTest.class.getSimpleName();

    public static void main(String[] args) {
        // 静态代理使用
        new LeagueOfLegendsProxy(new LeagueOfLegends(), "LiuGuoQing", "qwer1234").play();
        // 动态代理使用
        DynamicProxyHandler handler = new DynamicProxyHandler(new LeagueOfLegends());
        Game proxyInstance = (Game) Proxy.newProxyInstance(LeagueOfLegends.class.getClassLoader(), LeagueOfLegends.class.getInterfaces(), handler);
        proxyInstance.play();
    }

}

三、两者比较

1.相同点:

    装饰模式中装饰者(Decorator)和被装饰者(Cafe)都实现同一个 接口;代理模式中代理类(Proxy Class)和真实处理的类(Real Class)都实现同一个接口。

2.区别:

    装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身的功能进行增强。

上一篇 下一篇

猜你喜欢

热点阅读