設計模式之-迭代器(Iterator)模式 + 建造者(Build)模式

迭代器(Iterator)模式

又叫做遊標(Cursor)模式。GOF給出的定義爲:提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。 從定義可見,迭代器模式是爲容器而生。很明顯,對容器對象的訪問必然涉及到遍歷算法。你可以一股腦的將遍歷方法塞到容器對象中去;或者根本不去提供什麼遍歷算法,讓使用容器的人自己去實現去吧。這兩種情況好像都能夠解決問題。

建造者(Build)模式

將一個複雜對象的構造與它的表示分離,使同樣的構建過程可以創建不同的表示,這樣的設計模式被稱爲建造者模式

滿足原則:

單一原則
開閉原則
迭代器模式和建造者模式是非常簡單的模式,下面直接上代碼。

建立一個實體對象

package Iterator.normal;

/**
 * 
 * @author Allen 
 * @date 2017年2月15日
 *
 */
public class UserVo {

    private final int u_id;// id
    private final String u_name;// 名稱
    private final int u_age;// 年齡

    private UserVo(int u_id, String u_name, int u_age) {
        super();
        this.u_id = u_id;
        this.u_name = u_name;
        this.u_age = u_age;
    }

    public int getU_id() {
        return u_id;
    }

    public String getU_name() {
        return u_name;
    }

    public int getU_age() {
        return u_age;
    }
    /**
     * 建造者模式
     * @author Allen 
     * @date 2017年2月15日
     *
     */
    public static class UserBuild {
        private int u_id;// id
        private String u_name;// 名稱
        private int u_age;// 年齡

        public UserBuild() {
            // TODO Auto-generated constructor stub
        }

        public UserBuild u_id(int u_id) {
            this.u_id = u_id;
            return this;
        }

        public UserBuild u_name(String u_name) {
            this.u_name = u_name;
            return this;
        }

        public UserBuild u_age(int u_age) {
            this.u_age = u_age;
            return this;
        }

        public UserVo build() {
            return new UserVo(u_id, u_name, u_age);
        }
    }

    public static UserBuild build() {
        return new UserBuild();
    }

}

傳統的List操作

package Iterator.normal;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 
 * @author Allen
 * @date 2017年2月15日
 *
 */
public class UserList {

    private List<UserVo> list = new ArrayList<UserVo>();

    /**
     * 添加用戶
     * 
     * @author Allen
     * @date 2017年2月15日
     */
    public void addUser() {
        String[] temp = { "大牛", "二牛", "三牛", "四牛", "五牛", "六牛", "七牛","八牛" };
        String str;
        for (int i = 0; i < temp.length && (str = temp[i]) != ""; i++)
            // 建造者模式增加對象屬性
            list.add(
                    UserVo.build()
                    .u_age(new Random().nextInt(11) + 25)
                    .u_id(i)
                    .u_name(str)
                    .build()
                    );
    }

    /**
     * 刪除用戶
     * 
     * @author Allen
     * @date 2017年2月15日
     */
    public void removeUser() {

    }

    /**
     * 獲取全部用戶信息
     * 
     * @author Allen
     * @date 2017年2月15日
     */
    public void getAllUser() {
        System.out.print("id\t");
        System.out.print("age\t");
        System.out.println("name\t");
        //傳統我們都是用for或foreach遍歷
        //當然也可以使用Arrays.asList(list).iterator()
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i).getU_id() + "\t");
            System.out.print(list.get(i).getU_age() + "\t");
            System.out.println(list.get(i).getU_name());
        }
    }
}

下面我們來看我們自建的Iterator模式

先定義一個接口模型

package Iterator.iterator;

/**
 * 建立一個名爲Iterator的接口
 * 
 * @see 接口定義了兩個抽象方法
 * @author Allen
 * @date 2017年2月15日
 *
 */
public interface Iterator {
    /**
     * 迭代器內是否有下一個對象
     * 
     * @return
     * @author Allen
     * @date 2017年2月15日
     */
    public boolean hasNext();

    /**
     * 獲取迭代器內下一個對象
     * 
     * @return
     * @author Allen
     * @date 2017年2月15日
     */
    public Object next();
}

再來具象化它

package Iterator.iterator;

import java.util.Arrays;

/**
 * 我的迭代器
 * 
 * @author Allen
 * @date 2017年2月15日
 *
 */
public class MyIterator<T> {

    private Object[] ob;
    private int last = 0;
    private int size = 10;

    /**
     * 初始化容器大小
     * 
     * @param maxSize
     */
    public MyIterator() {
        this.ob = new Object[this.size];
    }

    /**
     * 獲取容器指定索引內容
     * 
     * @param index
     * @return
     * @author Allen
     * @date 2017年2月15日
     */
    @SuppressWarnings("unchecked")
    private T getIndex(int index) {
        return (T) ob[index];
    }

    /**
     * 追加一個新的內容到容器
     * 
     * @param Star
     * @author Allen
     * @date 2017年2月15日
     */
    public void add(T Star) {
        if (last == this.ob.length)
            // 簡單的自增容器
            this.ob = Arrays.copyOf(this.ob, this.size+=20); 
        this.ob[last++] = Star;
    }

