1. 程式人生 > >Spring 5 設計模式 - Structural

Spring 5 設計模式 - Structural

Spring 5 設計模式 - Structural

structural模式被用來定義物件(繼承或者組合)之間的關係。Structural模式確保部分的改變不會導致整體也跟著改變。

adapter

介面卡模式讓兩個不相容的類(因為介面不相容)一起工作。它像橋一樣工作於兩個不相容的介面之間。

帶來的好處:

  • 讓不相容的類一起工作
  • 提高舊程式碼的可重用性

Spring使用的介面卡模式

Spring內部大量使用了介面卡模式,比如JpaVendorAdapter、HibernateJpaVendorAdapter、HandlerInterceptorAdapter、SpringContextResourceAdapter等。

簡單的實現

adapter

先看舊的支付閘道器:

public interface PaymentGateway
{ void doPayment(Account account1, Account account2); } public class PaymentGatewayImpl implements PaymentGateway{ @Override public void doPayment(Account account1, Account account2){ System.out.println("Do payment using Payment Gateway"); } }

下面是新閘道器:

public interface
AdvancedPayGateway { void makePayment(String mobile1, String mobile2); } public class AdvancedPaymentGatewayAdapter implements AdvancedPayGateway { private PaymentGateway paymentGateway; public AdvancedPaymentGatewayAdapter(PaymentGateway paymentGateway) { this.paymentGateway = paymentGateway; } public void makePayment(String mobile1, String mobile2) { Account account1 = null;//get account number by mobile Account account2 = null;//get account number by mobile paymentGateway.doPayment(account1, account2); } }

下來是測試類:

public class AdapterPatternMain {
    public static void main(String[] args) {
        PaymentGateway paymentGateway = new PaymentGatewayImpl();
        AdvancedPayGateway advancedPayGateway = new AdvancedPaymentGatewayAdapter(paymentGateway);
        String mobile1 = null;
        String mobile2 = null;
        advancedPayGateway.makePayment(mobile1, mobile2);
    }
}

這樣,我們通過介面卡,使用新的方法,訪問了舊程式碼。

Bridge

橋模式用來解耦客戶程式碼和它的實現。就是說,把抽象和實現分開(繼承關係也分開)。Bridge模式優先考慮組合,而不是繼承。這樣,介面B的實現類或者介面B的修改,不影響抽象類A。橋模式組合一個抽象類A和一個介面B,使用一個介面C作為繼承抽象類A的具體類和實現介面B的類之間的一座橋。

帶來的好處

  • 允許你把實現和抽象分開
  • 提供修改兩端而不影響使用的客戶的靈活性
  • 允許向客戶隱藏實現細節

Spring中的應用

  • ViewRendererServlet,主要用於Portlet MVC
  • 日誌處理

簡單的實現

without

不使用橋模式,會有很深的繼承關係。
using

使用橋模式,在Bank介面和Account介面之間增加了一個關係。
Bridge

我們先看帳號:

public interface Account {
    Account openAccount();
    void accountType();
}

public class SavingAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("OPENED: SAVING ACCOUNT ");
        return new SavingAccount();
    }
    @Override
    public void accountType() {
        System.out.println("##It is a SAVING Account##");
    }
}

public class CurrentAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("OPENED: CURRENT ACCOUNT ");
        return new CurrentAccount();
    }
    @Override
    public void accountType() {
        System.out.println("##It is a CURRENT Account##");
    }
}

再看銀行:

public abstract class Bank {
    //Composition with implementor
    protected Account account;
    public Bank(Account account){
        this.account = account;
    }
    abstract Account openAccount();
}

public class IciciBank extends Bank {
    public IciciBank(Account account) {
        super(account);
    }
    @Override
    Account openAccount() {
        System.out.print("Open your account with ICICI Bank");
        return account;
    }
}

public class HdfcBank extends Bank {
    public HdfcBank(Account account) {
        super(account);
    }
    @Override
    Account openAccount() {
        System.out.print("Open your account with HDFC Bank");
        return account;
    }
}

我們的測試程式碼

public class BridgePatternMain {
    
    public static void main(String[] args) {
        Bank icici = new IciciBank(new CurrentAccount());
        Account current = icici.openAccount();
        current.accountType();
        Bank hdfc = new HdfcBank(new SavingAccount());
        Account saving = hdfc.openAccount();
        saving.accountType();
    }
}

Composite

相同型別的一組物件被客戶當作一個物件看待,這些物件組合成一個樹結構。

簡單的實現

Composite

先看帳號:

public interface Account {
    void accountType();
}

public class SavingAccount implements Account {
    @Override
    public void accountType() {
        System.out.println("SAVING ACCOUNT");
    }
}

public class CurrentAccount implements Account {
    @Override
    public void accountType() {
        System.out.println("CURRENT ACCOUNT");
    }
}

CompositeBankAccount被當作Composite,實現了Account介面:

public class CompositeBankAccount implements Account {
    //Collection of child accounts.
    private List<Account> childAccounts = new ArrayList<Account>();
    @Override
    public void accountType() {
        for (Account account : childAccounts) {
            account.accountType();
        }
    }
    //Adds the account to the composition.
    public void add(Account account) {
        childAccounts.add(account);
    }
    //Removes the account from the composition.
    public void remove(Account account) {
        childAccounts.remove(account);
    }
}

測試程式碼

public class CompositePatternMain {
    
    public static void main(String[] args) {
        SavingAccount savingAccount1 = new SavingAccount();
        SavingAccount savingAccount2 = new SavingAccount();

        CurrentAccount currentAccount1 = new CurrentAccount();
        CurrentAccount currentAccount2 = new CurrentAccount();

        CompositeBankAccount compositeBankAccount1 = new CompositeBankAccount();
        CompositeBankAccount compositeBankAccount2 = new CompositeBankAccount();
        CompositeBankAccount compositeBankAccount = new CompositeBankAccount();

        compositeBankAccount1.add(savingAccount1);
        compositeBankAccount1.add(currentAccount1);
        compositeBankAccount2.add(currentAccount2);
        compositeBankAccount2.add(savingAccount2);
        compositeBankAccount.add(compositeBankAccount2);
        compositeBankAccount.add(compositeBankAccount1);
        compositeBankAccount.accountType();
    }
}

Decorator

裝飾模式允許你在執行時動態或者靜態地增加或者減少一個物件的行為。裝飾模式通過繼承組合物件,允許你把某一領域的功能分到不同的具體實現類。
裝飾模式也叫Wrapper。

比如銀行把顧客分成三類:senior citizens、privileged和young。該銀行啟動了老年人儲蓄賬戶計劃,如果開一個儲蓄賬戶,可以獲得最多1000元的醫療保險。對於privileged顧客,額度是1600元,還可以透支84元。young顧客沒有任何計劃。
我們增加一個子類SavingAccount,類結構圖可能是這樣的:
without using the Decorator

如果使用裝飾模式,可以這樣設計:
using the Decorator

這樣,AccountDecorator和Account既是Is-a的關係(繼承),也是Has-a的關係(不改變舊程式碼,通過組合增加新功能)。

UML圖如下
Decorator

簡單的實現

public interface Account {
    String getTotalBenefits();
}

public class SavingAccount implements Account {
    @Override
    public String getTotalBenefits() {
        return "This account has 4% interest rate with per day $5000 withdrawal limit";
    }
}

public class CurrentAccount implements Account {
    @Override
    public String getTotalBenefits() {
        return "There is no withdrawal limit for current account";
    }
}

下來是裝飾類

public abstract class AccountDecorator implements Account {
    abstract String applyOtherBenefits();
}

public class SeniorCitizen extends AccountDecorator {
    Account account;
    public SeniorCitizen(Account account) {
        super();
        this.account = account;
    }
    public String getTotalBenefits() {
        return account.getTotalBenefits() + " other benefits are " + applyOtherBenefits();
    }
    String applyOtherBenefits() {
        return " an medical insurance of up to $1,000 for Senior Citizen";
    }
}

public class Privilege extends AccountDecorator {
    Account account;
    public Privilege(Account account) {
        this.account = account;
    }
    public String getTotalBenefits() {
        return account.getTotalBenefits() + " other benefits are " + applyOtherBenefits();
    }
    String applyOtherBenefits() {
        return " an accident insurance of up to $1,600 and an overdraft facility of $84";
    }
}

測試程式碼

public class DecoratorPatternMain {
    public static void main(String[] args) {
        Account basicSavingAccount = new SavingAccount();
        System.out.println(basicSavingAccount.getTotalBenefits());

        Account seniorCitizenSavingAccount = new SavingAccount();
        seniorCitizenSavingAccount = new SeniorCitizen(seniorCitizenSavingAccount);
        System.out.println(seniorCitizenSavingAccount.getTotalBenefits());

        Account privilegeCitizenSavingAccount = new SavingAccount();
        privilegeCitizenSavingAccount = new Privilege(privilegeCitizenSavingAccount);
        System.out.println(privilegeCitizenSavingAccount.getTotalBenefits());
    }
}

Spring中的應用

  • 事務、快取同步、安全等功能都使用了裝飾模式
  • AOP功能也通過CGLib使用了裝飾模式
  • BeanDefinitionDecorator:通過自定義屬性裝飾bean定義
  • WebSocketHandlerDecorator:給WebSocketHandler增加附加行為

Facade

Facade模式使用介面簡化客戶和子系統之間的互動。

without Facade

使用Facade模式以後:
with Facade

簡單的實現

public class PaymentService {
    public static boolean doPayment() {
        return true;
    }
}

public class AccountService {
    public static Account getAccount(String accountId) {
        return new SavingAccount();
    }
}

public class TransferService {
    public static void transfer(int amount, Account fromAccount, Account toAccount) {
        System.out.println("Transfering Money");
    }
}

增加Facade類

public interface BankingServiceFacade {
    void moneyTransfer();
}

public class BankingServiceFacadeImpl implements BankingServiceFacade {
    @Override
    public void moneyTransfer() {
        if(PaymentService.doPayment()) {
            Account fromAccount = AccountService.getAccount("1");
            Account toAccount = AccountService.getAccount("2");
            TransferService.transfer(1000, fromAccount, toAccount);
        }
    }
}

增加Facade的Client:

public class FacadePatternClient {
    public static void main(String[] args) {
        BankingServiceFacade serviceFacade = new BankingServiceFacadeImpl();
        serviceFacade.moneyTransfer();
    }
}

Proxy

Proxy模式提供一個物件,擁有另一個類的功能。這樣可以向外部隱藏實際的物件。

Proxy

簡單的實現

public interface Account {
    void accountType();
}

public class SavingAccount implements Account {
    public void accountType() {
        System.out.println("SAVING ACCOUNT");
    }
}

代理類

public class ProxySavingAccount implements Account {
    private Account savingAccount;
    public void accountType() {
        if(savingAccount == null){
            savingAccount = new SavingAccount();
        }
        savingAccount.accountType();
    }
}

Spring中的應用

Spring AOP使用了代理模式。另外,HTTP Invoker等很多功能也使用了代理模式。