知乎專欄 | 多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者” |
我看到網上很多人做法都是這樣實現的
if input = '天氣' { ... } else if(input = '飲食'){ ... } else if(xxx){ .... } .... .... switch (input){ case '天氣': xxxx case '飲食': xxxx case xxxx xxxxx ... ... default: xxxx }
稍微高級的做法是,定義一個數組,或者一個hashmap,或者使用資料庫實現key,value定義。然後判斷keyword 是否存在,如果存在就處理 key 所對應的 value。
這樣的做法會導致後期,極難維護,可讀性極差,增加一個需求,就增加一段代碼,新的代碼會影響整個程序。國內開發者很喜歡使用if來拼接一個sql語句,這是坑爹的寫法。
下面談談我思路,我將採用傳統的MVC模式,
微信 ---post xml---> 入口URL | V +----------------+ | Router | 這裡是路由映射,用戶輸入keyword 映射到 controller 上, +----------------+ | V +----------------+ | Controller | Controller 會加載請求的class 做一系列處理,包括數據模型處理,視圖渲染, +----------------+ | V +--------------- Application -------------------+ | class xxx | class xxx | class xxx | class xxx | +-----------------------------------------------+ | V +--------------+ | Model | 處理數據 +--------------+ | V +--------------+ | View | 最後呈現xml。 微信會通過返回的xml將消息推送給用戶 +--------------+
任務處理圖,程序應該有一個入口,多個出口,而不是層層循環,層層判斷。一半來說for/if/while等等 超過三層,程序閲讀就會非常困難。
.---> 終結 / .--> 終結 / .--> 終結 / / / / 微信 ---> Post XML ---> 介面程序 ---------------------------------------------> - 終結 \ \ \ \ `---> 終結 \ \ `---> 終結 `---> 終結
實現菜單結構
<menu> <menuitem> <item>[1] 天氣 </item> <controller></controller> <menuitem> <menuitem> <item>[2] 新聞 </item> <controller></controller> <menuitem> <menuitem> <item>[3] 飲食 </item> <submenu> <menuitem> <item>[31] 肯德基 </item> <controller></controller> </menuitem> <menuitem> <item>[32] 麥當勞 </item> <controller></controller> </menuitem> </submenu> <menuitem> </menu>
XML 不太靈活,下面是資料庫方案
CREATE TABLE menu ( id serial NOT NULL, mid integer, -- mid 欄位 menuitem character varying NOT NULL, -- menuitem 欄位 controller character varying, -- 映射控製器 submenu_id integer, -- 子菜單ID status boolean DEFAULT true, -- 啟用,禁用狀態 ctime timestamp without time zone DEFAULT now(), -- 創建時間 mtime timestamp without time zone DEFAULT now(), -- 修改時間 CONSTRAINT id PRIMARY KEY (id), CONSTRAINT submenu_id FOREIGN KEY (submenu_id) REFERENCES menu (mid) MATCH SIMPLE ON UPDATE RESTRICT ON DELETE RESTRICT, CONSTRAINT mid UNIQUE (mid) ) WITH ( OIDS=FALSE ); ALTER TABLE menu OWNER TO dba; COMMENT ON TABLE menu IS 'menu table'; COMMENT ON COLUMN menu.mid IS 'mid 欄位'; COMMENT ON COLUMN menu.menuitem IS 'menuitem 欄位'; COMMENT ON COLUMN menu.controller IS '映射控製器'; COMMENT ON COLUMN menu.submenu_id IS '子菜單ID'; COMMENT ON COLUMN menu.status IS '啟用,禁用狀態'; COMMENT ON COLUMN menu.ctime IS '創建時間'; COMMENT ON COLUMN menu.mtime IS '修改時間';
數據
INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (1, '天氣', 'weather', NULL, true); INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (2, '新聞焦點', NULL, NULL, true); INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (21, '國內新聞', 'news/1', 2, true); INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (22, '國際新聞', 'news/2', 2, true);
這裡id欄位可有可無,實際上mid可以設置為主鍵,考慮到中國人習慣性才增加了id. submenu_id外鍵指向了mid 而沒有指向id. 因為id是serial會順序增加,會使整個菜單排序混亂。這樣有也缺點,就是菜單項不能超過十個。
接下來實現路由到控製器的分發。
關註:顯示菜單 [1] 天氣 [2] 新聞焦點 發送:1 取出weather, 實例化 weather 類 執行index() 方法。 返回天氣預報 $weather = new Weather() 發送:2 [21] 國內新聞 [22] 國際新聞 發送:21 實例化 news 類,構造方法參數指定為 1 返回國內新聞列表 $news = new News(1);
當 submenu_id 為 NULL 時表示他有子菜單,如果非 NULL 就取controller參數。
接下來要做的就是需求增加,只需要在menu表中增加一個記錄,然後開發對應的controller. 有一些不使用的項目隨時可以將status設置為禁用狀態