Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android基礎系列]設計模式(二)

[Android基礎系列]設計模式(二)

編輯:關於Android編程

正文

結構型包含以下類型:

適配器 Adapter Class/Object 橋接 Bridge 組合 Composite 裝飾 Decorator 外觀 Facade 享元 Flyweight 代理 Proxy

適配器

適配器

個人意見:最適合在工作完成了一部分,但是兩套系統接口規范不完全相適的情況下,使用適配器“協調”一下,在從零開始的情況下,盡可能避免接口不適配的情況。

demo:

目標

package adapter;
/** 
 * @ClassName: Target 
 * @Description: 當前系統中所期望的接口和api,也是類適配器需要“提供”的內容  
 * @author leobert.lan
 * @version 1.0
 */
public interface Target {

    void targetApi1();

    void targetApi2();

}

已有模塊

package adapter;
/** 
 * @ClassName: Adaptee 
 * @Description: 已有模塊的入口,但和期待的不完全一致
 * @date 2016年5月19日 下午1:15:38
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Adaptee {

    public void Api1() {
        System.out.println("call api1");
    } 

}

以類適配器模式實現

package adapter;

/**
 * @ClassName: Adapter
 * @Description: 類適配器模式demo
 * @date 2016年5月19日 下午1:17:05
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Adapter extends Adaptee implements Target {

    @Override
    public void targetApi1() {
        Api1();
    }

    @Override
    public void targetApi2() {
        System.out.println("targetApi2, do nothing,complete it for your business");
    }

}

以對象適配器模式實現

package adapter;

/**
 * @ClassName: Adapter2
 * @Description: 對象適配器模式,相當於包裝了一次
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Adapter2 implements Target{

    private Adaptee adaptee;

    public Adapter2(Adaptee adaptee) {
        this.adaptee = adaptee;
    }


    @Override
    public void targetApi1() {
        this.adaptee.Api1();
    }

    @Override
    public void targetApi2() {
        System.out.println("targetApi2, do nothing,complete it for your business");
    }

}

測試一下

package adapter;
/** 
 * @ClassName: Test 
 * @Description: TODO
 * @date 2016年5月19日 下午1:27:56
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        Target apis = new Adapter();
        apis.targetApi1();
        apis.targetApi2();

        Target apiswrapper = new Adapter2(new Adaptee());
        apiswrapper.targetApi1();
        apiswrapper.targetApi2();
    }

}

兩種實現的結果是一致的

call api1
targetApi2, do nothing,complete it for your business
call api1
targetApi2, do nothing,complete it for your business

使用對象適配器模式會更靈活一些

值得一提的是:適配器中有一種缺省適配器的實現方法,當然和以上兩種不屬於一個范疇,它是用來實現定制化需求的。舉個例子:設計之初抽象出了一個接口類,其中有3個方法,但在某些特殊情況下,只會調用一個方法。再定義一個接口是沒有太多道理的,而傻乎乎的去實現會出現很多空方法,甚至你為了避免將來產生誤解,還需要額外的注釋說明這些方法在某種情況下不會被調用。
這種情況下你需要缺省適配器。

定義一個抽象父類實現接口:

package adapter;
/** 
 * @ClassName: AbsTargetAdapter 
 * @Description: 缺省適配器的抽象父類
 * @date 2016年5月19日 下午1:33:22
 *  
 * @author leobert.lan
 * @version 1.0
 */
public abstract class AbsTargetAdapter implements Target{

    @Override
    public void targetApi1() {
        // TODO Auto-generated method stub

    }

    @Override
    public void targetApi2() {
        // TODO Auto-generated method stub

    }

}

這樣他的子類就可以靈活的根據實際情況來實現需要的功能。如果有某個方法是必須要實現,且不同場景邏輯不一樣,那就不要在抽象父類中實現它。

