Jianwoo中的設(shè)計模式(4) — 工廠方法模式

前言

六大設(shè)計原則中有一條叫“開閉原則”,意思就是修改對外關(guān)閉,擴(kuò)展對外開放胖烛,是啥意思呢?就是我寫的產(chǎn)品功能诅迷,我不希望在擴(kuò)展功能還要修改內(nèi)部邏輯佩番,而是可以通過擴(kuò)展外部來實現(xiàn)功能的擴(kuò)展,這么說可能并不是很好理解罢杉,舉個例子吧趟畏,你實現(xiàn)了一個圖片濾鏡功能,這個濾鏡可以把圖片處理成黑白滩租,你把圖片處理的算法寫在了功能內(nèi)部拱镐,然后有一天,你又寫了另一個濾鏡可以把圖片處理成素描樣式持际,于是你想把這個濾鏡算法加進(jìn)去沃琅,那怎么區(qū)分是哪個濾鏡呢,因為你算法都寫在功能類內(nèi)部蜘欲,所以你只能通過if else or switch case來處理不同的濾鏡益眉,開始你感覺很好,我可以切換兩種濾鏡姥份,慢慢的你發(fā)現(xiàn)郭脂,你寫了幾十個濾鏡,你要維護(hù)一個有幾十個if else的代碼澈歉,很顯然這不是一個好的方案展鸡,而這個時候,合理的使用設(shè)計模式去設(shè)計你的代碼結(jié)構(gòu)就顯得非常重要埃难,那應(yīng)該怎么辦呢莹弊,你可以使用策略模式或者工廠模式來提供不同的算法涤久,這篇文章就介紹一下工廠方法模式如何在不修改內(nèi)部的情況下對功能進(jìn)行擴(kuò)展,當(dāng)然這也是簡物中的項目實踐

簡物中的工廠方法模式

工廠模式分好幾類忍弛,基礎(chǔ)的有簡單工廠模式/靜態(tài)工廠模式响迂,接著就是工廠方法模式,再應(yīng)用更復(fù)雜的場景還有抽象工廠模式细疚,不同的模式對于不同的應(yīng)用場景是不一樣的蔗彤,那這里就暫時不對各種工廠模式進(jìn)行介紹,重點聊聊簡物中的工廠方法模式

簡物中的應(yīng)用場景

在前面我寫了一篇簡物中高仿Pinterest交互的實現(xiàn)思路的文章疯兼,在高仿Pinterest交互中然遏,展開的圖標(biāo)大小是有共同屬性的,圖標(biāo)都是具有icon吧彪、標(biāo)題啦鸣、like圖標(biāo)還有收藏和未收藏的值,后面甚至有考慮給圖標(biāo)加選中動畫来氧,而這一切我不希望把它捆綁在Pinterest交互內(nèi)部去做诫给,因為我要考慮以后更好的去擴(kuò)展,所以我決定用工廠方法模式啦扬,因為這里就單一一個產(chǎn)品功能中狂,不需要用到抽象工廠模式
那我們來看一下,菜單圖標(biāo)需要哪些屬性呢扑毡?

高仿Pinterest交互

從圖上可以看到一些基本屬性選中前圖標(biāo)胃榕、選中后圖標(biāo)、圖標(biāo)文字瞄摊、還有圖標(biāo)的擺放順序勋又,當(dāng)然還有動畫,不過現(xiàn)在動畫都是統(tǒng)一换帜,內(nèi)部調(diào)用暫未使用楔壤,那我們按照這些屬性來給它設(shè)計一個接口模型

public interface IPinterestView {

    int ITEM_SHOPPING_CART = 0x00010;
    int ITEM_LIKE = 0x00020;

    int LIKE = 1;
    int CART = 2;

    /**
     * 菜單id
     * @return
     */
    int getItemId();

    /**
     * 菜單坐標(biāo)
     * @return
     */
    int getImageIndex();

    /**
     * 正常圖標(biāo)資源
     * @return
     */
    int getImageResNormal();

    /**
     * 按下后圖標(biāo)資源
     * @return
     */
    int getImageResPress();

    /**
     * 菜單標(biāo)題
     * @return
     */
    String getImageTitle();

    /**
     * 圖標(biāo)動畫
     * @return
     */
    Animation getAnimation();

}

