天天看點

給我一張名片——工廠方法模式廣告展現方案的抉擇安全模式類安全的工廠方法回憶

工廠方法模式(Factory Method):通過對産品類的抽象使其建立業務主要負責用于建立多類産品的執行個體。

廣告是一個公司主要的一個經濟來源,這不,很多企業等着要來公司首頁打廣告呢。

廣告展現

“小白, 咱們新來了一批廣告資源需要投放, 關于計算機教育訓練的。一批是 Java的, 用綠色字型。還有一批是PHP的,要用黃色字型,紅色背景。”

“沒問題, 于是小白準備建立兩個類, 然後通過執行個體對象方式來完成這個需求”。

//建立Java學科類
var Java = function(content){
    //将内容儲存在content裡面以備日後使用
    this.content = content;
    //建立對象時,通過閉包,直接執行,将内容按需求的樣式插入到頁面
    (function(content){
        var div = document.createElement('div');
        div.innerHTML = content;
        div.style.color = 'green';
        document.getElementById("container").appendChild(div);
    })(content);
}

//建立PHP學科類
var Php = function(){
    this.content = content;
    (function(content){
        var div = document.createElement('div');
        div.innerHTML = content;
        div.style.color = 'yellow';
        div.style.background = 'red';
        document.getElementById("container").appendChild(div);
    })(content);
}
           

剛寫完就聽到身後的喊聲:“小白,又來了一批廣告,關于 JavaScript的,要求背景色粉色……”

好吧,”突然間小白想起昨天學習的簡單工廠模式,心想,“正好派上用場了,就用簡單工廠模式去實作吧, 這樣日後再建立對象直接找工廠就好了 。”

//建立Java學科類
var Java = function(content){
    ..........
}

//建立PHP學科類
var Php = function(content){
    ..........
}

//建立JavaScript學科
var JavaScript = function(content){
    this.content = content;
    (function(content){
        var div = document.createElement('div');
        div.innerHTML = content;
        div.style.background = 'pink';
        document.getElementById("container").appendChild(div);
    })(content);
}

//學科類工廠
function JobFactory(type, content){
    switch(type){
        case 'java' :
            return new Java(content);
        case 'php' :
            return new Php(content);
        case 'JavaScript' :
            return new JavaScript(content);
    }
}
           

然後寫了一個測試案例:

JobFactory('JavaScript', 'JavaScript哪家強');
           

“小白, 又來了一批uI學科, 紅色邊框……”。

小白沉默了…

方案的抉擇

小銘見狀走了過來。“怎麼了,小白?”

“需求總在變,我不知道哪種解決方式更好,開始需求簡單,我就直接建立對象,後來需求多了,我就用簡單工廠方法重構,而現在又變了,我不僅僅要添加類,還要修改工廠函數。兩我更擔心的是未來的需求還會變……””

“這樣呀,”小銘微笑一下,”不用擔心,需求變是正常的,而我們還有更好的模式可以應用, 剛才你用簡單工廠模式遇到的問題就是每添加一個類就要修改兩處是吧, 是以說你可以試用一下工廠方法模式 。這樣以後每需要一個類,你隻需要添加這個類就行,其他的不用操心了 。”

“工廠方法?這是一個什麼樣的模式?”

“工廠方法模式本意是說将實際建立對象工作推遲到子類當中。這樣核心類就成了抽象類, 不過對于 JavaScript不必這麼深究, JavaScript沒有像傳統建立抽象類那樣的方式輕易建立抽象類, 是以在 JavaScript中實作工廠方法模式我們隻需要參考它的核心思想即可 。 是以我們可以将工廠方法看作是一個執行個體化對象的工廠類。安全起見,我們釆用安全模式類,而我們将建立對象的基類放在工廠方法類的原型中即可 。”

安全模式類

小白有些不懂,打斷小銘的話:“小銘,什麼叫安全模式類?你說的我不是很懂,你能詳細說明一下麼? ”