GOF
意圖
將一個類的接口轉換成客戶希望的另外一個接口。Adapter 模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。
適用性
你想使用一個已經存在的類,而它的接口不符合你的需求。
你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作。
(僅適用於對象Adapter )你想使用一些已經存在的子類,但是不可能對每一個都進行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。

橋接

 

這真的是一個復雜系統才會用到的,思來想去我刪掉了此處的demo,因為我的理解很可能是錯誤的。

TODO:重新閱讀GOF相關部分

組合

組合
直接上demo

package composite;
/** 
 * @ClassName: IComponent 
 * @Description: TODO
 * @date 2016年5月20日 下午12:59:36
 *  
 * @author leobert.lan
 * @version 1.0
 */
public interface IComponent {

    void doSomething();

}

Compositer

package composite;

import java.util.ArrayList;

/** 
 * @ClassName: Compositer 
 * @Description: TODO
 * @date 2016年5月20日 下午1:02:55
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Compositer implements IComponent{

    private ArrayList tree = new ArrayList<>();

    @Override
    public void doSomething() {
        for (IComponent leaf :tree) {
            leaf.doSomething();
        }
    }

    public void add(IComponent leaf) {
        tree.add(leaf);
    }

    public void remove(LeafClass leaf) {
        tree.remove(leaf);
    }

}

leaf

package composite;
/** 
 * @ClassName: LeafClass 
 * @Description: TODO
 * @date 2016年5月20日 下午1:02:24
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class LeafClass implements IComponent{

    @Override
    public void doSomething() {
        System.out.println("i am doing something");
    }

}

測試一下:

package composite;
/** 
 * @ClassName: Test 
 * @Description: TODO
 * @date 2016年5月20日 下午1:06:38
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        Compositer compositer = new Compositer();
        Compositer compositer2 = new Compositer();
        Compositer compositer3 = new Compositer();
        LeafClass leaf1 = new LeafClass();
        LeafClass leaf2 = new LeafClass();
        LeafClass leaf3 = new LeafClass();
        LeafClass leaf4 = new LeafClass();

        //可以很隨意的組合

        compositer2.add(leaf1);
        compositer2.add(leaf2);
        compositer3.add(leaf4);

        compositer2.add(compositer3);

        compositer.add(leaf3);

        compositer.add(compositer2);

        compositer.doSomething();

    }

}

我們發現不僅能“裝葉子”

意圖
將對象組合成樹形結構以表示“部分-整體”的層次結構。Composite 使得用戶對單個對象和組合對象的使用具有一致性
適用性
你想表示對象的部分-整體層次結構。
你希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。

裝飾

裝飾者
這個就厲害了
上demo
模擬一個屏幕繪制的例子

package decorator;
/** 
 * @ClassName: IWindow 
 * @Description: TODO
 * @date 2016年5月20日 下午1:42:44
 *  
 * @author leobert.lan
 * @version 1.0
 */
public interface IWindow {

    void drawWindow();

    //Test
    void checkWindowType();

}

抽象裝飾者

package decorator;

/**
 * @ClassName: AbsSimpleWindowDecorator
 * @Description: TODO
 * @date 2016年5月20日 下午1:44:23
 * 
 * @author leobert.lan
 * @version 1.0
 */
public abstract class AbsSimpleWindowDecorator implements IWindow {

    protected IWindow windowToBeDecorated;

    public AbsSimpleWindowDecorator(IWindow window) {
        this.windowToBeDecorated = window;
    }

    @Override
    public void drawWindow() {
        windowToBeDecorated.drawWindow();
    }

    @Override
    public void checkWindowType() {
        System.out.print("origin:");
        windowToBeDecorated.checkWindowType();
    }

}

實現裝飾者

