[英]How to avoid type checking in C# to load correct UI?
我正在使用具有兩種模式的 WinForms 構建一個簡單的測驗程序:
1) 編輯模式:用戶可以在這里創建自己的問題
2)問答模式:用戶需要回答問題的地方
目前有兩種類型的問題:開放式(問題和自由文本框)和多項選擇(問題和 4 個可能的答案)。
我為一個問題創建了一個抽象類:
public abstract class Question
{
public string QuestionString { get; private set; }
public Question(string q)
{
QuestionString = q;
}
}
以及繼承此類的 2 個子類:
public class OpenQuestion : Question
{
public string CorrectAnswer { get; private set; }
public OpenQuestion(string q, string a) : base(q)
{
CorrectAnswer = a;
}
}
public class MultipleChoiceQuestion : Question
{
public string[] Answers { get; private set; }
public MultipleChoiceQuestion(string q, string[] ans) : base(q)
{
Answers = ans;
}
}
我將所有創建的問題保存在List<Question>
,並最終以 JSON 格式保存在文本文件中。
我的問題是加載問題,如何加載正確的 UI?
對於開放式問題,會有一個帶有問題和文本字段的標簽來寫答案,對於多項選擇題,會有問題標簽和 4 個單選按鈕。
目前這就是我所做的:
public void LoadNextQuestion()
{
Question q = GetCurrentQuestion(); // Just returning the current question to show
if(q is OpenQuestion) // And here is the problematic part.
{
ShowOpenQuestion(q as OpenQuestion); // Load UI for open question
}
else if(q is MultipleChoiceQuestion)
{
ShowMultipleChoiceQuestion(q as MultipleChoiceQuestion); // Load UI for Multiple choice question
}
}
有沒有辦法避免這種類型檢查? 因為在我看來它是錯誤的,如果我要添加另一種類型的問題,我將需要返回到此方法並為該類型添加另一個條件。
編輯對於 UI,我使用包含 UI 的面板,例如:
public void ShowOpenQuestion(OpenQuestion oq)
{
openQuestionPanel.Visible = true;
multipleChoicePanel.Visible = false; // Hide other question type panels, currently there is only one more
openQuestionLabel.Text = oq.QuestionString;
openQuestionInputField.Text = string.Empty;
}
提前致謝
類型檢查是你的朋友。 不要與類型檢查作斗爭。 甚至有一種運動來添加/使用更多它。 充其量你可以讓別人的代碼為你做類型檢查(比如函數調用解析)。
但是,在您給出的示例中,我沒有看到很多問題。 如果有的話,如果你自己繼續做這件事會很有好處,因為它會避免問題。 我什至想不出半打“問題類型”——所以這個列表不會像任何衡量標准一樣長。
您可以做的第一件事是用 switch/case 替換那些 if/else。 他們最近獲得了模式匹配能力。 事實上,基於類型的鑄造和處理是添加的第一件事。 示例代碼正好與您現在所做的有關。 如果使用 switch,則應該使用默認值來顯示一些錯誤消息甚至拋出異常。 這就是您避免未來問題的方法(忘記為新類提供正確的代碼。其他人通過不提供繪制功能而弄亂了繼承)。
當然,通常可以用 Collection 替換 switch/Case。 Dictionary<type, DelegateThatTakesAnyQuestionInstance>
。 您必須在 Delegate 中進行手動轉換(除非這里的協方差或逆方差幫助?),但您知道它匹配。 並且使用 Lambda 代替 Delegate 的命名函數,您甚至可以將整個代碼與您定義的其他大型集合一起隱藏。 同樣,沒有匹配項應該給你一個通知,除非是例外。
我寫這個的時候你沒有指定你的編程環境。 但值得指出的是,如果您使用 WPF/UWP 並遵循 MVVM,那么有一個很好的幫手:我稱它們為“類型目標數據模板”。 如果你在 View 中拋出一些隨機類並且沒有更高階的東西適用,它會嘗試找到一個匹配的模板來顯示它。 使用TargetType 屬性。
您可以稍微更新基礎Question
類並添加ShowQuestion
方法,該方法將由繼承者實現
public abstract class Question
{
public string QuestionString { get; private set; }
public Question(string q)
{
QuestionString = q;
}
public abstract void ShowQuestion();
}
但是此解決方案不允許您拆分問題的邏輯及其UI表示形式,您可能會考慮使用MVVM或MVP模式將UI和邏輯分開
一般而言,答案是通過以下方式應用信息隱藏和封裝的面向對象設計原則:
Question
類指定一個抽象方法,該方法為特定類型的問題呈現 UI 和OpenQuestion
和MultipleChoiceQuestion
。在更具體的層面上,關於這些方法應該如何呈現 UI 的“確切”答案取決於您使用的 UI 范例和框架。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.