2011-11-26 48 views
2

我一直在嘗試將正確的OOP原則應用於我的項目。我有一個名爲DocumentSection的抽象類,以及從它派生的幾個類(DocumentSectionView,DocumentSectionText等)。同樣,我有一個抽象類(DocAction),它有幾個派生自它的類(DocumentActionReplaceByTag,DocumentSectionAppend等)。每個DocumentSection都有一個DocumentAction。派生類中屬性的可見性(C#)

我對所有這些繼承業務的理解是,通過指定一個'DocumentAction',這將允許任何這些派生類放在它的位置,並且基類中的任何屬性/方法都可用,例如以及我在實例化的具體類中指定的任何東西。因此,在下面的例子中,我希望能夠看到PerformAction方法(現在將虛擬/覆蓋關鍵字留在混合中)。它是可用的。然而,因爲我去了v.DocAction = new DocumentActionReplaceByTag(),所以我還希望我的ReplaceActionFindText屬性可見。

很明顯,我錯了某處 - 任何意見讚賞。

class Program 
{ 
    static void Main(string[] args) 
    { 
     DocumentSectionView v = new DocumentSectionView(); 
     v.DocAction = new DocumentActionReplaceByTag(); 

     // would like to go: 
     //v.DocAction.ReplaceActionFindText... 

     Console.ReadLine(); 
    } 
}  
public abstract class DocumentSection 
{ 
    public abstract string GetContent(); 
    public DocumentAction DocAction { get; set; } 
} 
public class DocumentSectionView : DocumentSection 
{ 
    public string ViewPath { get; set; } 
    public dynamic ViewModel { get; set; } 

    public override string GetContent() 
    { 
     return "test"; 
    } 
}  
public abstract class DocumentAction 
{ 
    void PerformAction(StringBuilder sb, string content); 
} 
public class DocumentActionReplaceByTag : DocumentAction 
{ 
    public string ReplaceActionFindText { get; set; } 
    public void PerformAction(StringBuilder sb, string content) 
    { 
     sb.Replace(ReplaceActionFindText, content); 
    } 
} 

編輯: 我標誌着一個答案是正確的,但想到我會加上我進一步思考的成果,在這個問題上對那些跨稍後即將到來:

一)正如指出的,我的意圖是大致正確的,但我的方法是錯誤的。從Main方法設置Action的屬性是不正確的。在所有情況下,AA DocumentActionReplaceByTag需要FINDTEXT,所以我把它在構造函數中:

public DocumentActionReplaceByTag(string replaceActionFindText) 
    { 
     this.ReplaceActionFindText = replaceActionFindText; 
    } 

從此,0參數的構造函數會正確地失敗,並防止在執行該操作的情況下,但沒有FINDTEXT是指定。

b)多態現在工作正常,因爲我的額外屬性findtext已填充,並且運行PerformAction將正確運行,無論操作類型如何。

+0

謝謝大家。那麼,在DocumentSection中指定任何類型的DocAction都可以指定的'OOP正確'方式是什麼。我們的目標是從我的舊方法(在http://stackoverflow.com/questions/8242520/correct-oop-practice-for-class-properties-tied-by-logic討論)移動到使用多態調用action.GetContent ();在我的DocAction上運行任何適當的getcontent動作。但要做到這一點,我需要設置特定於該操作的屬性(如ReplaceActionText)。下面的演員被評論爲不理想 - 正在鑄造唯一的方法? – Glinkot

回答

2

因爲您將派生類分配給具有基類類型的屬性,所以只有基類的方法和屬性可用。這是有道理的,因爲你可能已經分配了任何從基類派生的類的實例 - 所以任何派生的方法都不能在此上下文中使用。

這是對OOP原則之一 - 你的派生類的實例可以作爲基類的一個實例(而不是其他方式輪)

編輯:

闡述一下解決方案由@sll建議轉換爲特定的派生類類型:不要這樣做!這是一種解決方法,但不符合整體設計的利益。

如果您必須轉換爲派生類型,那麼您違反了Liskov substitution principle這意味着任何派生類型都應該可用來代替基類型 - 如果您需要特定演員陣列,則顯然不是這種情況。

重新考慮你的設計 - 你真的需要與基類類型的屬性,如果是這樣的方法,目前只在一個特定的派生類型更好的基本類型是呢?

+0

謝謝Brokenglass。在我上面放鏈接(http://stackoverflow.com/questions/8242520/correct-oop-practice-for-class-properties-tied-by-logic)我試圖避免這並不涉及到其性質一個特定的目的。例如,一個動作可能需要路徑/文件名,而另一個動作可能需要「textcontent」屬性。將這兩種綁定到基類聽起來不像「正確的方式」?感謝 – Glinkot

0

不,在你的例子中,因爲DocAction只是一個DocumentAction,你將只能看到DocumentAction的屬性,無論使用哪種派生類型DocumentAction

2

v引用類型是DocumentSectionView,它不知道DocumentActionReplaceByTag類的方法,即使您已經爲其分配底層實例的DocumentActionReplaceByTag類。你需要投它能夠accesing派生類中的成員:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText 
在某些情況下,這是相當正常,當底層實例無法鑄造這樣的代碼部分資金應該被跳過,那麼你可以使用exception-

而且使用as operator鑄造的安全方式:

var typedAction = v.DocAction as DocumentActionReplaceByTag; 
if (typedAction != null) 
{ 
    // accessing the typedAction.ReplaceActionFindText property 
} 

我的建議是隻幫助你理解問題的C#的一面,關於整體設計和方法,請參閱BrokenGlass的答案。

+1

+1指出鑄造都會讓他做他想做 –

+1

這會損害這種設計的目的雖然 – BrokenGlass

+0

@BrokenGlass什麼:對不起,我沒有得到一點關於目前的設計,你可以澄清嗎?這種設計的正確選擇是什麼?我剛纔看到的方法是代碼'主()'不分配派生類實例時基參考 – sll