Android 組合模式(View與ViewGroup)

Android 23種設(shè)計模式

前言

組合設(shè)計模式摧玫,又被稱為部分整體模式。組合模式就是把一組比較相似的對象當做一樣的對象處理绑青。并根據(jù)樹狀結(jié)構(gòu)來組合對象席赂,然后提供可以一個統(tǒng)一方法去訪問這些對象吮铭,這樣就可以忽略對象和集合之間的差別。




我們可以看下這兩張樹狀圖颅停。公司架構(gòu)圖里邊谓晌,樹狀圖的各個節(jié)點node,還有各個葉子leaf實際上他們是由差別的。而組合模式就是把node當做一樣的對象處理癞揉。leaf也當做一樣的對象處理纸肉。而當我們要對node和leaf操作的時候,不需要考慮他是節(jié)點還是葉子喊熟,組合模式提供一致的方式來操作柏肪。這就是組合模式了。

組合模式定義

將部分整體的層次結(jié)構(gòu)轉(zhuǎn)換為樹狀結(jié)構(gòu)芥牌,是的客戶訪問對象和組合對象具有一致性烦味。

組合模式舉例

組合模式在寫法上分為透明組合模式和安全組合模式。我們先來透明組合模式

透明組合模式

1壁拉、先抽象出方法

public abstract class Component {
    String name;
    public Component(String name){
        this.name = name;
    }
    public abstract void print();
    public abstract void addChild(Component component);
    public abstract void removeChild(Component component);
    public abstract Component getChild(int index);
}

2谬俄、node節(jié)點
由于root根節(jié)點根node幾乎一樣,這里就直接定義node未單獨定義一個root節(jié)點

public class Node extends Component {
    private static final String TAG = Node.class.getSimpleName();
    private List<Component> list = new ArrayList<>();

    public Node(String name) {
        super(name);
    }

    @Override
    public void print() {
        Log.d(TAG,name);
        for (Component component:list) {
            component.print();
        }
    }

    @Override
    public void addChild(Component component) {
        list.add(component);
    }

    @Override
    public void removeChild(Component component) {
        list.remove(component);
    }

    @Override
    public Component getChild(int index) {
        return list.get(index);
    }
}

3弃理、葉子
枝干很簡單就是實現(xiàn)我們的增刪查和遍歷溃论。然后看葉子

public class Leaf extends Component {
    private static final String TAG = Leaf.class.getSimpleName();

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void print() {
        Log.d(TAG,name);
    }

    @Override
    public void addChild(Component component) {
        Log.d(TAG,"葉子節(jié)點,沒有子節(jié)點");
    }

    @Override
    public void removeChild(Component component) {
        Log.d(TAG,"葉子節(jié)點痘昌,沒有子節(jié)點");
    }

    @Override
    public Component getChild(int index) {
        Log.d(TAG,"葉子節(jié)點钥勋,沒有子節(jié)點");
        return null;
    }
}

4、調(diào)用
由于葉子節(jié)點沒有子節(jié)點了辆苔,所以增刪查詢就沒有作用了算灸。接下來調(diào)用

        Component root = new Node("XX公司");
        Component software = new Node("軟件部");
        Component hardware = new Node("硬件部");

        Component androidSoftware = new Leaf("android");
        Component iosSoftware = new Leaf("ios");
        Component layout = new Leaf("layout");

        root.addChild(software);
        root.addChild(hardware);
        software.addChild(androidSoftware);
        software.addChild(iosSoftware);
        hardware.addChild(layout);

        root.print();

5、打印
上也說了由于node和root極其相似驻啤,所以就復用了菲驴。看輸出

01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Node: XX公司
01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Node: 軟件部
01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Leaf: android
01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Leaf: ios
01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Node: 硬件部
01-24 11:17:52.649 30713-30713/com.yink.designpattern.designpattern D/Leaf: layout

