《装饰器模式》VS《代理模式》

装饰器强调的是动态功能增强,而这种增强是比单继承更加的灵活的方式,可以动态的给基类扩展不同的功能。

继承实现增强有不同结构

如果是按照最小原则,是这样的⬇︎⬇︎⬇︎
image

如果不想那么多类文件,是这样的⬇︎⬇︎⬇︎
image

虽然这样都能实现让子类拥有base/A/B三个操作,但如果现在只需要base/B操作怎么办。差的是灵活性,强调是动态。

可增可撤的增强功能

image

AccessToken
package com.xxx.sales.saicorder.outerapp;

/**
 * accessToken 是最接近访问接口的动态令牌,拿到此令牌即可调用需要授权的接口
 * 注意:在标准的授权登录中,是要先拿到用户授权的code,然后携code取accessToken信息
 * T : 表示获取code的参数,通常是app_key和secret
 * V : 表示用户授权,开放平台返回的结构
 * Z : 表示获取令牌,开放平台返回的结构
 *
 * @author Euler
 */
public interface AccessToken<T, V, Z> {


    /**
     * 获取授权码
     * <p>
     * 用户授权后,开放平台返回的code。一般通过redirect方式返回
     *
     * @param params
     * @return
     */
    V getCode(T params);


    /**
     * 获取访问令牌
     * <p>
     * 通过code获取对应的accessToken
     *
     * @param codeResponse 授权码响应结果
     * @return
     */
    Z getAccessToken(V codeResponse);


}

BaseAccessToken
package com.xxx.sales.saicorder.outerapp.tmall.accesstoken;


import com.xxx.sales.saicorder.outerapp.AccessToken;
import com.xxx.sales.saicorder.outerapp.tmall.req.CodeRequest;
import com.xxx.sales.saicorder.outerapp.tmall.resp.AccessTokenResponse;
import com.xxx.sales.saicorder.outerapp.tmall.resp.CodeResponse;

/**
 * 通过阿里开放平台的接口,获取数据
 *
 * @author Euler
 */
public class BaseAccessToken implements AccessToken<CodeRequest, CodeResponse, AccessTokenResponse> {
    /**
     * 获取授权码
     * <p>
     * 用户授权后,开放平台返回的code。一般通过redirect方式返回
     *
     * @param params
     * @return
     */
    @Override
    public CodeResponse getCode(CodeRequest params) {
        return null;
    }

    /**
     * 获取访问令牌
     * <p>
     * 通过code获取对应的accessToken
     *
     * @param codeResponse 授权码响应结果
     * @return
     */
    @Override
    public AccessTokenResponse getAccessToken(CodeResponse codeResponse) {
        return null;
    }
}

CacheWrapperAccessToken
package com.xxx.sales.saicorder.outerapp.tmall.accesstoken;


import com.xxx.sales.saicorder.outerapp.AccessToken;
import com.xxx.sales.saicorder.outerapp.tmall.req.CodeRequest;
import com.xxx.sales.saicorder.outerapp.tmall.resp.AccessTokenResponse;
import com.xxx.sales.saicorder.outerapp.tmall.resp.CodeResponse;

/**
 * 基于缓存的accessToken的实现
 * <p>
 * 如果多个系统共同使用一个accessToken,可以将其通过redis共享。
 * 默认实现是基于进程内的内存共享
 *
 * @author Euler
 */
public class CacheWrapperAccessToken implements AccessToken<CodeRequest, CodeResponse, AccessTokenResponse> {

    /**
     * 基于请求天猫接口的实现
     */
    private AccessToken accessToken;

    public CacheWrapperAccessToken(AccessToken accessToken) {
        this.accessToken = accessToken;
    }

    /**
     * 获取授权码
     * <p>
     * 用户授权后,开放平台返回的code。一般通过redirect方式返回
     *
     * @param params
     * @return
     */
    @Override
    public CodeResponse getCode(CodeRequest params) {
	    //先从缓存取,缓存没有在从取源数据
        return null;
    }

    /**
     * 获取访问令牌
     * <p>
     * 通过code获取对应的accessToken
     *
     * @param codeResponse 授权码响应结果
     * @return
     */
    @Override
    public AccessTokenResponse getAccessToken(CodeResponse codeResponse) {
	    //先从缓存取,缓存没有在从取源数据
        return null;
    }
}


mybatis的执行器也是这样的

image

CachingExecutor
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.ibatis.executor;

import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cache.TransactionalCacheManager;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;

public class CachingExecutor implements Executor {
    private final Executor delegate;
    private final TransactionalCacheManager tcm = new TransactionalCacheManager();

    public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
        delegate.setExecutorWrapper(this);
    }

    public Transaction getTransaction() {
        return this.delegate.getTransaction();
    }

    public void close(boolean forceRollback) {
        try {
            if (forceRollback) {
                this.tcm.rollback();
            } else {
                this.tcm.commit();
            }
        } finally {
            this.delegate.close(forceRollback);
        }

    }

    public boolean isClosed() {
        return this.delegate.isClosed();
    }

    public int update(MappedStatement ms, Object parameterObject) throws SQLException {
        this.flushCacheIfRequired(ms);
        return this.delegate.update(ms, parameterObject);
    }

    public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
        this.flushCacheIfRequired(ms);
        return this.delegate.queryCursor(ms, parameter, rowBounds);
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();
        if (cache != null) {
            this.flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                this.ensureNoOutParams(ms, boundSql);
                List<E> list = (List)this.tcm.getObject(cache, key);
                if (list == null) {
                    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    this.tcm.putObject(cache, key, list);
                }

                return list;
            }
        }

        return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    public List<BatchResult> flushStatements() throws SQLException {
        return this.delegate.flushStatements();
    }

    public void commit(boolean required) throws SQLException {
        this.delegate.commit(required);
        this.tcm.commit();
    }

    public void rollback(boolean required) throws SQLException {
        try {
            this.delegate.rollback(required);
        } finally {
            if (required) {
                this.tcm.rollback();
            }

        }

    }

    private void ensureNoOutParams(MappedStatement ms, BoundSql boundSql) {
        if (ms.getStatementType() == StatementType.CALLABLE) {
            Iterator var3 = boundSql.getParameterMappings().iterator();

            while(var3.hasNext()) {
                ParameterMapping parameterMapping = (ParameterMapping)var3.next();
                if (parameterMapping.getMode() != ParameterMode.IN) {
                    throw new ExecutorException("Caching stored procedures with OUT params is not supported.  Please configure useCache=false in " + ms.getId() + " statement.");
                }
            }
        }

    }

    public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        return this.delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
    }

    public boolean isCached(MappedStatement ms, CacheKey key) {
        return this.delegate.isCached(ms, key);
    }

    public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
        this.delegate.deferLoad(ms, resultObject, property, key, targetType);
    }

    public void clearLocalCache() {
        this.delegate.clearLocalCache();
    }

    private void flushCacheIfRequired(MappedStatement ms) {
        Cache cache = ms.getCache();
        if (cache != null && ms.isFlushCacheRequired()) {
            this.tcm.clear(cache);
        }

    }

    public void setExecutorWrapper(Executor executor) {
        throw new UnsupportedOperationException("This method should not be called");
    }
}


下面是代理↡↡↡↡

代理侧重于控制对真实对象的访问

比如,使用nginx进行反向代理最能体现这一思想。但在代码中使用代理更多的是功能增强,功能增强是代理模式的附加属性。

posted @   Eular  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示