深入淺出設計模式(五):7.適配器模式

前面講完了創建型模式,這裏開始,我將講下7種結構型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。其中對象的適配器模式是各種模式的起源,我們看下面的圖:
這裏寫圖片描述

7.適配器模式(Adapter)

當一個系統需要使用另一個系統提供的外部接口,而這個外部接口與目前系統使用的接口不兼容時,就需要使用適配器模式,適配器模式就是將一個系統的接口轉換成另外一種形式,從而使原來不能直接使用的接口變得可以使用。

哪裏會使用到適配器模式

比如:

  • 財務系統要使用人事系統的接口,而人事系統來不及寫,財務系統又不能停下來等,這時兩種解決辦法:一種是雙方事先定好要提供的接口方法,包括方法名、參數、返回值等;另一種是雙方各自開發自己的程序,等將來提供了接口再進行整合,此時就需要適配器模式進行開發

  • 有時候需要使用外部購買的系統提供的接口,或者使用很久以前的接口(已經不再維護),或者系統對方不提供源代碼,這時需適配器模式將購買的系統接口轉成自己需要的接口

  • 如java的接口定義了8個方法,而一個客戶端使用2個,另一個客戶端只是用1個,如果將這8個方法都在實現類裏覆寫一遍,將會非常麻煩,此時可用適配器模式

適配器的實現原理

這裏寫圖片描述

在模塊的接口間使用適配器模式

比如目前人事系統接口返回Map,此時財務系統客戶端要求Map,而供應鏈系統要求用List,所以就需要一個適配器將Map轉換爲List:

這裏寫圖片描述

代碼比較簡單,就不在此貼出,全部放在項目中。

適配器模式的實際應用,源碼剖析

適配器模式在StringReader, StringWriter, CharArrayReader, CharArrayWriter的實際應用

StringReader

import java.io.IOException;
import java.io.Reader;

public class StringReader extends Reader {

    private String str;
    private int length;
    private int next = 0;
    private int mark = 0;


    public StringReader(String s) {
        this.str = s;
        this.length = s.length();
    }

    //確認該流沒有被關閉
    private void ensureOpen() throws IOException {
        if (str == null)
            throw new IOException("Stream closed");
    }

    // 讀取字符
    public int read() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (next >= length)
                return -1;
            return str.charAt(next++);
        }
    }

    // 讀取字符數組中的字符
    public int read(char cbuf[], int off, int len) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
                ((off + len) > cbuf.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
            if (next >= length)
                return -1;
            int n = Math.min(length - next, len);
            str.getChars(next, next + n, cbuf, off);
            next += n;
            return n;
        }
    }

    // 跳轉
    public long skip(long ns) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (next >= length)
                return 0;
            // Bound skip by beginning and end of the source
            long n = Math.min(length - next, ns);
            n = Math.max(-next, n);
            next += n;
            return n;
        }
    } 

    // 確認該字符是否已被讀取
    public boolean ready() throws IOException {
        synchronized (lock) {
        ensureOpen();
        return true;
        }
    }

    // 是否支持mark操作
    public boolean markSupported() {
        return true;
    }

    //標識當前位置
    public void mark(int readAheadLimit) throws IOException {
        if (readAheadLimit < 0){
            throw new IllegalArgumentException("Read-ahead limit < 0");
        }
        synchronized (lock) {
            ensureOpen();
            mark = next;
        }
    }

    // 重置當前位置
    public void reset() throws IOException {
        synchronized (lock) {
            ensureOpen();
            next = mark;
        }
    }

    // 關閉流
    public void close() {
        str = null;
    }
}

StringWriter

import java.io.IOException;
import java.io.Writer;

public class StringWriter extends Writer {

    private StringBuffer buf;


    public StringWriter() {
        buf = new StringBuffer();
        lock = buf;
    }

    public StringWriter(int initialSize) {
        if (initialSize < 0) {
            throw new IllegalArgumentException("Negative buffer size");
        }
        buf = new StringBuffer(initialSize);
        lock = buf;
    }