到此街佑,我想你已經(jīng)理解什么是組合模式了跃赚。這時候有的讀者可能發(fā)現(xiàn)了径密,葉子節(jié)點很多方法沒必要存在,如果方法多的時候,代碼就十分繁瑣多于嚎京。這個時候另外一種組合模式的寫法就出來了顺少。

安全組合模式

1酌摇、抽象方法
安全組合模式和上面的透明組合模式最大差別呢就是把抽象方法簡化了鉴吹,只留了我們都需要的。

public abstract class SafeComponent {
    protected String name;
    public SafeComponent(String name) {
        this.name = name;
    }
    public abstract void print();
}

2、node
增刪查不再是統(tǒng)一接口

public class SafeNode extends SafeComponent {
    private static final String TAG = SafeNode.class.getSimpleName();
    private List<SafeComponent> list = new ArrayList<>();

    public SafeNode(String name) {
        super(name);
    }

    @Override
    public void print() {
        Log.d(TAG,name);
        for (SafeComponent safeComponent:list) {
            safeComponent.print();
        }
    }

    public void addChild(SafeComponent safeComponent) {
        list.add(safeComponent);
    }

    public void removeChild(SafeComponent safeComponent) {
        list.remove(safeComponent);
    }

    public SafeComponent getChild(int index) {
        return list.get(index);
    }
}

3闷供、leaf

public class SafeLeaf extends SafeComponent {
    private static final String TAG = SafeLeaf.class.getSimpleName();

    public SafeLeaf(String name) {
        super(name);
    }

    @Override
    public void print() {
        Log.d(TAG,name);
    }
}

4烟央、調(diào)用

        SafeComponent root = new SafeNode("XX公司");
        SafeComponent software = new SafeNode("軟件部");
        SafeComponent hardware = new SafeNode("硬件部");

        SafeComponent androidSoftware = new SafeLeaf("android");
        SafeComponent iosSoftware = new SafeLeaf("ios");
        SafeComponent layout = new SafeLeaf("layout");

        ((SafeNode) root).addChild(software);
        ((SafeNode) root).addChild(hardware);
        ((SafeNode) software).addChild(androidSoftware);
        ((SafeNode) software).addChild(iosSoftware);
        ((SafeNode) hardware).addChild(layout);

        root.print();

調(diào)用過后輸出和上面是一樣的,這里就不重復了歪脏。安全組合模式分工就很明確了疑俭。它還有一個好處就是當我們add/remove/getchild的時候,我們能知道具體的類是什么了婿失,而透明組合模式就得在運行時去判斷钞艇,比較麻煩。

View和ViewGroup

1豪硅、View和ViewGroup就是安全組合容器

組合模式Android中最經(jīng)典的用法無非就是View和ViewGroup的運用了哩照。我們都知道View還有Textview、Button他們都是繼承于View懒浮。他們就像葉子飘弧。而ViewGroup是容器,ViewGroup可以添加View砚著,而View不能添加ViewGroup次伶。這不就是安全組合模式里邊Leaf和Node的關(guān)系嗎。所以它就是安全組合模式的一種運用赖草。

2学少、ViewGroup容器實現(xiàn)方式

2.1剪个、接口添加操作子視圖方法

public abstract class ViewGroup extends View implements ViewParent, ViewManager {

首先ViewGroup繼承自View秧骑,所有ViewGroup擁有view的公開方法。具有view的特性扣囊。然后ViewGroup繼承了兩個接口乎折。我們先看ViewManager這個接口

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

一眼就明白了,跟我們之前的node一樣侵歇,添加了add/remove等對子視圖的操作方法骂澄。
在看ViewParent

public interface ViewParent {
    public void requestLayout();
    public void invalidateChild(View child, Rect r);
    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset);
    public void requestChildFocus(View child, View focused);
    ...
}

這里省略了ViewParent其它接口,我們會看到我們很多熟悉的方法惕虑,請求重新布局坟冲、獲取子視圖焦點等等。這里也是一些對子視圖的操作溃蔫。

2.2健提、繼承View復寫onalyout操作子元素