這個接口模型帶有這些菜單的基本屬性,當(dāng)然也可以提供一些行為方法惯驼,供實現(xiàn)類去實現(xiàn)蹲嚣。我們現(xiàn)在有兩個菜單,一個Like一個Cart祟牲,我們讓這兩個具體菜單實現(xiàn)這個產(chǎn)品模型接口隙畜,然后返回具體菜單參數(shù),不過這里我先寫一個菜單父類實現(xiàn)這個接口模型说贝,把一些暫時不用待實現(xiàn)方法的或者需要封裝的方法寫上去议惰,以減少子類復(fù)寫的內(nèi)容

public class PinterestView implements IPinterestView {

    /**
     * 主要用于Like菜單返回圖標(biāo)
     */
    boolean like;

    @Override
    public int getItemId() {
        return 0;
    }

    @Override
    public int getImageIndex() {
        return 0;
    }

    @Override
    public int getImageResNormal() {
        return 0;
    }

    @Override
    public int getImageResPress() {
        return 0;
    }

    @Override
    public String getImageTitle() {
        return null;
    }

    public boolean isLike() {
        return like;
    }

    @Override
    public Animation getAnimation() {
        return null;
    }

    public PinterestView withLike(boolean like) {
        this.like = like;
        return this;
    }

}

那我們可以來寫Like菜單了

public class LikePinterestView extends PinterestView {

    @Override
    public int getItemId() {
        return ITEM_LIKE;
    }

    @Override
    public int getImageIndex() {
        return IPinterestView.LIKE;
    }

    @Override
    public int getImageResNormal() {
        return isLike() ? R.mipmap.ic_unlike : R.mipmap.ic_like;
    }

    @Override
    public int getImageResPress() {
        return isLike() ? R.mipmap.ic_unlike_press : R.mipmap.ic_like_press;
    }

    @Override
    public String getImageTitle() {
        return isLike() ? "Unlike" : "Like";
    }
}

Like菜單好了,那我們應(yīng)該要有一個能生產(chǎn)這類菜單模型的工具乡恕,而可能生產(chǎn)這類模型的工具中不一定能完全用同一個工具言询,比如我們已經(jīng)設(shè)計好了一個主板模型俯萎,已經(jīng)可以按照這類主板模型生產(chǎn)的不同的主板,可是造主板的材料不一定是木質(zhì)倍试,可能是別的材料讯屈,那我們怎么辦呢蛋哭,我們可以設(shè)計一個造主板的抽象工具县习,讓造不同的主板用不同的工具材料就好了

public interface PinterestViewFactory {

    IPinterestView create();

}

那我們現(xiàn)在要生產(chǎn)Like菜單,可以寫一個具體的生產(chǎn)類,而Like菜單是需要傳參數(shù)的谆趾,所以我們可以在工廠里面設(shè)置這些參數(shù)

public class LikePinterestViewFactory implements PinterestViewFactory {

    private boolean mIsLike;

    @Override
    public IPinterestView create() {
        return new LikePinterestView().withLike(mIsLike);
    }

    public LikePinterestViewFactory withLike(boolean like){
        this.mIsLike = like;
        return this;
    }

}

那我們Pinterest交互功能怎么用呢躁愿,我們只需要傳入一個IPinterestView接口模型,然后內(nèi)部功能調(diào)用接口方法就好了沪蓬,不用操心具體實現(xiàn)類彤钟,你要改這個方法的參數(shù),你在外面改跷叉,不要動我里面逸雹,你只要按照這個接口模型給我提供參數(shù)和具體方法執(zhí)行就行,我給你修改擴(kuò)展的權(quán)利云挟,這就是“開閉原則”

        new PinterestSelector.Builder()
                ...
                .addITouchView(new LikePinterestViewFactory().withLike(getAdapter().getItem(position).isLike()).create())
                ...
                .create()
                .onTouch(v, event);

內(nèi)部接收到了IPinterestView之后梆砸,接收參數(shù),或者在功能運行過程中調(diào)用接口方法

    IPinterestView mITouchView;

    public void initParams(){
        setVisibility(View.GONE);
        mBaseDegree = 0;
        mItemId = mITouchView.getItemId()
        mNormalResId = mITouchView.getImageResNormal();
        mPressResId = mITouchView.getImageResPress();
        mTitle = mITouchView.getImageTitle();
        mIndex = mITouchView.getImageIndex();
        setImageResource(getNormalResId());
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getIconWidth(),getIconHeight());
        /**
         * 高
         */
        mHeight = Math.abs((int)(Math.sin(getAngle(getAngle())) * getR()));
        /**
         * 寬
         */
        mWidth = Math.abs((int)(Math.cos(getAngle(getAngle())) * getR()));

        mIndexX = getTouchX() - mWidth - getIconWidth() / 2;
        mIndexY = getTouchY() - mHeight - getIconHeight() / 2 - getStatusBarHeight();
        params.setMargins(getIndexX(), getIndexY(), 0, 0);
        setLayoutParams(params);
    }

