【2016-03-26】《修改代码的艺术》:The Seam Model

Seam定义:java

A seam is a place where you can alter behavior in your program without editing in that place。函数

bool CAsyncSslRec::Init()
{
    if (m_bSslInitialized) {
        return true;
    }
    m_smutex.Unlock();
    m_nSslRefCount++;
    m_bSslInitialized = true;
    FreeLibrary(m_hSslDll1);
    m_hSslDll1=0;
    FreeLibrary(m_hSslDll2);
    m_hSslDll2=0;
    if (!m_bFailureSent) {
        m_bFailureSent=TRUE;
        PostReceiveError(SOCKETCALLBACK, SSL_FAILURE);
}
    CreateLibrary(m_hSslDll1,"syncesel1.dll");
    CreateLibrary(m_hSslDll2,"syncesel2.dll");
    m_hSslDll1->Init();
    m_hSslDll2->Init();
    return true;
}

例如上面这段C++,若是PostReceiveError是一个严重依赖其余子系统的全局函数,而且这个子系统在测试的时候难以交互,用什么方式能够绕过PostReceiveError函数呢?测试

能够这样:ui

void CAsyncSslRec::PostReceiveError(UINT type, UINT errorcode)
{
    ::PostReceiveError(type, errorcode);
}

在CAsyncSslRec中写一个同名的方法,而后它的实现委托给全局的PostReceiveError方法。
其中::在C++中是域操做符(scoping operator),在Java中是没有的spa

class TestingAsyncSslRec : public CAsyncSslRec
{
    virtual void PostReceiveError(UINT type, UINT errorcode)
    {
    }
}

在测试类中写一个一样的方法,能够在测试的时候调用测试类中的PostReceiveError。翻译

以上方法叫作Object seam. 原书定义以下(不翻译了):
code

We were able to change the method that is called without changing the method that calls it. 继承


Seam的类型:input

  • Preprocessing Seams,主要用于C/C++(跳过没看)it

  • Link Seams

  • Object Seams:在OOP中用处比较大


Link Seams的Java例子。

有以下类:

package fitnesse;
import fit.Parse;
import fit.Fixture;
import java.io.*;
import java.util.Date;
import java.io.*;
import java.util.*;
public class FitFilter {
    public String input;
    public Parse tables;
    public Fixture fixture = new Fixture();
    public PrintWriter output;
    public static void main (String argv[]) {
        new FitFilter().run(argv);
    }
    public void run (String argv[]) {
    args(argv);
    process();
    exit(); 
    }
    public void process() {
        try {
            tables = new Parse(input);
            fixture.doTables(tables);
        } catch (Exception e) {
            exception(e);
        }
        tables.print(output);
    }
    ... 
}

在这个类中,引用了fit.Parse 和 fit.Fixture,JVM如何找到这些类呢?经过classpath环境变量。

能够建立一样名字的类,把它们放到别的目录中,修改classpath(enabling point),link到咱们加的fit.Parse 和 fit.Fixture,虽然再生产环境中使用有些费解,可是这个方法在测试的时候是一个好的切入点。


在OOP中,继承关系中不少方法调用都是seam,但并非全部的都是seam,好比这种:

public void method1(){
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
}

所以此处没有enabling point,咱们若是想换一个add方法,必需要修改代码

可是下面这种是seam,enabling point是method1的参数(这个好理解,毕竟多态的做用就是消除类型之间的耦合关系):

public void method1(List<Integer> list){
    list.add(1);
}

书中举了个Cell类的例子,殊途同归

public class CustomSpreadsheet extends Spreadsheet
{
    public Spreadsheet buildMartSheet(Cell cell) {
        ...
        cell.Recalculate();
        ... 
    }
}
相关文章
相关标签/搜索