2016-10-13 35 views
0

下面是樹結構的一個愚蠢示例,其中每個節點都執行不同類型的操作,但只有一個節點(任何節點)必須在開始和結束時執行一些常見工作的項目。避免調用基類的受保護成員

public abstract class Employee 
{ 
    public void StartProject() 
    { 
     AnnounceProjectToNewspapers(); 
     DoActualWork(); 
     PutProductOnMarket(); 
    } 

    protected abstract void DoActualWork(); 

    private void AnnounceProjectToNewspapers() { } 
    private void PutProductOnMarket() { } 
} 

public class Engineer : Employee 
{ 
    protected override void DoActualWork() 
    { 
     // Build things. 
    } 
} 

public class Salesman : Employee 
{ 
    protected override void DoActualWork() 
    { 
     // Design leaflets. 
    } 
} 

public class Manager : Employee 
{ 
    protected override void DoActualWork() 
    { 
     // Make gantt charts. 

     // Also delegate. 
     foreach (var subordinate in subordinates) 
      // ...but then compiler stops you. 
      subordinate.DoActualWork(); 
    } 

    private List<Employee> subordinates; 
} 

問題是,您無法在基類上調用受保護的方法DoActualWork()

兩個解決方案,我看到的是:

  • DoActualWork()公衆。但是,這將允許任何人在沒有AnnounceProjectToNewspapers()PutProductOnmarket()的情況下致電。
  • 使DoActualWork()內部。但是這會阻止其他組件使用「管理系統」。

是否有一個標準的變通方法來避免這種限制?

+0

你是什麼意思*「你不能在基類」*上調用受保護的方法'DoActualWork()'。到目前爲止,您的設計是慣例,我不認爲它有問題。 –

+0

如果我理解正確,您需要將DoActualWork設置爲Manager類的專用設置,並且可以爲外部呼叫者提供相同的時間。這有點混亂,因爲它與繼承的抽象主義相矛盾。我認爲你需要將工作實現分離到一個單獨的類中,我們稱之爲Task,並根據需要將其成員設置爲public/private。 –

+0

@OndrejTucny受保護的成員只能從派生類訪問,方法是調用派生類的靜態類型或派生類的派生類的對象。因此,'Manager'不能調用'subordinate.DoActualWork()',因爲從屬不是'Manager'或者派生自它。 –

回答

1

我有幾種方法來實現你所需要的。

  1. 第一個也是顯而易見的方法是從Manager而不是員工繼承Engineer和Salesman。但是這使得繼承聽起來很荒謬。每個工程師是一個管理器(我希望這是真的。)

  2. 正如你所提到的,

讓DoActualWork()公共

這並不工作。爲了防止任何其他方法調用DoActualWork(),您可以使用reflection/stacktrace找到類的類型並阻止無效類型。請參閱here

但這兩種方法都對我感到嚴峻。應該有一種方法來設計類來獲得你所需要的。

+0

感謝您的鏈接!我寧願嘗試避免反思,但我會研究它。 –

+0

我帶着選擇號碼1去了我遇到的具體問題:刪除了經理類,並讓每個員工都能夠帶下屬。這個稍微破碎的抽象不應該太混亂。 –

0

我想出了這樣一個解決方案(這還沒有經過測試)

public interface IEmployee { 
    void StartProject(); 
    void DoWork(); 
} 

public abstract class EmployeeBase : IEmployee { 
    public void StartProject() { 
     AnnounceProjectToNewspapers(); 
     DoActualWork(); 
     PutProductOnMarket(); 
    } 

    void IEmployee.DoWork() { 
     // Maybe set a flag to see whether the work has been already done by calling StartProject(). 
     this.DoActualWork(); 
    } 

    protected abstract void DoActualWork(); 

    private void AnnounceProjectToNewspapers() { } 
    private void PutProductOnMarket() { } 
} 

public class Employee : EmployeeBase { 
    protected override void DoActualWork() { 
     // Log system Action 
    } 
} 

public class Engineer : Employee { 
    protected override void DoActualWork() { 
     // Build things. 
    } 
} 

public class Salesman : Employee { 
    protected override void DoActualWork() { 
     // Design leaflets. 
    } 
} 

public class Manager : Employee { 
    protected override void DoActualWork() { 
     DoWorkInternal(); 
    } 

    private void DoWorkInternal() { 
     foreach (var subordinate in subordinates) 
      subordinate.DoWork(); 
    } 

    private List<IEmployee> subordinates; 
} 
+0

如果我沒有錯,這相當於將DoActualWork()聲明爲public(並且有點過於複雜):每個客戶端將能夠調用DoWork()(因此DoActualWork())OP想要避免它 –

+0

實際上,DoActualWork()可公開訪問,即使沒有將其設置爲公開,因爲它可以被另一個公共方法(StartupProject)調用。他需要重新設計整個層次結構。 –

+0

@IslamYahiatene通過這個推理,存在的每一個私有方法都是公開訪問的,因爲它是通過調用一個類的公共方法而被執行的。在我的例子中,「DoActualWork」只能在合適的環境中從外部調用:在AnnounceProjectToNewspapers之後和PutProductOnMarket之前。 –

0

所有響應思考,一個妥協只是穿過我的腦海:通過內部方法使用一個間接調用。換句話說,一個窮人的朋友通過非正式的評論聲明。

下面是相關位:

public abstract class Employee 
{ 
    // Meant to be called by Manager class only. 
    internal void FollowTheLeader() 
    { 
     DoActualWork(); 
    } 
} 

public class Manager : Employee 
{ 
    protected override void DoActualWork() 
    { 
     // Make gantt charts. 

     // Also delegate. 
     foreach (var subordinate in subordinates) 
      // ...but then compiler stops you. 
      subordinate.FollowTheLeader(); 
    } 
} 

從其他組件派生類將能夠自定義工作員工和經理做的,但它們將不能夠讓任何人做的工作沒有適當的上下文。

程序集中的類將能夠做任何事情,但讓我們假設您可以信任開發框架的人員按照註釋中的說明操作。

+0

這種類型的(我稱之爲)「設計複雜性:正是我們需要採用單一職責原則和控制力學倒置的原因。否則,你無疑最終會寫出這些讓你想知道的代碼, 「首先隱藏代碼的原因是什麼?」 – code4life

+0

@ code4life感謝您的意見。請您詳細闡述或發佈您將如何重構代碼的示例?我確信我對於但我並不熟悉OOP –

+0

我剛剛注意到你的代碼 - 你試過編譯它嗎?實際上它不應該工作。另外,你引入了一個漂亮的悖論(這種悖論讓我想起一個ourobouros,lol),坐下來畫出你想要發生的執行路徑可能會更好,然後弄清楚這個問題,要知道你想要實現什麼邏輯實際上有點難,是應該在父級別的主要代碼,還是應該僅僅是「引導流量」的父級代碼?一旦你迴應了這個問題,我會發佈一個答案。 – code4life