    /**
     * 獲取容器長度
     * 
     * @return
     * @author Allen
     * @date 2017年2月15日
     */
    public int toLength() {
        return this.size;
    }

    /**
     * 返回一個構造器對象
     * 
     * @see 在多數例子中都把iterator定義爲一個接口類,在MyIterator中進行實現其方法 new Iterator(this)
     *      並將下面的IteratorImpl定義爲接口來聲明並使用MyIterator ,與當前使用內部類並無差異,當前修改增加了對泛型的使用
     *      統配各種類型
     *      
     * @return
     * @author Allen
     * @date 2017年2月15日
     */
    public Iterator iterator() {
        return new IteratorImpl();
    }

    /**
     * 內部類來實現構造器基本功能
     * 
     * @author Allen
     * @date 2017年2月15日
     *
     */
    class IteratorImpl implements Iterator {
        /**
         * 迭代指針
         */
        private int p = 0;

        public boolean hasNext() {
            if (p < toLength() && (T) getIndex(p) != null) {
                return true;
            } else {
                return false;
            }
        }

        public Object next() {
            T star = (T) getIndex(p++);
            return star;
        }
    }

}

最後來運行它

package Iterator.iterator;

import java.util.Random;

import Iterator.normal.UserVo;

public class Main {
    static MyIterator<UserVo> myIt = new MyIterator<UserVo>();

    public static void main(String[] args) {
        iniData();
        Iterator it = myIt.iterator();
        while (it.hasNext()) {
            UserVo Star = (UserVo) it.next();
            System.out.println(Star.getU_name());
        }
    }

    private static void iniData() {
        String[] temp = { "大牛", "二牛", "三牛", "四牛", "五牛", "六牛", "七牛","八牛" };
        String str;
        for (int i = 0; i < temp.length && (str = temp[i]) != ""; i++){
            // 建造者模式增加對象屬性
        myIt.add(UserVo.build().u_age(new Random().nextInt(11) + 25).u_id(i).u_name(str).build()); 
        }
    }
}

Iterator
總的來說就是自己建立一個迭代器滿足我們項目所需,當然java內置容器中有都迭代器的實現,不過自建的更小巧

build
一種基於實體的不同依賴的實現

從上面Iterator的例子中在Vo對象中我們使用了簡單的build模式,我們可以使用內部類也可以定義爲實體類。最直觀來看我們避免了冗長的構造對象,使用鏈式定義。

下面我們可以擴展一下build模式,滿足了不同建造者的職責細節,比在Iterator例子中發揮了更大的作用

UserVo傳統get Set

package build.abs;

public class UserVo {

    private int u_id;// id
    private String u_name;// 名稱
    private int u_age;// 年齡

    public UserVo() {
        // TODO Auto-generated constructor stub
    }

    public int getU_id() {
        return u_id;
    }

    public String getU_name() {
        return u_name;
    }

    public int getU_age() {
        return u_age;
    }

    public void setU_id(int u_id) {
        this.u_id = u_id;
    }

    public void setU_name(String u_name) {
        this.u_name = u_name;
    }

    public void setU_age(int u_age) {
        this.u_age = u_age;
    }

}

建立一個構建者接口提供了我們要做的所有操作以及最終實體類獲取
這裏使用了java8在interface中的default新特性
當然如果老版本jdk可以使用abstract
如果覺得abstract使用extends讓其派生類沒有更多的擴展性
那麼可以定義爲interface 然後把create定義在外部

package build.abs;

interface IBuilder {
    UserVo user = new UserVo();

    public IBuilder buildName();

    public IBuilder buildId();

    public IBuilder buildAge();

    public default UserVo create() {
        return user;
    }

}

我們做兩個細節不同的建造者

package build.abs;

public class A_Builder implements IBuilder {

    public IBuilder buildName() {
        user.setU_name("~~~~~~I have an apple");
        return this;
    }

    public IBuilder buildId() {
        // ...
        return this;
    }

    public IBuilder buildAge() {
        // ...
        return this;
    }
}
package build.abs;

public class B_Builder implements IBuilder {

    public IBuilder buildName() {
        user.setU_name("~~~~~~i have a pen");
        return this;
    }

    public IBuilder buildId() {
        // ...
        return this;
    }

    public IBuilder buildAge() {
        // ...
        return this;

    }
}

封裝一個組裝細節

package build.abs;
public class BuildBind {
    public UserVo construct(IBuilder ab) { 
        return ab.buildAge()
                .buildId()
                .buildName()
                .create();
    }
}

最終實現

    public static void main(String[] args) {
        //爲了更方便觀察我們循環調用不同的build
        AbsBuilder[] ab = { new A_Builder(), new B_Builder() };
        BuildBind bc = new BuildBind();
        for (AbsBuilder temp : ab) {
            //buildBind進行組裝並返回不同build下的UserVo
            UserVo uvo = bc.construct(temp);
            System.out.println(uvo.getU_name());
        }
    }

結果

~~I have an apple
~~i have a pen

GOF提供的是一種思路,一種解決方案,在實際應用中我們應該根據自己的訴求來調整,而不是爲了設計模式而設計模式,不要曲解了那些官方例子

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章