之前一直以为,把模块内聚封装起来叫”模板方法模式“,看来是我狭隘了。模板方法模式是将一组算法封装在一起,组成一个对外接口函数,而”门面模式“(我以前叫它”外观模式“)是将一个模块的函数封装出接口,组成一个模块对外开放接口组。
哦,是我读书不用功了。
整个模块打包成动态链接库,对外开放的接口只有 “增删查改” 四项功能函数名与参数列表,其余的场景类并不需要知道。 如果要拓展,也很简单,再来个操作类,依赖与数据库基类,被场景类依赖即可。
具体实现如下:
#ifndef DB_BASE_H
#define DB_BASE_H
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<sstream>
#include<sqlite3.h>
#include<string.h>
using namespace std;
//数据库单例
class DB_base
{
public:
static DB_base* instence(char* name);//获取数据库单例
/*对查询结果进行操作*/
int return_serch_num(char* sql);//返回查询记录数
int ireturn_serch(char* sql, int n);//获取查询结果(单一结果)
char* creturn_serch(char* sql, int n);//获取查询结果(单一结果)
int ireturn_multi_serch(char* sql, int r, int c);
char* creturn_multi_serch(char* sql, int r, int c);
void ret_any(char* sql,char* ret);
bool excute(char* sql);
private:
DB_base(char* name);
~DB_base();
static DB_base* My_DB;//实例
static sqlite3* db;//数据库文件句柄
};
#endif
#include"DB_base.h"
#include"Mutex.h"
class DB_command
{
private:
DB_base* My_DB;
Mutex* DB_Mutex;
public:
DB_command();
//增
int add_user(int id,int pwd,char* tel,char* err);
int add_file(char* file_name,int owner_id, int pwd, int mode,int dir_id,int force,char* err);//force,是否替换原文件
int add_list(int id,int pwd,int father_dir,char* dir_name,char* err);
//删
int del_user(int user_id,int pwd);
int del_file(int user_id,int pwd,int file_id,int dir_id,char* err);
int del_list(int user_id,int pwd,int dir_id,char* err);
//查
int login_check(int user_id,int pwd); //登录验证,不带目录id
int login(int user_id, int pwd,char* err); //带上id的登录验证
int pwd(int user_id,char* tel);
void file_list(int user_id,int pwd,int dir_id, char* ret,char* err);
int download(int user_id,int pwd,int file_id, int dir_id,int shared,char* err);
//改
int cpwd(int user_id, int old_pwd, int new_id,char* err);
int cfile_addr(int user_id,int pwd, int file_id, int old_dir, int new_dir,char* err);
int cdir_addr(int user_id,int pwd, int dir_id, int new_dir,char* err);
int share_file(int user_id, int pwd, int shared, int file_id, int dir_id,char* err);
int cfile_name(int user_id, int pwd, char* file_name, int file_id, int dir_id,char* err);
int cdir_name(int user_id, int pwd, char* dir_name, int dir_id,char* err);
};
场景类不需要知道函数怎么实现的,所以各位也不需要知道。 再来看看使用这个模块的一个场景:
简单抽取一部分,其中task_db是数据库事物对象
switch (m_packet.getHead()->funcId)
{
case 0x01://登陆
{
err = new char[40];
Login_t* plogin = (Login_t*)(pData);
tru = task_db->login(plogin->id, plogin->pwd,err);
m_packet.replyLogin(tru, tru,err, m_packet.getHead()->fd);
m_send->Write_date(m_packet.getData(), m_packet.getSize());
}break;
case 0x02://注册
{
Register_t* pregister = (Register_t*)(pData);
tru = task_db->add_user(pregister->id, pregister->pwd, pregister->tel,err);
m_packet.replyRegist(tru,err,m_packet.getHead()->fd);
m_send->Write_date(m_packet.getData(), m_packet.getSize());
}break;
case 0x03://找回密码
{
F_Pwd_t* Fpwd = (F_Pwd_t*)(pData);
tru = task_db->pwd(Fpwd->id, Fpwd->tel);
m_packet.replyFpwd(tru, tru, m_packet.getHead()->fd);
m_send->Write_date(m_packet.getData(), m_packet.getSize());
}break;
门面模式是个很好的模式,很符合面向接口编程,遵守了依赖倒置原则、迪米特法则等,当然,有些书说违背了开-闭原则,我个人认为,门面模式并不妨碍拓展,只要把基类抽取好,新功能只需要继承或依赖与基类即可。 至于说到既有功能失败而导致要修改原有功能,那跟设计模式没关系,哪个模式可以在不违背“开-闭原则”的情况下对错误功能进行修订啊?代理?适配器?还是啥?
门面模式的定义已经呼之欲出了:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
优点:高内聚,松耦合。安全,不通过门面上提供的方法,休想访问模块内部。
使用场景:还是那句:该用的时候,自然而然就用了,做一个项目的时候,应该有意识的将各个模块界定清楚,最好能达到每个都能独立封装成动态库,而后场景类调用动态库,这样一定封装的很不错了。