设计模式(装饰模式)

什么是装饰模式(Decorator):
  装饰模式是为已有功能动态的添加更多功能的一种方式;在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象;

装饰模式由4种角色组成:
  抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加职责的对象;
  具体构件(Concrete Component)角色:定义一个将要接收附加职责的类;
  装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口,从外类来扩展Component类的功能,但对于Component类来说,是无需知道Decorato的存在的;
  具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的职责;

装饰模式的优点:
  1.把类中的装饰功能从类中搬移出去,这样可以简化原有的类;
  2.有效的把类的核心职责和装饰功能分开,而且可以去除相关类中重复的装饰逻辑;
  3.装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性;
  4.通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合;

装饰模式的应用场景,以下引自百度百科:
  1. 需要扩展一个类的功能,或给一个类添加附加职责;
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销;
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实;
  4. 当不能采用生成子类的方法进行扩充时。
    一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
    另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类;

模式简化
  如果只有一个Concrete Component类而没有抽象的Component接口时,可以让Decorator继承Concrete Component;
  如果只有一个Concrete Decorator类时,可以将Decorator和Concrete Decorator合并;

UML类图

根据UML生成一个简单的Demo:

interface Component{
    void operation();
}

class ConcreateComponent implements Component{
    @Override
    public void operation() {
        System.out.println("balabala....");
    }
}

abstract class Decorator implements Component{
    private Component comp;

    public Decorator(Component comp){
        this.comp = comp;
    }

    @Override
    public void operation() {
        comp.operation();
    }
}

class ConcreateDecorator extends Decorator{
    public ConcreateDecorator(Component comp) {
        super(comp);
    }

    @Override
    public void operation() {
        System.out.println("begin...");
        super.operation();
        System.out.println("end...");
    }
}

public class TestMain {
    public static void main(String[] args) {
        Component component = new ConcreateComponent();
        component = new ConcreateDecorator(component);
        component.operation();
    }
}

 输出的结果为:

begin...
balabala....
end...

在Mybatis的Executor也采用了装饰模式,不过在使用方法上稍微有些区别,我们先看一下Executor的实现图:

以下是我从Mybatis中分离出来的一部分代码,标红部分可以重点关注一下:

package org.apache.ibatis.executor;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;

import java.sql.SQLException;
import java.util.List;

public interface Executor {
    ResultHandler NO_RESULT_HANDLER = null;

    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

    void commit(boolean required) throws SQLException;

    void rollback(boolean required) throws SQLException;

    CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

    Transaction getTransaction();

    void setExecutorWrapper(Executor var1);
}
package org.apache.ibatis.executor;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.jdbc.ConnectionLogger;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public abstract class BaseExecutor implements Executor {

    protected Transaction transaction;
    protected Executor wrapper;

    protected Configuration configuration;

    protected int queryStack;

    protected BaseExecutor(Configuration configuration, Transaction transaction) {
        this.transaction = transaction;
        this.configuration = configuration;
        this.wrapper = this;
    }

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException {
        return null;
    }

    @Override
    public void commit(boolean required) throws SQLException {

    }

    @Override
    public void rollback(boolean required) throws SQLException {

    }

    @Override
    public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        return null;
    }

    @Override
    public Transaction getTransaction() {
        return null;
    }

    @Override
    public void setExecutorWrapper(Executor var1) {
        this.wrapper = wrapper;
    }

    protected Connection getConnection(Log statementLog) throws SQLException {
        Connection connection = transaction.getConnection();
        if (statementLog.isDebugEnabled()) {
            return ConnectionLogger.newInstance(connection, statementLog, queryStack);
        } else {
            return connection;
        }
    }

}
package org.apache.ibatis.executor;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.transaction.Transaction;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class SimpleExecutor extends BaseExecutor {

    protected SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);
        stmt = handler.prepare(connection, transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
    }

}
package org.apache.ibatis.executor;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cache.TransactionalCacheManager;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;

import java.sql.SQLException;
import java.util.List;

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);
    }

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException {
        return null;
    }

    @Override
    public void commit(boolean required) throws SQLException {

    }

    @Override
    public void rollback(boolean required) throws SQLException {

    }

    @Override
    public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        return null;
    }

    @Override
    public Transaction getTransaction() {
        return null;
    }

    @Override
    public void setExecutorWrapper(Executor var1) {
        throw new UnsupportedOperationException("This method should not be called");
    }
}
package org.apache.ibatis.session;

import org.apache.ibatis.executor.*;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.transaction.Transaction;

public class Configuration {

    private Configuration conf;
    public Configuration(Configuration conf){
        this.conf = conf;
    }

    protected boolean cacheEnabled = true;
    protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

    protected final InterceptorChain interceptorChain = new InterceptorChain();

    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Executor executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(conf, transaction);
        }
        if (cacheEnabled) {
            executor = new CachingExecutor(executor);
        }
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
    }
}

  

原文地址:https://www.cnblogs.com/jiangyaxiong1990/p/9236764.html