1. 程式人生 > >Spring中常見的設計模式——介面卡模式

Spring中常見的設計模式——介面卡模式

一、介面卡模式的應用場景  

  介面卡模式(Adapter Pattern)是指將一個類的介面轉換成使用者期待的另一個介面,使原本介面不相容的類可以一起工作,屬於構造設計模式。

  介面卡適用於以下幾種業務場景:

  • 已經存在的類的方法和需求不匹配(方法結果相同或相似)的情況。
  • 介面卡模式不是軟體初始階段應該考慮的設計模式,是隨著軟體的開發,由於不同產品、不同廠家造成功能類似而介面不同的問題的解決方案,有點亡羊補牢的感覺。

二、重構第三方登入自由適配的業務場景

  將原來的單一支援使用者名稱和密碼登入,擴充套件為可以支援微信和手機登入。

  建立統一返回結果ResultMsg:

@Data
public class ResultMsg {
private Integer code;
private String msg;
private Object data;

public ResultMsg(Integer code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
}

  老系統登入程式碼如下:

public class SignInService {
    public ResultMsg regist(String userName, String passWord) {
        return new ResultMsg(200, "註冊成功", new Member());
    }

    public ResultMsg login(String userName, String passWord) {
        return null;
    }
}

  為了遵循開閉原則,我們不修改老系統程式碼,下面是Member類:

@Data
public class Member {
    private String userName;
    private String passWord;
    private String mid;
    private String info;
}

  我們優雅的根據不同登入方式建立不同的“Adapter”,首先建立LoginAdapter:

public interface LoginAdapter {
    boolean support(Object adapter);

    ResultMsg login(String id, Object adapter);
}

  手機登入:

public class LoginForTelAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForTelAdapter;
    }

    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }
}

  微信登入:

public class LoginForWechatAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForWechatAdapter;
    }

    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }
}

  接著,建立第三方登入相容介面IPassportForThid:

public interface IPassportForThird {
    ResultMsg loginForTel(String telephone, String code);

    ResultMsg loginForWechat(String id);

    ResultMsg loginForResist(String userName, String passWord);
}

  實現相容PassportForThirdAdapter:

public class PassportForThirdAdapter extends SignInService implements IPassportForThird {
    @Override
    public ResultMsg loginForTel(String telephone, String code) {
        return null;
    }

    @Override
    public ResultMsg loginForWechat(String id) {
        return null;
    }

    @Override
    public ResultMsg loginForResist(String userName, String passWord) {
        super.regist(userName, passWord);
        return super.login(userName, passWord);
    }

    //這裡使用簡單工廠及策略模式
    private ResultMsg procssLogin(String key, Class<? extends LoginAdapter> clazz) {
        try {
            LoginAdapter adapter = clazz.newInstance();
            if (adapter.support(adapter)) {
                return adapter.login(key, adapter);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

  前面每個介面卡都加上了support()方法,用來判斷箭筒。support()方法的引數也是Object型別,而support()來自介面。介面卡並不依賴介面,我們使用介面只是為了程式碼規範。

三、介面卡模式在原始碼中的體現

  Spring中的AOP中AdvisorAdapter類,它有三個實現:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。

  先看頂層介面AdviceAdapter的原始碼:

public interface AdvisorAdapter {
    boolean supportsAdvice(Advice var1);

    MethodInterceptor getInterceptor(Advisor var1);
}

  再看MethodBeforAdviceAdapter:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
}

  其他兩個類就不看了。Spring會根據不同的AOP配置來使用對應的“Advice”,與策略模式不同的是,一個方法可以同時擁有多個“Advice”。

四、介面卡模式的優缺點

  優點:

  • 能提高類的透明性和複用性,現有的類會被複用但不需要改變。
  • 目標類和介面卡類解耦,可以提高程式的擴充套件性。
  • 在很多業務場景中符合開閉原則。

  缺點:

  • 在介面卡程式碼編寫過程中需要進行全面考慮,可能會增加系統複雜度。
  • 增加程式碼閱讀難度,過多使用介面卡會使系統程式碼變得凌亂。