“安全模式類是說可以屏蔽使用這對類的錯誤使用造成的錯誤。 比如對于一個類 (我們暫且稱之為 Demo類)的建立,我們知道類的前面是需要有 new關鍵字的(如 var d= new Demo()),不過如果其他人不知道這個對象(Demo)是一個類, 那麼在使用時很可能忽略 new關鍵字直接執行類(如 var d = Demo();),此時我們得到的并不是我們預期的對象,如下所示

var Demo = function(){};
Demo.prototype = {
    show : function(){
        console.log('成功擷取!');
    }
}

var d = new Demo();
d.show();//成功擷取
var d = Demo();
d.show();//Uncaught TypeError: Cannot read property 'show' of undefined
           

“那麼你所說的安全模式就是為了解決這種問題吧 。”

“當然, 這也是避免像你一樣的那些新來同學可能犯的錯誤。 當然解決方案很簡單, 就是在構造函數開始時先判斷目前對象this指代是不是類(Demo),如果是則通過 new關鍵字建立對象, 如果不是說明類在全局作用域中執行 (通常情況下) , 那麼既然在全局作用域中執行當然this就會指向 window了(通常情況下,如非浏覽器環境可為其他全局對象),這樣我們就要重新傳回新建立的對象了 。”

var Demo = function(){
    if(!(this instanceof Demo)){
        return new Demo();
    }
}
Demo.prototype = {
    show : function(){
        console.log('成功擷取!');
    }
}

var d = Demo();
d.show();//成功擷取
           

“有了安全模式我們就可以将這種技術應用在我們的工廠方法中了 。”

安全的工廠方法

//安全模式建立的工廠類
var Factory = function(type, content){
    if(this instanceof Factory){
        var s = new this[type](content);
        return s;
    } else {
        return new Factory(type, content);
    }
}
//工廠原型中設定建立所有類型資料對象的基類
Factory.prototype = {
    Java : function(content){
        .....
    },
    JavaScript : function(content){
        .....
    },
    UI : function(content){
        this.content = content;
        (function(content){
            var div = document.createElement('div');
            div.innerHTML = content;
            div.style.border = '1px solid red';
            document.getElementById('container').appendChild(div);
        })
    },
    php : function(content){
        .....
    }
};
           

“這樣我們以後如果想添加其他類時,是不是隻需寫在 Factory 這個工廠類的原型裡面就可以了?”

“嗯,是這樣,你再也不必擔心建立時做任何修改。就好比你在 Factory 類的原型裡面注冊了一張名片, 以後需要哪類直接拿着這張名片, 査找上面的資訊就能找到這個類了, 是以你就不用擔心使用時找不到基類的問題了。”

“小白。這裡是我們今天要添加廣告的資料,給你,現在就給添加上吧。”經理走過來對小白說。

var data = [
    {type:'JavaScript', content:'JavaScript哪家強'},
    {type:'Java', content:'Java哪家強'},
    {type:'Php', content:'Php哪家強'},
    {type:'UI', content:'UI哪家強'},
    {type:'Java', content:'Java哪家強'},
];
           

小白接過資料一看, 格式很友好。 于是很快完成了經理提出的需求。

for(var i = ; i >=; i--){
    Factory(data[i].type, data[i].content);
}
           

“小白,廣告那邊又來了需求,需要一批C++學科,藍色字型……”

小白聽到,笑了笑。。。。

回憶

對于建立多類對象,前面學過的簡單工廠模式就不太适用了,這是簡單工廠模式的應用局限, 當然這正是工廠方法模式的價值之所在, 通過工廠方法模式我們可以輕松建立多個類的執行個體對象, 這樣工J一方法對象在建立對象的方式也避免了使用者與對象類之間的耦合, 使用者不必關心建立該對象的具體類, 隻需調用工廠方法即可。在實踐中, 理想與現實總有一線之隔的, 新來的同僚很可能錯誤地直接調用工廠方法, 這樣就很有可能通過工廠方法執行中的 this對象為全局對象添加全局變量,并且得不到期望的實樣就很有可能通過工廠方法執行中的 this對象為全局對象添加全局變量,并且得不到期望的執行個體對象, 此時一個安全的工廠對象則讓我們吃了一顆定心丸 。

繼續閱讀