    // 寫入字符
    public void write(int c) {
        buf.append((char) c);
    }

    // 寫入數組中的字符
    public void write(char cbuf[], int off, int len) {
        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
            ((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        buf.append(cbuf, off, len);
    }

    //寫入字符串
    public void write(String str) {
        buf.append(str);
    }

    // 在指定位置寫入字符串
    public void write(String str, int off, int len)  {
        buf.append(str.substring(off, off + len));
    }

    // 增加字符串序列
    public StringWriter append(CharSequence csq) {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }

    // 在指定位置增加字符串序列
    public StringWriter append(CharSequence csq, int start, int end) {
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }

    // 增加字符
    public StringWriter append(char c) {
        write(c);
        return this;
    }

    public String toString() {
        return buf.toString();
    }

    public StringBuffer getBuffer() {
        return buf;
    }

    public void flush() {
    }


    public void close() throws IOException {
    }
}

適配器模式在Spring的實際應用

在Spring中也有適配器的大量應用,在Spring的AOP中,由於Advisor需要的是MethodInterceptor對象,所有每一個Advisor中的Advice都要適配成對應的MethodInterceptor對象。
這裏寫圖片描述

AdvisorAdapter

package org.springframework.aop.framework.adapter;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;

public abstract interface AdvisorAdapter
{
  public abstract boolean supportsAdvice(Advice paramAdvice);

  public abstract MethodInterceptor getInterceptor(Advisor paramAdvisor);
}
}

MethodBeforeAdviceAdapter

package org.springframework.aop.framework.adapter;

import java.io.Serializable;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;

class MethodBeforeAdviceAdapter
  implements AdvisorAdapter, Serializable
{
  public boolean supportsAdvice(Advice advice)
  {
    return advice instanceof MethodBeforeAdvice;
  }

  public MethodInterceptor getInterceptor(Advisor advisor)
  {
    MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
    return new MethodBeforeAdviceInterceptor(advice);
  }
}

在Spring的ORM包中,對於JPA的支持也是採用了適配器模式,首先定義了一個抽象類的JpaVendorAdapter,然後不同的持久層框架都繼承了此類:

JpaVendorAdapter

package org.springframework.orm.jpa;

import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;

public abstract interface JpaVendorAdapter
{
  // 返回一個具體的持久層提供者
  public abstract PersistenceProvider getPersistenceProvider();

  // 返回持久層提供者的包名
  public abstract String getPersistenceProviderRootPackage();

  // 返回持久層提供者的屬性
  public abstract Map<String, ?> getJpaPropertyMap();

  // 返回JpaDialect
  public abstract JpaDialect getJpaDialect();

  // 返回持久層管理器工廠
  public abstract Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface();

  // 返回持久層管理器
  public abstract Class<? extends EntityManager> getEntityManagerInterface();

  // 自定義回調方法
  public abstract void postProcessEntityManagerFactory(EntityManagerFactory paramEntityManagerFactory);
}

AbstractJpaVendorAdapter

package org.springframework.orm.jpa.vendor;

import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaVendorAdapter;

public abstract class AbstractJpaVendorAdapter implements JpaVendorAdapter {
    private Database database; //定義數據庫
    private String databasePlatform; //定義數據庫的平臺
    private boolean generateDdl; //是否生成ddl
    private boolean showSql; //是否顯示sql

    public AbstractJpaVendorAdapter() {
        this.database = Database.DEFAULT;

        this.generateDdl = false;

        this.showSql = false;
    }

    /* 設定下列數據庫
     * DB2, DERBY, H2, HSQL, INFORMIX, MYSQL, ORACLE, POSTGRESQL, SQL_SERVER,SYBASE
     */
    public void setDatabase(Database database) {
        this.database = database;
    }

    // 返回要操作的數據庫
    protected Database getDatabase() {
        return this.database;
    }