看到?jīng)]园欣,內(nèi)部功能的運行并沒有直接和菜單的具體參數(shù)和運行方法掛鉤帖世,外部只要按照這個接口模型生產(chǎn)對應(yīng)的菜單就好了,這就是多態(tài)的妙處

過了不久沸枯,我上線了一個購物車功能日矫,我需要彈出的菜單有購物車,那怎么辦绑榴?繼續(xù)在外部生產(chǎn)唄哪轿,內(nèi)部不做任何變動,Cart菜單來了

public class CartPinterestView extends PinterestView {

    public CartPinterestView(){
        super();
    }

    @Override
    public int getItemId() {
        return ITEM_SHOPPING_CART;
    }

    @Override
    public int getImageIndex() {
        return IPinterestView.CART;
    }

    @Override
    public int getImageResNormal() {
        return R.mipmap.ic_shopping_cart;
    }

    @Override
    public int getImageResPress() {
        return R.mipmap.ic_shopping_cart_press;
    }

    @Override
    public String getImageTitle() {
        return "Cart";
    }

}

生產(chǎn)Cart

public class CartPinterestViewFactory implements PinterestViewFactory {

    @Override
    public IPinterestView create() {
        return new CartPinterestView();
    }

}

投入運轉(zhuǎn)

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(!v.isClickable()){
            return false;
        }
        new PinterestSelector.Builder()
                .show((View)v.getParent())
                .scroll(getBindId())
                .backgroundColor("#f0ffffff")
                .dialogMode()

                /**
                 * 我在這里
                 */
                .addITouchView(new CartPinterestViewFactory().create())
                .addITouchView(new LikePinterestViewFactory().withLike(getAdapter().getItem(position).isLike()).create())

                .setOnLongClickListener(new PinterestSelector.OnLongClickListener() {
                    @Override
                    public void onLongClick(View v) {
                        handleLongClick();
                    }
                })
                .setOnCancelListener(new PinterestSelector.OnCancelListener() {
                    @Override
                    public void onCancel() {
                    }

                    @Override
                    public void onSyncCancel() {
                        handleSyncCancel();
                    }
                })
                .setOnItemSelectListener(new PinterestSelector.OnItemSelectListener() {
                    @Override
                    public void onItemSelect(int index) {
                        switch (index){
                            case IPinterestView.LIKE:
                                handleCollectSelect();
                                break;
                            case IPinterestView.CART:
                                handleSlideToCart();
                                break;
                        }
                    }
                })
                .create()
                .onTouch(v, event);

        return super.onTouch(v, event);
    }

好了翔怎,殺青

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末智什,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子节槐,更是在濱河造成了極大的恐慌配乱,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件于毙,死亡現(xiàn)場離奇詭異敦冬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)唯沮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門脖旱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堪遂,“玉大人,你說我怎么就攤上這事萌庆∪芡剩” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵践险,是天一觀的道長猿妈。 經(jīng)常有香客問我,道長巍虫,這世上最難降的妖魔是什么彭则? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮占遥,結(jié)果婚禮上俯抖,老公的妹妹穿的比我還像新娘。我一直安慰自己瓦胎,他們只是感情好芬萍,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搔啊,像睡著了一般柬祠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坯癣,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天瓶盛,我揣著相機(jī)與錄音,去河邊找鬼示罗。 笑死惩猫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚜点。 我是一名探鬼主播轧房,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绍绘!你這毒婦竟也來了奶镶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤陪拘,失蹤者是張志新(化名)和其女友劉穎厂镇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體左刽,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡捺信,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了欠痴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迄靠。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡秒咨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掌挚,到底是詐尸還是另有隱情雨席,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布吠式,位于F島的核電站陡厘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奇徒。R本人自食惡果不足惜雏亚,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一缨硝、第九天 我趴在偏房一處隱蔽的房頂上張望摩钙。 院中可真熱鬧,春花似錦查辩、人聲如沸胖笛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽长踊。三九已至,卻和暖如春萍倡,著一層夾襖步出監(jiān)牢的瞬間身弊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工列敲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留阱佛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓戴而,卻偏偏與公主長得像凑术,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子所意,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

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