自下而上的开发实践

2018-07-01  本文已影响0人  zhanghTK

title: 自下而上的开发实践
date: 2016-10-22 19:23:25
tags:


两种开发思路

自上而下:设计先行,根据设计开发

自下而上:开发先行,给予开发重构

关注点分离

类似于文章段落的划分,代码拆分的简单过程可以概括为:

共性与可变性分析

软件工程的两个敌人:

共性的复用两种模式:

接口

context+role+collaborator

好处:类型确定,但实现可变、不确定

类与接口的关系类似于人与角色的关系:

接口设计应当遵循的原则:接口隔离原则(SIP)

接口应该是干净的,单一的,细粒度的,而不是混合过多的方法,职责单一

扩展式设计的一般过程:

  1. 分离职责各司其职:关注点分离
    • 向上分离:继承
    • 向外分离:组合
  2. 统一接口:
    • 提炼接口,提供多态
    • 面向接口编程
  3. 引用接口预留空白
    • 依赖注入

以一个事务为例子展示扩展式设计的一般过程:

首先,有一个Service,在方法中业务逻辑与JDBC事务粘合在一起:

public class OrderService {
    private DatabasePool dbPool;

    public void subscribTrainings(List<Training> trainings, 
                                  Customer customer) throws SQLException {
        // 初始化方法
        Connection c = null;
        PreparedStatement ps = null;
        Statement s = null;
        ResultSet rs = null;
        boolean transactionState = false;
      
        try {
            // 开启事务 
            s = c.createStatement();
            transactionState = c.getAutoCommit();
            c.setAutoCommit(false);
          
            // 业务操作
            for (Training training : trainings) {
                addTrainingItem(customer, training);
            }
            addOrder(customer, trainings);
            
            // 提交事务
            c.commit();
        } catch (SQLException sqlx) {
            // 回滚
            c.rollback();
          
            throw sqlx;
        } finally {
            // 关闭操作
            try {
                c.setAutoCommit(transactionState);
                dbPool.release(c);
                if (s != null) s.close();
                if (ps != null) ps.close();
                if (rs != null) rs.close();
            } catch (SQLException ignored) {
            }
        }
    }

    private void addOrder(Customer customer, List<Training> trainings) {
    
    }

    private void addTrainingItem(Customer customer, Training training) {

    }
}

第一步在原始代码上分段并添加注释后代码如上所示。对每段代码提取方法,向上抽象:

public class TransactionScope {
    private DatabasePool dbPool;
    private Connection connection;
    private PreparedStatement preparedStatement;
    private Statement statement;
    private ResultSet resultSet;
    private boolean transactionState;

    public void using() throws SQLException {
        setup();
        try {
            beginTransaction();
            // 留白一个具体的业务的实现:
            //      1. (模板方法)继承->钩子方法
            //      2. (委派)传递一个方法(方法接口)
            commitTransaction();
        } catch (SQLException sqlx) {
            rollbackTransaction();
            throw sqlx;
        } finally {
            teardown();
        }
    }

    private void rollbackTransaction() throws SQLException {
        connection.rollback();
    }

    private void setup() {
        connection = null;
        preparedStatement = null;
        statement = null;
        resultSet = null;
        transactionState = false;
    }

    private void teardown() {
        try {
            connection.setAutoCommit(transactionState);
            dbPool.release(connection);
            if (statement != null) statement.close();
            if (preparedStatement != null) preparedStatement.close();
            if (resultSet != null) resultSet.close();
        } catch (SQLException ignored) {
        }
    }

    private void commitTransaction() throws SQLException {
        connection.commit();
    }

    private void beginTransaction() throws SQLException {
        statement = connection.createStatement();
        transactionState = connection.getAutoCommit();
        connection.setAutoCommit(false);
    }
}

public interface Command {
    void execute();
}

现在提炼出了一个本地事务的基本控制模板,实现了事务控制与业务逻辑控制基本分离。

继续提炼事务控制类的接口,用于横向扩展继承使用:

public interface TransactionScope {
    void using(Command command) throws SQLException;
}

public class LocalTransactionScope implements TransactionScope {
    @Override
    public void using(Command action) throws SQLException {
        setup();
        try {
            beginTransaction();
            action.execute();  // 具体的业务逻辑
            commitTransaction();
        } catch (SQLException sqlx) {
            rollbackTransaction();
            throw sqlx;
        } finally {
            teardown();
        }
    }
}

public class DistructedTransactionScope implements TransactionScope {
    @Override
    public void using(Command command) throws SQLException {
      
    }
}

调用方通过接口留白,实现依赖注入:

public class OrderService {
    private TransactionScope transactionScope;

    public void setTransactionScope(TransactionScope transactionScope) {
        this.transactionScope = transactionScope;
    }

    public void subscribTrainings(List<Training> trainings, 
                                  Customer customer) throws SQLException {
        transactionScope.using(() -> {
                for (Training training : trainings) {
                    addTrainingItem(customer, training);
                }
                addOrder(customer, trainings);
        });
    }
}
上一篇下一篇

猜你喜欢

热点阅读