    public void setDatabasePlatform(String databasePlatform) {
        this.databasePlatform = databasePlatform;
    }

    protected String getDatabasePlatform() {
        return this.databasePlatform;
    }

    public void setGenerateDdl(boolean generateDdl) {
        this.generateDdl = generateDdl;
    }

    protected boolean isGenerateDdl() {
        return this.generateDdl;
    }

    public void setShowSql(boolean showSql) {
        this.showSql = showSql;
    }

    protected boolean isShowSql() {
        return this.showSql;
    }

    public String getPersistenceProviderRootPackage() {
        return null;
    }

    public Map<String, ?> getJpaPropertyMap() {
        return null;
    }

    public JpaDialect getJpaDialect() {
        return null;
    }

    public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() {
        return EntityManagerFactory.class;
    }

    public Class<? extends EntityManager> getEntityManagerInterface() {
        return EntityManager.class;
    }

    // 設定emf,基於Eclipse的模型框架。它是Eclipse MDA(Model Driven Architecture)的一個重要組成部分
    public void postProcessEntityManagerFactory(EntityManagerFactory emf) {
    }
}

EclipseLinkJpaVendorAdapter

package org.springframework.orm.jpa.vendor;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.persistence.EntityManager;
import org.eclipse.persistence.jpa.JpaEntityManager;
import org.springframework.orm.jpa.JpaDialect;

public class EclipseLinkJpaVendorAdapter extends AbstractJpaVendorAdapter {
    // 設定持久層提供者
    private final javax.persistence.spi.PersistenceProvider persistenceProvider;
    // 設定持久層方言
    private final JpaDialect jpaDialect;

    public EclipseLinkJpaVendorAdapter() {
        this.persistenceProvider = new org.eclipse.persistence.jpa.PersistenceProvider();

        this.jpaDialect = new EclipseLinkJpaDialect();
    }

    public javax.persistence.spi.PersistenceProvider getPersistenceProvider() {
        return this.persistenceProvider;
    }

    // 返回JPA的屬性
    public Map<String, Object> getJpaPropertyMap() {
        Map jpaProperties = new HashMap();
        // 判斷平臺是否爲空
        if (getDatabasePlatform() != null) {
            jpaProperties.put("eclipselink.target-database",
                    getDatabasePlatform());
        } else if (getDatabase() != null) {
            String targetDatabase = determineTargetDatabaseName(getDatabase());
            if (targetDatabase != null) {
                jpaProperties
                        .put("eclipselink.target-database", targetDatabase);
            }
        }
        // 判斷是否生成ddl
        if (isGenerateDdl()) {
            jpaProperties.put("eclipselink.ddl-generation", "create-tables");

            jpaProperties.put("eclipselink.ddl-generation.output-mode",
                    "database");
        }

        if (isShowSql()) {
            jpaProperties.put("eclipselink.logging.level",
                    Level.FINE.toString());
        }

        return jpaProperties;
    }

    //設定數據庫
    protected String determineTargetDatabaseName(Database database)    
    {     
        switch (1.$SwitchMap$org$springframework$orm$jpa$vendor$Database[database.ordinal()]) 
        {       
        case 1:                                                                                   
            return "DB2";                                                                            
        case 2:                                                                                    
          return "Derby";                                                                          
        case 3:                                                                                    
          return "HSQL";                                                                           
        case 4:                                                                                    
          return "Informix";                                                                       
        case 5:                                                                                    
          return "MySQL4";                                                                         
        case 6:                                                                                    
          return "Oracle";                                                                         
        case 7:                                                                                    
          return "PostgreSQL";                                                                     
        case 8:                                                                                    
          return "SQLServer";                                                                      
        case 9:                                                                                    
          return "Sybase"; 
        }                                                                       
        return null;  
    }   

    public JpaDialect getJpaDialect() {
        return this.jpaDialect;
    }