ViewGroup是一個抽象類,通篇ViewGroup的代碼伟叛,ViewGroup就一個為了把View的onlayout方法重置為抽象方法私痹。為啥View要這么做呢?我們知道View的onlatyou的方法是,View在父視圖中l(wèi)ayout布局過后調(diào)用onlayout方法紊遵,onlayout只是一個空實現(xiàn)账千,因為View已經(jīng)布局完成。onlayout沒有其他的實現(xiàn)意義暗膜。而ViewGroup作為一個視圖容器匀奏,ViewGroup調(diào)用layout布局完自己后。還需要布局子視圖学搜。所以它把onlayout重置為抽象方法攒射, 讓子類必須實現(xiàn)。

2.3恒水、其他方法

除了onlayout還有一些其他方法会放。我們再舉一個例子。
View中的dispatchDraw是一個空實現(xiàn)钉凌,而ViewGroup中就是為了遍歷然后drawChild咧最。等等還有其他方法都是為了操作子視圖 。這不就是組合模式么御雕。

 protected void dispatchDraw(Canvas canvas) {
    ...
    for (int i = 0; i < childrenCount; i++) {
            while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
                final View transientChild = mTransientViews.get(transientIndex);
                if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
                        transientChild.getAnimation() != null) {
                    more |= drawChild(canvas, transientChild, drawingTime);
                }
                transientIndex++;
                if (transientIndex >= transientCount) {
                    transientIndex = -1;
                }
            }

            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
            }
        }
      ....
}

總結(jié)

現(xiàn)在我想大家對什么是組合模式已經(jīng)有桿秤了矢沿。最后我想說下組合模式的優(yōu)缺點
優(yōu)點:
1、組合模式可以以層次結(jié)構(gòu)清楚的定義復雜對象酸纲。讓高層次忽略層次差異捣鲸。
2、高層次可以使用統(tǒng)一的方法而不用擔心它是枝干還是葉子闽坡。比如ViewGroup的dispatchView
3栽惶、組合模式可以形成復雜的樹形結(jié)構(gòu),但對樹形機構(gòu)的控制卻非常簡單疾嗅。
缺點:
1外厂、葉子類型不能控制。比如我想控制ViewGroup添加的View必須為TextView的時候代承,約束起來就很麻煩汁蝶。特別是類型多的時候。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末论悴,一起剝皮案震驚了整個濱河市掖棉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膀估,老刑警劉巖幔亥,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異玖像,居然都是意外死亡紫谷,警方通過查閱死者的電腦和手機齐饮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笤昨,“玉大人祖驱,你說我怎么就攤上這事÷髦希” “怎么了捺僻?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長崇裁。 經(jīng)常有香客問我匕坯,道長,這世上最難降的妖魔是什么拔稳? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任葛峻,我火速辦了婚禮,結(jié)果婚禮上巴比,老公的妹妹穿的比我還像新娘术奖。我一直安慰自己,他們只是感情好轻绞,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布采记。 她就那樣靜靜地躺著,像睡著了一般政勃。 火紅的嫁衣襯著肌膚如雪唧龄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天奸远,我揣著相機與錄音既棺,去河邊找鬼。 笑死然走,一個胖子當著我的面吹牛援制,可吹牛的內(nèi)容都是我干的戏挡。 我是一名探鬼主播芍瑞,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼褐墅!你這毒婦竟也來了拆檬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤妥凳,失蹤者是張志新(化名)和其女友劉穎竟贯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逝钥,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡屑那,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片持际。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡沃琅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜘欲,到底是詐尸還是另有隱情益眉,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布姥份,位于F島的核電站郭脂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏澈歉。R本人自食惡果不足惜展鸡,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望埃难。 院中可真熱鬧娱颊,春花似錦、人聲如沸凯砍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悟衩。三九已至剧罩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間座泳,已是汗流浹背惠昔。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挑势,地道東北人镇防。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像潮饱,于是被迫代替她去往敵國和親来氧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容