2013-04-15 89 views
2

我有一個關於設計模式的問題。設計模式查詢

假設我想設計豬殺死工廠

這樣的方式將

1)抓豬

2)清潔豬

3)殺死豬

現在因爲這些豬是由卡車司機提供給我的

現在如果想設計一個應用程序,我應如何進行 我所做的是

public class killer{ 
private Pig pig ; 
public void catchPig(){ //do something }; 
public void cleanPig(){ }; 
public void killPig(){}; 
} 

現在IAM的事情,因爲我知道的步驟將在catchPig--->cleanPig---->KillPig的方式來調用,所以我應該有包含這些方法的抽象類和一個執行方法調用所有這3種方法。

但我不能有抽象類的實例,所以我很困惑如何實現這一點。 remenber我必須對所有進入卡車的豬執行此過程。

所以我的問題是我應該選擇哪種設計以及哪種設計模式最能解決這些問題。

+0

爲什麼反對票:( –

+1

我認爲這是一個素食主義者 – devdigital

+0

你只打算殺死豬或其他動物的歡迎呢? – Bart

回答

3

我會建議一個不同於前面提到的方法。

我會做這樣的事情:

public abstract class Killer { 
    protected Pig pig; 

    protected abstract void catchPig(); 

    protected abstract void cleanPig(); 

    protected abstract void killPig(); 

    public void executeKillPig { 
     catchPig(); 
     cleanPig(); 
     killPig(); 
    } 
} 

每擊殺將延長Killer類必須實現的抽象方法。 executeKillPig()對於每個子類都是相同的,並且將始終按照您希望catch-> clean-> kill的順序執行。抽象方法是受保護的,因爲它們是公衆的內部實現executeKillPig

+1

+1。比界面更好。在這裏,這些步驟將始終以正確的順序執行。一個接口不能保證這一點。 (P.S.這被稱爲模板模式)。此外,表達意圖很重要:每個子類都是一個「殺手」,與一個接口相連,我們允許任意類有殺手_behavior_。但從領域設計的角度來看,這是沒有意義的。我們想要在代碼中說/強調/加強每一個這樣做的對象都是'殺手',當然不是'素食者'。 – radarbob

+0

所有的拳頭你不能保證只有抽象類。你只能建議/建議,但是當你有抽象類時,每個公共/受保護的方法都可以改變。模板模式增加了東西耦合,所以它不是最好的選擇。恕我直言,應該避免。在模板中實現的路線可能會在某種程度上發生變化,那麼我們需要擔心所有實現它的類。更敏捷的方法是讓其他物體接受殺手對象並根據需要操縱他。 –

+1

@Vash,我同意「不能保證有...抽象類」。是的,如果你想要並重寫方法,你可以調用你的'Killer'子類'Vegetarian',但是我的論點不是關於編碼機制。我認爲你正在接受語義學的爭論:這個答案一般是關於「豬」而不是「動物」的。但是,如果'Killer'類處理'Animal's而不是'Pig's,那麼我仍然會使用帶有模板模式的抽象基類,而不是接口。 – radarbob

0

你正面臨參考OOP的一部分的問題稱爲polymorphism

而是抽象類的我將使用一個接口,接口之間的差異的抽象類是接口只有方法的描述,一個抽象類可以也有方法和實現。

public interface InterfaceOfPigKiller { 

    void catchPig(); 
    void cleanPig(); 
    void killPig(); 
} 

在抽象類中,我們實現兩個三個有效的方法,因爲我們認爲這些操作是每個未來的類型將繼承形成了我們班常見。

public abstract class AbstractPigKiller implements InterfaceOfPigKiller{ 

    private Ping pig; 

    public void catchPig() { 
    //the logic of catching pigs. 
    } 

    public void cleanPig() { 
    // the logic of pig cleaning. 
    } 

} 

現在我們將創建兩個新類:

  • AnimalKiller - 負責對豬死亡的人。

  • AnimalSaver - 負責釋放豬的人。


public class AnimalKiller extends AbstractPigKiller { 

public void killPig() { 
    // The killing operation 
} 

} 

public class AnimalSaver extends AbstractPigKiller { 

public void killPing() { 
    // The operation that will make pig free 
} 

} 

因爲我們有我們的結構,讓我們看看它是如何工作的。

將執行序列

首先方法:

public void doTheRequiredOperation(InterfaceOfPigKiller killer) { 

    killer.catchPig(); 
    killer.cleanPig(); 
    killer.killPig(); 
} 

正如我們在參數看,我們不使用類AnimalKillerAnimalSever。而不是我們有接口。感謝這個操作,我們可以在任何實現使用過的接口的類上進行操作。


實施例1:

public void test() { 

    AnimalKiller aKiller = new AnimalKiller();// We create new instance of class AnimalKiller and assign to variable aKiller with is type of `AnimalKilleraKiller ` 
    AnimalSaver aSaver = new AnimalSaver(); // 

    doTheRequiredOperation(aKiller); 
    doTheRequiredOperation(aSaver); 


} 

實施例2:

public void test() { 

    InterfaceOfPigKiller aKiller = new AnimalKiller();// We create new instance of class AnimalKiller and assign to variable aKiller with is type of `InterfaceOfPigKiller ` 
    InterfaceOfPigKiller aSaver = new AnimalSaver(); // 

    doTheRequiredOperation(aKiller); 
    doTheRequiredOperation(aSaver); 


} 

代碼實施例1和2也同樣在方法doTheRequiredOperation的範圍。區別在於,我們將類型分配給類型,而在第二個類型中,我們將類型分配給接口。

結論

我們不能創建抽象類或接口的新對象,但我們可以指定對象的接口或類類型。

+0

-1。這是濫用接口恕我直言的一個很好的例子;它在概念上混淆了多態和遺傳。這裏絕對不需要'abstract'類來實現一個接口。類本身可以聲明和定義所需的方法。從概念上來說,一個接口給予(有限/特定的)_behavior_給予任何對象這個能力,而另一個能力。 OTOH的子類「PigKiller」是一個天生的'殺手',並且_inherently_具有所有'殺手'的行爲。 – radarbob

+0

介紹的接口強烈地展示了使用抽象類和類的概念有時會變得複雜。想像抽象類就像接口,但我們可以有共同的實現方式更容易。由於提出的例子遠不是正確的。你的意見是錯誤的。除了上面的解釋之外,需要抽象類共享共同的行爲,比如'catchPig'和'cleanPig',我們向孩子展示瞭如何處理豬。介紹界面我們給變化有一些完全不同的殺戮。 –

+0

@radarbob,這將防止類似擴展抽象和覆蓋三種方法中的兩種。所以應該避免抽象類沒有推廣恕我直言。我不會在這裏使用抽象類,但這個問題需要它。 –

1

這擴展了Avi的答案並解決了評論。

代碼的點:

  1. abstract基類強調的是A關係
  2. 模板圖案,以確保步驟是按照正確的順序
  3. 策略模式 - 一個abstract類是儘可能多的一個界面(小「我」)多達Interface(大寫「I」)。
  4. 擴展底座而不使用接口。
  5. 沒有混凝土類的耦合。耦合不是abstract vs interface的問題,而是一個很好的設計。
 
    public abstract Animal { 
     public abstract bool Escape(){} 
     public abstract string SaySomething(){} 
    } 

    public Wabbit : Animal { 
     public override bool Escape() {//wabbit hopping frantically } 
     public override string SaySomething() { return @"What's Up Doc?"; } 
    } 


    public abstract class Killer { 
     protected Animal food; 
     protected abstract void Catch(){} 
     protected abstract void Kill(){} 
     protected abstract void Clean(){} 

     protected abstract string Lure(){} 

     // this method defines the process: the methods and the order of 
     // those calls. Exactly how to do each individual step is left up to sub classes. 
     // Even if you define a "PigKiller" interface we need this method 
     // ** in the base class ** to make sure all Killer's do it right. 
     // This method is the template (pattern) for subclasses. 
     protected void FeedTheFamily(Animal somethingTasty) { 
      food = somethingTasty; 
      Catch(); 
      Kill(); 
      Clean(); 
     } 

    } 
    public class WabbitHunter : Killer { 
     protected override Catch() { //wabbit catching technique } 
     protected override Kill() { //wabbit killing technique } 
     protected override Clean() { //wabbit cleaning technique } 
     protected override Lure() { return "Come here you wascuhwy wabbit!"; } 

    } 

    // client code ******************** 
    public class AHuntingWeWillGo { 
     Killer hunter; 
     Animal prey; 

     public AHuntingWeWillGo (Killer aHunter, Animal aAnimal) { 
      hunter = aHunter; 
      prey = aAnimal; 
     } 

     public void Hunt() { 
      if (!prey.Escape()) hunter.FeedTheFamily(prey) 
     } 
    } 


    public static void main() { 
     // look, ma! no coupling. Because we pass in our objects vice 
     // new them up inside the using classes 

     Killer ElmerFudd = new WabbitHunter(); 
     Animal BugsBunny = new Wabbit(); 
     AHuntingWeWillGo safari = new AHuntingWeWillGo(ElmerFudd, BugsBunny); 

     safari.Hunt(); 
    }