我看到网上很多人做法都是这样实现的
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设置为禁用状态
原文出处:Netkiller 系列 手札
本文作者:陈景峯
转载请与作者联系,同时请务必标明文章原始出处和作者信息及本声明。
时间: 2024-10-15 17:56:44