package decorator;
/** 
 * @ClassName: HorizontalWindow 
 * @Description: TODO
 * @date 2016年5月20日 下午1:53:38
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class HorizontalWindow extends AbsSimpleWindowDecorator{

    public HorizontalWindow(IWindow window) {
        super(window);
    }

    @Override
    public void drawWindow() {
        super.drawWindow();
        drawHbar();
    }

    private void drawHbar() {
        System.out.println("drawing hbar");
    }

    @Override
    public void checkWindowType() {
        super.checkWindowType();
        System.out.print("now");
        System.out.println("this is :"+getClass().getSimpleName());
    }

}


package decorator;
/** 
 * @ClassName: VertivalWindow 
 * @Description: TODO
 * @date 2016年5月20日 下午1:53:07
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class VerticalWindow extends AbsSimpleWindowDecorator{

    public VerticalWindow(IWindow window) {
        super(window);
    }

    @Override
    public void drawWindow() {
        super.drawWindow();
        drawVbar();
    }

    private void drawVbar() {
        System.out.println("drawing vbar");
    }

    @Override
    public void checkWindowType() {
        super.checkWindowType();
        System.out.print("now");
        System.out.println("this is :"+getClass().getSimpleName());
    }

}

實際的已有的類,我們的裝飾對象

package decorator;
/** 
 * @ClassName: SimpleWindow 
 * @Description: TODO
 * @date 2016年5月20日 下午1:43:38
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class SimpleWindow implements IWindow{

    @Override
    public void drawWindow() {
        // TODO Auto-generated method stub
        System.out.println("on Drawing ...");
    }

    @Override
    public void checkWindowType() {
        System.out.println("this is :"+getClass().getSimpleName());
    }

}

測試一下

package decorator;
/** 
 * @ClassName: Test 
 * @Description: TODO
 * @date 2016年5月20日 下午1:56:48
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        IWindow simpleWindow  = new SimpleWindow();
        IWindow horizentalWindow = new HorizontalWindow(simpleWindow);
        IWindow verticalWindow  = new VerticalWindow(simpleWindow);

        simpleWindow.drawWindow();
        simpleWindow.checkWindowType();

        System.out.println();

        horizentalWindow.drawWindow();
        horizentalWindow.checkWindowType();

        System.out.println();

        verticalWindow.drawWindow();
        verticalWindow.checkWindowType();
    }

}

on Drawing …
this is :SimpleWindow

on Drawing …
drawing hbar
origin:this is :SimpleWindow
nowthis is :HorizontalWindow

on Drawing …
drawing vbar
origin:this is :SimpleWindow
nowthis is :VerticalWindow


意圖
動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator 模式相比生成子類更為靈活。
適用性
在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
處理那些可以撤消的職責。
當不能采用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,為支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隱藏,或類定義不能用於生成子類。

外觀

外觀

一個復雜的系統,可以使用外觀模式提供一些簡化使用的方案,當然,在熟悉內部細節的情況下,實現定制化需求可以跳過外觀層

demo:

package facade;
/** 
 * @ClassName: Class1 
 * @Description: TODO
 * @date 2016年5月23日 上午9:59:47
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Class1 {

    public boolean doThing1() {
        //...
        return true;
    }

}

package facade;

/**
 * @ClassName: Class2
 * @Description: TODO
 * @date 2016年5月23日 上午9:59:56
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Class2 {

    public void doThing2(int i) {

    }

}


package facade;

/**
 * @ClassName: Class3
 * @Description: TODO
 * @date 2016年5月23日 上午10:00:04
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Class3 {
    public int doThing3(boolean b) {
        return 1;
    }

}

facade:

package facade;
/** 
 * @ClassName: SysFacade 
 * @Description: TODO
 * @date 2016年5月23日 上午10:01:04
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class SysFacade {
    private final Class1 c1;
    private final Class2 c2;
    private final Class3 c3;

    public SysFacade() {
        c1 = new Class1();
        c2 = new Class2();
        c3 = new Class3();
    }

    public void doSomething() {
        boolean b = c1.doThing1();
        int i = c3.doThing3(b);
        c2.doThing2(i);
    }

}

測試一下:

package facade;
/** 
 * @ClassName: Test 
 * @Description: TODO
 * @date 2016年5月23日 上午10:28:07
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        SysFacade facade = new SysFacade();

        //目的就是讓你簡單的使用一個較為復雜的系統,不用關心系統內部的運作
        //當然,定制性的需求可以越過facade層
        facade.doSomething();
    }

}

沒做輸出

意圖
為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
適用性
當你要為一個復雜子系統提供一個簡單接口時。子系統往往因為不斷演化而變得越來越復雜。大多數模式使用時都會產生更多更小的類。這使得子系統更具可重用性,也更容易對子系統進行定制,但這也給那些不需要定制子系統的用戶帶來一些使用上的困難。Facade 可以提供一個簡單的缺省視圖,這一視圖對大多數用戶來說已經足夠,而那些需要更多的可定制性的用戶可以越過facade層。
客戶程序與抽象類的實現部分之間存在著很大的依賴性。引入facade 將這個子系統與客戶以及其他的子系統分離,可以提高子系統的獨立性和可移植性。
當你需要構建一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,你可以讓它們僅通過facade進行通訊,從而簡化了它們之間的依賴關系。

享元

享元

demo:
模擬一個咖啡店下單的例子

咖啡店

package flyweight;

import java.util.List;
import java.util.Vector;

/**
 * @ClassName: CoffeeShop
 * @Description: TODO
 * @date 2016年5月23日 上午10:41:57
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class CoffeeShop {
    private final List orders = new Vector();
    private final Menu menu = new Menu();

    public void takeOrder(String flavourName, int table) {
        CoffeeFlavour flavour = menu.lookup(flavourName);
        Order order = new Order(table, flavour);
        orders.add(order);
    }

    public void service() {
        for (Order order : orders)
            order.serve();
    }

    public String report() {
        return "\ntotal CoffeeFlavour objects made: " + menu.totalCoffeeFlavoursMade();
    }
}

咖啡口味

package flyweight;

/**
 * @ClassName: CoffeeFlavour
 * @Description: 咖啡口味
 * @date 2016年5月23日 上午10:35:00
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class CoffeeFlavour {
    private final String flavour;

    public CoffeeFlavour(String flavour) {
        this.flavour = flavour;
    }

    @Override
    public String toString() {
        return flavour;
    }

}

訂單

package flyweight;

/**
 * @ClassName: Order
 * @Description: 訂單
 * @date 2016年5月23日 上午10:40:52
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Order {
    private final int tableNumber;
    private final CoffeeFlavour flavour;

    public Order(int tableNumber, CoffeeFlavour flavor) {
        this.tableNumber = tableNumber;
        this.flavour = flavor;
    }

    public void serve() {
        System.out.println("Serving " + flavour + " to table " + tableNumber);
    }
}

menu

package flyweight;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName: Menu
 * @Description: TODO
 * @date 2016年5月23日 上午10:40:22
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Menu {
    private Map flavours = new ConcurrentHashMap();

    public CoffeeFlavour lookup(String flavorName) {
        if (!flavours.containsKey(flavorName))
            flavours.put(flavorName, new CoffeeFlavour(flavorName));
        return flavours.get(flavorName);
    }

    public int totalCoffeeFlavoursMade() {
        return flavours.size();
    }
}

測試一下:

package flyweight;

/**
 * @ClassName: Test
 * @Description: TODO
 * @date 2016年5月23日 上午10:42:44
 * 
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        CoffeeShop shop = new CoffeeShop();

        shop.takeOrder("Cappuccino", 2);
        shop.takeOrder("Frappe", 1);
        shop.takeOrder("Espresso", 1);
        shop.takeOrder("Frappe", 897);
        shop.takeOrder("Cappuccino", 97);
        shop.takeOrder("Frappe", 3);
        shop.takeOrder("Espresso", 3);
        shop.takeOrder("Cappuccino", 3);
        shop.takeOrder("Espresso", 96);
        shop.takeOrder("Frappe", 552);
        shop.takeOrder("Cappuccino", 121);
        shop.takeOrder("Espresso", 121);

        shop.service();
        System.out.println(shop.report());
    }

}

意圖
運用共享技術有效地支持大量細粒度的對象。
適用性
一個應用程序使用了大量的對象。
完全由於使用大量的對象,造成很大的存儲開銷。
對象的大多數狀態都可變為外部狀態。
如果刪除對象的外部狀態,那麼可以用相對較少的共享對象取代很多組對象。
應用程序不依賴於對象標識。由於Flyweight 對象可以被共享,對於概念上明顯有別的對象,標識測試將返回真值。

代理

代理

demo演示虛代理

package proxy;
/** 
 * @ClassName: IImage 
 * @Description: TODO
 * @date 2016年5月23日 上午10:52:04
 *  
 * @author leobert.lan
 * @version 1.0
 */