    public Class<? extends EntityManager> getEntityManagerInterface() {
        return JpaEntityManager.class;
    }
}

HibernateJpaVendorAdapter

package org.springframework.orm.jpa.vendor;

import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.InformixDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle9iDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.ejb.HibernateEntityManager;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.orm.jpa.JpaDialect;

public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
    //設定持久層提供者
    private final PersistenceProvider persistenceProvider;
    //設定持久層方言
    private final JpaDialect jpaDialect;

    public HibernateJpaVendorAdapter() {
        this.persistenceProvider = new HibernatePersistence();
        this.jpaDialect = new HibernateJpaDialect();
    }

    //返回持久層方言
    public PersistenceProvider getPersistenceProvider() {
        return this.persistenceProvider;
    }

    //返回持久層提供者
    public String getPersistenceProviderRootPackage() {
        return "org.hibernate";
    }

    //返回JPA的屬性
    public Map<String, Object> getJpaPropertyMap() {
        Map jpaProperties = new HashMap();

        if (getDatabasePlatform() != null) {
            jpaProperties.put("hibernate.dialect", getDatabasePlatform());
        } else if (getDatabase() != null) {
            Class databaseDialectClass = determineDatabaseDialectClass(getDatabase());
            if (databaseDialectClass != null) {
                jpaProperties.put("hibernate.dialect",
                        databaseDialectClass.getName());
            }
        }

        if (isGenerateDdl()) {
            jpaProperties.put("hibernate.hbm2ddl.auto", "update");
        }
        if (isShowSql()) {
            jpaProperties.put("hibernate.show_sql", "true");
        }

        return jpaProperties;
    }

    //設定數據庫
    protected Class determineDatabaseDialectClass(Database database)     
    {                                                                                       
        switch (1.$SwitchMap$org$springframework$orm$jpa$vendor$Database[database.ordinal()]) 
        {                                                                                     
        case 1:                                                                             
          return DB2Dialect.class;                                                            
        case 2:                                                                               
          return DerbyDialect.class;                                                          
        case 3:                                                                               
          return H2Dialect.class;                                                             
        case 4:                                                                               
          return HSQLDialect.class;                                                           
        case 5:                                                                               
          return InformixDialect.class;                                                       
        case 6:                                                                               
          return MySQLDialect.class;                                                          
        case 7:                                                                               
          return Oracle9iDialect.class;                                                       
        case 8:                                                                               
          return PostgreSQLDialect.class;                                                     
        case 9:                                                                               
          return SQLServerDialect.class;                                                      
        case 10:                                                                              
          return SybaseDialect.class; }                                                       
        return null;              
    }

    //返回JPA方言
    public JpaDialect getJpaDialect() {
        return this.jpaDialect;
    }

    //返回JPA實體管理器工廠
    public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() {
        return HibernateEntityManagerFactory.class;
    }

    //返回JPA實體管理器
    public Class<? extends EntityManager> getEntityManagerInterface() {
        return HibernateEntityManager.class;
    }
}

適配器模式在JUnit中的實際應用

通俗而言,就是要適配成TestCase類。這裏重點看TestCase的runTest()方法:

protected void runTest() throws Throwable {
        assertNotNull("TestCase.fName cannot be null", this.fName);
        Method runMethod = null;
        try {
            //獲取要測試的方法
            runMethod = getClass().getMethod(this.fName, (Class[]) null);
        } 
        catch (NoSuchMethodException e) {
            fail("Method \"" + this.fName + "\" not found");
        }
        //判斷要測試的方法是否爲公用方法
        if (!Modifier.isPublic(runMethod.getModifiers())) {
            fail("Method \"" + this.fName + "\" should be public");
        }
        //java反射機制
        try {
            runMethod.invoke(this, new Object[0]);
        } 
        catch (InvocationTargetException e) {
            e.fillInStackTrace();
            throw e.getTargetException();
        } 
        catch (IllegalAccessException e) {
            e.fillInStackTrace();
            throw e;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章