概述:
模板方法本质是将既定不变的步骤,流程,方法,算法封装起来对外提供统一的接口,以复用这些流程或算法步骤;我们以登录界面为例,假设有两种用户普通用户client和管理员用户master,他们都需要登录login,即包含获取用户信息find_get_user,密码加密encrypt_pwd,匹配获得结果match这几步,只是具体的实现可能不同。我们将登录步骤抽象为统一的模板,封装为login方法,实现过程复用。
1. login_template抽象类定义,实现:
//定义
#ifndef _LOGIN_TEMPLATE_H
#define _LOGIN_TEMPLATE_H
#include<stdbool.h>
#include"login_model.h"
struct login_template_vmt;
struct login_template {
const struct login_template_vmt* vptr;
bool (*login)(struct login_template* pthis, struct login_model* plm);
struct login_model* (*find_login_user)(struct login_template* pthis, int id);
char* (*encrypt_pwd)(struct login_template* pthis, char* pwd);
bool (*match)(struct login_template* pthis, struct login_model* plm, struct login_model* pdb);
};
///< 将具体实现可能不同的方法放入虚表
struct login_template_vmt {
struct login_model* (*find_login_user_vm)(struct login_template* pthis, int id);
char* (*encrypt_pwd_vm)(struct login_template* pthis, char* pwd);
};
extern void login_template_init(struct login_template* pthis);
#endif // _LOGIN_TEMPLATE_H
//实现:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include"login_model.h"
#include"login_template.h"
///< 模板方法
static bool login(struct login_template* pthis, struct login_model* plm)
{
///< 第一步
struct login_model* dblm = pthis->find_login_user(pthis, plm->get_id(plm));
if (dblm != NULL) {
///< 第二步
char* crypwd = pthis->encrypt_pwd(pthis, plm->get_pwd(plm));
plm->set_pwd(plm, crypwd);
///< 第三步
return pthis->match(pthis, plm, dblm);
}
}
///< 不提供默认实现,必须由子类实现
static struct login_model* find_login_user(struct login_template* pthis, int id)
{
pthis->vptr->find_login_user_vm(pthis, id); ///< must realized by derived class
}
///< 提供默认实现,可由子类覆盖
static char* encrypt_pwd(struct login_template* pthis, char* pwd)
{
if (pthis->vptr->encrypt_pwd_vm != NULL) {
pthis->vptr->encrypt_pwd_vm(pthis, pwd);
} else {
printf("default plain text\n");
return pwd; ///< default realization
}
}
static bool match(struct login_template* pthis, struct login_model* plm, struct login_model* pdb)
{
if (plm->get_id(plm) == pdb->get_id(pdb)
&& !strcmp(plm->get_pwd(plm), pdb->get_pwd(pdb))) {
printf("login successfully!\n");
return true;
}
return false;
}
void login_template_init(struct login_template* pthis)
{
static const struct login_template_vmt vmt = {
.find_login_user_vm = NULL,
.encrypt_pwd_vm = NULL,
};
pthis->vptr = &vmt;
pthis->login = login;
pthis->find_login_user = find_login_user;
pthis->encrypt_pwd = encrypt_pwd;
pthis->match = match;
}
2. client_login子类定义,实现:
///< 定义
#ifndef _CLIENT_LOGIN_H
#define _CLIENT_LOGIN_H
#include<stdbool.h>
#include"login_model.h"
#include"login_template.h"
struct client_login {
struct login_template super;
bool (*login)(struct login_template* pthis, struct login_model* plm);
struct login_model* (*find_login_user)(struct login_template* pthis, int id);
char* (*encrypt_pwd)(struct login_template* pthis, char* pwd);
bool (*match)(struct login_template* pthis, struct login_model* plm, struct login_model* pdb);
};
extern struct client_login* construct_client_login(void);
extern void destruct_client_login(struct client_login* pthis);
#endif // _CLIENT_LOGIN_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"login_template.h"
#include"login_model.h"
#include"client_login.h"
static struct login_model* find_login_user_ov(struct login_template* pthis, int id)
{
///< 这里通过直接构造,来模拟查找
struct login_model* plm = construct_login_model();
plm->set_id(plm, id);
plm->set_pwd(plm, "xxdk");
return plm;
}
static void client_login_init(struct client_login* pthis)
{
static const struct login_template_vmt vmt = {
.find_login_user_vm = find_login_user_ov, ///< method override
};
login_template_init(&pthis->super);
pthis->super.vptr = &vmt;
pthis->login = pthis->super.login; ///< use base class method
pthis->match = pthis->super.match; ///< use base class method
pthis->encrypt_pwd = pthis->super.encrypt_pwd; ///< use base class method
}
struct client_login* construct_client_login(void)
{
struct client_login* pthis = malloc(sizeof(*pthis));
memset(pthis, 0, sizeof(*pthis));
client_login_init(pthis);
return pthis;
}
void destruct_client_login(struct client_login* pthis)
{
free(pthis);
}
3. master_login子类定义,实现:
///< 定义
#ifndef _MASTER_LOGIN_H
#define _MASTER_LOGIN_H
#include<stdbool.h>
#include"login_model.h"
#include"login_template.h"
struct master_login {
struct login_template super;
bool (*login)(struct login_template* pthis, struct login_model* plm);
struct login_model* (*find_login_user)(struct login_template* pthis, int id);
char* (*encrypt_pwd)(struct login_template* pthis, char* pwd);
bool (*match)(struct login_template* pthis, struct login_model* plm, struct login_model* pdb);
};
extern struct master_login* construct_master_login(void);
extern void destruct_master_login(struct master_login* pthis);
#endif // _MASTER_LOGIN_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"login_template.h"
#include"login_model.h"
#include"master_login.h"
static struct login_model* find_login_user_ov(struct login_template* pthis, int id)
{
struct login_model* plm = construct_login_model();
plm->set_id(plm, id);
plm->set_pwd(plm, "xxdk");
return plm;
}
static char* encrypt_pwd_ov(struct login_template* pthis, char* pwd)
{
printf("master encrypt pwd\n");
return pwd;
}
static void master_login_init(struct master_login* pthis)
{
static const struct login_template_vmt vmt = {
.find_login_user_vm = find_login_user_ov, ///< method override
.encrypt_pwd_vm = encrypt_pwd_ov, ///< method override
};
login_template_init(&pthis->super);
pthis->super.vptr = &vmt;
pthis->login = pthis->super.login; ///< use base class method
pthis->match = pthis->super.match; ///< use base class method
}
struct master_login* construct_master_login(void)
{
struct master_login* pthis = malloc(sizeof(*pthis));
memset(pthis, 0, sizeof(*pthis));
master_login_init(pthis);
return pthis;
}
void destruct_master_login(struct master_login* pthis)
{
free(pthis);
}
4. 辅助的login_model类定义,实现, 用于封装用户信息:
///< 定义
#ifndef _LOGIN_TEMPLATE_H
#define _LOGIN_TEMPLATE_H
#include<stdbool.h>
#include"login_model.h"
struct login_template_vmt;
struct login_template {
const struct login_template_vmt* vptr;
bool (*login)(struct login_template* pthis, struct login_model* plm);
struct login_model* (*find_login_user)(struct login_template* pthis, int id);
char* (*encrypt_pwd)(struct login_template* pthis, char* pwd);
bool (*match)(struct login_template* pthis, struct login_model* plm, struct login_model* pdb);
};
struct login_template_vmt {
struct login_model* (*find_login_user_vm)(struct login_template* pthis, int id);
char* (*encrypt_pwd_vm)(struct login_template* pthis, char* pwd);
};
extern struct login_template* construct_login_template(void);
extern void login_template_init(struct login_template* pthis);
extern void desturct_login_template(struct login_template* pthis);
#endif // _LOGIN_TEMPLATE_H
///< 实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"login_model.h"
static int get_id(struct login_model* pthis)
{
return pthis->id;
}
static void set_id(struct login_model* pthis, int id)
{
pthis->id = id;
}
static char* get_pwd(struct login_model* pthis)
{
return pthis->pwd;
}
static void set_pwd(struct login_model* pthis, char* pwd)
{
strncpy(pthis->pwd, pwd, 16);
}
static void login_model_init(struct login_model* pthis)
{
pthis->get_id = get_id;
pthis->set_id = set_id;
pthis->get_pwd = get_pwd;
pthis->set_pwd = set_pwd;
}
struct login_model* construct_login_model(void)
{
struct login_model* pthis = malloc(sizeof(*pthis));
login_model_init(pthis);
return pthis;
}
void destruct_login_model(struct login_model* pthis)
{
free(pthis);
}
5. 测试文件:
#include<stdio.h>
#include<stdbool.h>
#include"login_template.h"
#include"login_model.h"
#include"client_login.h"
#include"master_login.h"
int main()
{
struct login_model* usr;
struct login_template* plt;
usr = construct_login_model();
usr->set_id(usr, 1);
usr->set_pwd(usr, "xxdk");
printf("client user login: \n");
plt = (struct login_template*)construct_client_login();
plt->login(plt, usr);
destruct_client_login((struct client_login*)plt);
printf("master user login: \n");
plt = (struct login_template*)construct_master_login();
plt->login(plt, usr);
destruct_master_login((struct master_login*)plt);
destruct_login_model(usr);
return 0;
}