public interface IImage {

    void display();

}
package proxy;
/** 
 * @ClassName: RealImage 
 * @Description: TODO
 * @date 2016年5月23日 上午10:53:31
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class RealImage implements IImage{

    private String filename = null;
    /**
     * Constructor
     * @param filename
     */
    public RealImage(final String filename) { 
        this.filename = filename;
        loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private void loadImageFromDisk() {
        System.out.println("Loading   " + filename);
    }

    /**
     * Displays the image
     */
    public void display() { 
        System.out.println("Displaying " + filename); 
    }

}
package proxy;
/** 
 * @ClassName: ImageLoader 
 * @Description: 代理,wikipedia上面的例子命名為proxyImage,命名上更便於理解
 * @date 2016年5月23日 上午10:52:25
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class ImageLoader implements IImage {

    private RealImage image = null;
    private String filename = null;
    /**
     * Constructor
     * @param filename 
     */
    public ImageLoader(final String filename) { 
        this.filename = filename; 
    }

    /**
     * Displays the image
     */
    public void display() {
        if (image == null) {
           image = new RealImage(filename);
        } 
        image.display();
    }
}

測試一下

package proxy;

/** 
 * @ClassName: Test 
 * @Description: TODO
 * @date 2016年5月23日 上午10:56:53
 *  
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        final IImage IMAGE1 = new ImageLoader("HiRes_10MB_Photo1");
        final IImage IMAGE2 = new ImageLoader("HiRes_10MB_Photo2");

        IMAGE1.display(); // loading necessary
        IMAGE1.display(); // loading unnecessary
        IMAGE2.display(); // loading necessary
        IMAGE2.display(); // loading unnecessary
        IMAGE1.display(); // loading unnecessary
    }

}

Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1


意圖:

為其他對象提供一種代理以控制對這個對象的訪問。
適用性:
在需要用比較通用和復雜的對象指針代替簡單的指針的時候,使用Proxy模式。下面是一 些可以使用Proxy 模式常見情況:
1) 遠程代理(Remote Proxy )為一個對象在不同的地址空間提供局部代表。 NEXTSTEP[Add94] 使用NXProxy 類實現了這一目的。Coplien[Cop92] 稱這種代理為“大使” (Ambassador )。
2 )虛代理(Virtual Proxy )根據需要創建開銷很大的對象。在動機一節描述的ImageProxy 就是這樣一種代理的例子。
3) 保護代理(Protection Proxy )控制對原始對象的訪問。保護代理用於對象應該有不同 的訪問權限的時候。例如,在Choices 操作系統[ CIRM93]中KemelProxies為操作系統對象提供 了訪問保護。
4 )智能指引(Smart Reference )取代了簡單的指針,它在訪問對象時執行一些附加操作。 它的典型用途包括:
對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它(也稱為SmartPointers[Ede92 ] )。
當第一次引用一個持久對象時,將它裝入內存。
在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved