none
關於動態產生類別實體不依靠Switch的問題 RRS feed

  • 問題

  • 各位大家好,本人剛接觸C#不到一年的時間,

    目前接觸到的程式碼都與網站有關係,使用的是aspx與ashx泛型處理函式來處理資料,

    而連資料庫的方式是使用ADO.NET,使用VS2012 .Net4.5函式庫。

    我目前有類似這樣的程式碼:

     var serializer = new JavaScriptSerializer();
     var filterArgs = serializer.Deserialize<FilterArgs>(context.Request.Params["FilterArgs"]);//從前端接到JSON文件
    foreach(Filter filter in filterArgs.FilterList){//分析...
        switch(filter.category){
            case "Money":
                CreateMoneySqlString(filter.data);
                //Do somthing about Money...
                break;
            case "People":
                CreatePeopleSqlString(filter.data);
                //Do somthing about People...
                break;
            case "Work":
                CreateWorkSqlString(filter.data);
                //Do somthing about Work...
                break;
        }
    }

    ADO.NET的程式碼就不再列了,大致上的感覺是這個樣子,

    根據一個"字串值"為依據來判斷要做甚麼事情...

    而我認為這樣的寫法在未來可能新增更多Filter的情況,維護上會很不方便,

    尤其是在每個Filter都有一大堆要做的事情...

    而最近在學習設計模式,我將程式碼改成這樣:

    var serializer = new JavaScriptSerializer(); var filterArgs = serializer.Deserialize<FilterArgs> var factory =new FilterFactory(); List<Filter> filters = factory.CreateFilters(filterArgs.FilterList);

    foreach(Filter filter in filters){ filter.CreateSqlString(); }

    //另外cs檔 public class FilterFactory{ public List<Filter> CreateFilters(List<Filter> filterlist){ var list = new List<Filter>(); foreach(Filter filter in ){ switch(filter.category){ case "Money": list.add(new MoneyFilter(filter.data)); break; case "People": list.add(new PeopleFilter(filter.data)); break; case "Work": list.add(new WorkFilter(filter.data)); break; } } } }


    而有一個共用的interface Filter

    並寫出各種繼承interface的實體,那些實體會做自己該做的事情,

    我在外層只需要呼叫方法就好!(甚至有回傳值可以使用)

    public interface Filter{ public void CreateSqlString();

    public DataObject Data{get;set;} } public class MoneyFilter : Filter{

    public DataObject Data{get;set;}

    MoneyFilter(){}

    MoneyFilter(DataObject data){this.Data=data;} public void CreateSqlString(){ //create money sql string } //anothor things about money } public class PeopleFilter : Filter{

    public DataObject Data{get;set;}

    PeopleFilter(){}

    PeopleFilter(DataObject data){this.Data=data;}

    public void CreateSqlString(){ //create People sql string } //anothor things about People } public class WorkFilter : Filter{

    public DataObject Data{get;set;}

    WorkFilter(){}

    WorkFilter(DataObject data){this.Data=data;}

    public void CreateSqlString(){ //create Work sql string } //anothor things about Work }

    我使用了一些概念:

    1.我將Filter會做的事情都包裝在Filter各自類別裡面

    2.使用抽象多型讓在外層的程式碼變乾淨

    3.未來要新增Filter只需要建立xxxFilter類別,並實作Filter介面即可

    我想問的是:

    1.我設計這樣的結構是否恰當呢?有符合設計模式嗎,或者有沒有更好讓程式碼更乾淨的的做法?

    1.1. 有沒有更好的概念可以加上去的(其他設計模式或OO概念等...)

    2.未來若要新增Filter我勢必要修改Factory類別(例如為新的filter新增一個case判斷式...)

    有甚麼方法可以動態讓程式碼,判斷要建立甚麼實體的方式嗎?

    目前有查到的是利用泛型 <T>以及where : Filter泛型條件式,

    但是那個T不能在執行期間給值吧...例如<Fitler.category> 在泛型裡給變數...

    關於泛型有甚麼建議的作法嗎~?

    以及我查到

    var type = Type.GetType("Some.Namespace.ClassName");
    var obj = Activator.CreateInstance(type);

    類似這樣的程式碼來達到利用category字串來判斷要建立哪個實體...

    3.會不會到頭來,我想錯方向了? 放錯重點等等...

    我整個程式目的是要判斷哪個Category來做那個Category要做的事情(例如資料庫CRUD)

    而實際上我的Filter大約有20幾個以上吧(上面只列出3個當範例)

    因次我才有想改良結構的想法...

    以上,非常感謝幫助我的每一個人!



    • 已編輯 Datzutzu 2018年11月28日 上午 02:42 修改一些程是碼細節
    2018年11月28日 上午 02:15

解答

  • 您可以考慮用Web API技術取代泛型處理常式, 再利用Web API提供的Model Binder功能建立不同類別的物件. 請參考:

    ASP.NET Web API 中繫結的參數

    • 已標示為解答 Datzutzu 2018年11月29日 上午 01:07
    2018年11月28日 上午 04:28
  • 改善 Simple Factory 分支的方式有好幾種,其中一種就是 "用資源搜尋取代分支"
    你可以把這些 Filter 塞進一個 Dictionary , Key 是字串, Value 是 Type (透過 Activator 建立執行個體)。

    這樣當 Filter 增加的時候, 只要在 Dictionary 加一筆資料就好。省去修改分支的問題。

    如果想要進一步學習, 可以參考 skilltree 歷史活動。

    如果你人在台北, 方便的話, 星期四可以來參與 twMVC 每周四聚會  可以和程式同好聊聊。


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 https://skilltree.my/

    • 已標示為解答 Datzutzu 2018年11月29日 上午 01:07
    2018年11月28日 上午 06:06
    版主

所有回覆

  • 您可以考慮用Web API技術取代泛型處理常式, 再利用Web API提供的Model Binder功能建立不同類別的物件. 請參考:

    ASP.NET Web API 中繫結的參數

    • 已標示為解答 Datzutzu 2018年11月29日 上午 01:07
    2018年11月28日 上午 04:28
  • 改善 Simple Factory 分支的方式有好幾種,其中一種就是 "用資源搜尋取代分支"
    你可以把這些 Filter 塞進一個 Dictionary , Key 是字串, Value 是 Type (透過 Activator 建立執行個體)。

    這樣當 Filter 增加的時候, 只要在 Dictionary 加一筆資料就好。省去修改分支的問題。

    如果想要進一步學習, 可以參考 skilltree 歷史活動。

    如果你人在台北, 方便的話, 星期四可以來參與 twMVC 每周四聚會  可以和程式同好聊聊。


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 https://skilltree.my/

    • 已標示為解答 Datzutzu 2018年11月29日 上午 01:07
    2018年11月28日 上午 06:06
    版主
  • 改善 Simple Factory 分支的方式有好幾種,其中一種就是 "用資源搜尋取代分支"
    你可以把這些 Filter 塞進一個 Dictionary , Key 是字串, Value 是 Type (透過 Activator 建立執行個體)。

    這樣當 Filter 增加的時候, 只要在 Dictionary 加一筆資料就好。省去修改分支的問題。

    使用Dictionary的想法真是太妙了! 非常謝謝您,這正是我需要的解決方式。

    沒想到有這樣子的聚會,若有時間非常想參加,感謝您的回答!


    2018年11月29日 上午 01:04
  • 您可以考慮用Web API技術取代泛型處理常式, 再利用Web API提供的Model Binder功能建立不同類別的物件.

    謝謝您給我新的方向,雖然目前環境因素只能用泛型處理函式開發,但Web API相關機制的確值得研究,

    非常感謝您的回答!

    2018年11月29日 上午 01:06