设计模式-适配器模式(Apater)
【描述】适配器模式将某个对象的接口适配为另一个对象所期望的接口。
【uml图】
图1 apater模式
(1) 已知apatee类,该类提供了画线的函数实现;
(2) 现在用户要求绘制点,我们知道如果将画线函数起点和终点坐标取一致,实际上就相当于绘制了点。于是决定采用适配器模式将画线函数适配为画点函数。
【代码清单】
apatee.h
[html]
#ifndef apatee_h
#define apatee_h
class apatee
{
public:
apatee();
public:
void draw(int x0, int y0, int x1, int y1);
};
#endif // apatee_h
#ifndef apatee_h
#define apatee_h
class apatee
{
public:
apatee();
public:
void draw(int x0, int y0, int x1, int y1);
};
#endif // apatee_h
apatee.cpp
[html]
#include <qdebug>
#include "apatee.h"
apatee::apatee()
{
qdebug()<<"construct apatee";
}
void apatee::draw(int x0, int y0, int x1, int y1)
{
qdebug()<<qstring("apatee::draw(int %1, int %2, int %3, int %4)").arg(x0).arg(y0).arg(x1).arg(y1);
}
#include <qdebug>
#include "apatee.h"
apatee::apatee()
{
qdebug()<<"construct apatee";
}
void apatee::draw(int x0, int y0, int x1, int y1)
{
qdebug()<<qstring("apatee::draw(int %1, int %2, int %3, int %4)").arg(x0).arg(y0).arg(x1).arg(y1);
}
apater.h
[html]
#ifndef apater_h
#define apater_h
#include "apatee.h"
class apater : public apatee
{
public:
apater(apatee adaptee);
private:
apatee apatee;
public:
void draw_dot(int x, int y);
};
#endif // apater_h
#ifndef apater_h
#define apater_h
#include "apatee.h"
class apater : public apatee
{
public:
apater(apatee adaptee);
private:
apatee apatee;
public:
void draw_dot(int x, int y);
};
#endif // apater_h
apater.cpp
[html]
#include <qdebug>
#include "apater.h"
apater::apater(apatee adaptee)
{
qdebug()<<"construct apater";
this->apatee = apatee;
}
void apater::draw_dot(int x, int y)
{
qdebug()<<(qstring("apater::draw_dot(int %1, int %2)").arg(x).arg(y));
apatee.draw(x, y, x, y);
}
#include <qdebug>
#include "apater.h"
apater::apater(apatee adaptee)
{
qdebug()<<"construct apater";
this->apatee = apatee;
}
void apater::draw_dot(int x, int y)
{
qdebug()<<(qstring("apater::draw_dot(int %1, int %2)").arg(x).arg(y));
apatee.draw(x, y, x, y);
}
【运行结果】
[html]
construct apatee
construct apatee
construct apatee
construct apater
"apater::draw_dot(int 1, int 2)"
"apatee::draw(int 1, int 2, int 1, int 2)"
construct apatee
construct apatee
construct apatee
construct apater
"apater::draw_dot(int 1, int 2)"
"apatee::draw(int 1, int 2, int 1, int 2)"
【分析】
适配器模式实际上,也可采用继承实现。继承apatee类后,apater类中直接调用父类方法。即将
[html]
apatee.draw(x, y, x, y);
apatee.draw(x, y, x, y);替换为
[html] view plaincopyprint?draw(x, y, x, y);
draw(x, y, x, y);
【实例剖析】
md5算法的qt实现一文代码中,update()函数实际上就是应用了适配器模式的思想。
我们要实现的update接口包括:
[html]
private:
void update(const byte* input, size_t length);
public:
void update(const void* input, size_t length);
void update(const qstring& str);
void update(ifstream& in);
private:
void update(const byte* input, size_t length);
public:
void update(const void* input, size_t length);
void update(const qstring& str);
void update(ifstream& in);
但实际上,我们只需实现一个接口(这个接口是私有的):
[html]
void update(const byte* input, size_t length);
void update(const byte* input, size_t length);
实现代码
[html]
void md5::update(const byte *input, size_t length)
{
uint32 i, index, partlen;
_finished = false;
/* compute number of bytes mod 64 */
index = (uint32)((_count[0] >> 3) & 0x3f);//0x3f = 63
/* update number of bits */
if ((_count[0] += ((uint32)length << 3)) < ((uint32)length << 3))
{
++_count[1];
}
_count[1] += ((uint32)length >> 29);
//qdebug()<<_count[0]<<_count[1];
partlen = 64 - index;
/* transform as many times as possible. */
if (length >= partlen)
{
memcpy(&_buffer[index], input, partlen);
transform(_buffer);
for (i = partlen; i + 63 < length; i += 64)
{
transform(&input[i]);
}
index = 0;
}
else
{
i = 0;
}
/* buffer remaining input */
memcpy(&_buffer[index], &input[i], length - i);
}
/*
md5 finalization. ends an md5 message-_digest operation, writing the
the message _digest and zeroizing the context.
*/
void md5::final()
{
byte bits[8];
uint32 oldstate[4];
uint32 oldcount[2];
uint32 index, padlen;
/* save current state and count. */
memcpy(oldstate, _state, 16);
memcpy(oldcount, _count, 8);
/* save number of bits */
encode(_count, bits, 8);
/* pad out to 56 mod 64. */
index = (uint32)((_count[0] >> 3) & 0x3f);
padlen = (index < 56) ? (56 - index) : (120 - index);
update(padding, padlen);
/* append length (before padding) */
update(bits, 8);
/* store state in digest */
encode(_state, _digest, 16);
/* restore current state and count. */
memcpy(_state, oldstate, 16);
memcpy(_count, oldcount, 8);
}
void md5::update(const byte *input, size_t length)
{
uint32 i, index, partlen;
_finished = false;
/* compute number of bytes mod 64 */
index = (uint32)((_count[0] >> 3) & 0x3f);//0x3f = 63
/* update number of bits */
if ((_count[0] += ((uint32)length << 3)) < ((uint32)length << 3))
{
++_count[1];
}
_count[1] += ((uint32)length >> 29);
//qdebug()<<_count[0]<<_count[1];
partlen = 64 - index;
/* transform as many times as possible. */
if (length >= partlen)
{
memcpy(&_buffer[index], input, partlen);
transform(_buffer);
for (i = partlen; i + 63 < length; i += 64)
{
transform(&input[i]);
}
index = 0;
}
else
{
i = 0;
}
/* buffer remaining input */
memcpy(&_buffer[index], &input[i], length - i);
}
/*
md5 finalization. ends an md5 message-_digest operation, writing the
the message _digest and zeroizing the context.
*/
void md5::final()
{
byte bits[8];
uint32 oldstate[4];
uint32 oldcount[2];
uint32 index, padlen;
/* save current state and count. */
memcpy(oldstate, _state, 16);
memcpy(oldcount, _count, 8);
/* save number of bits */
encode(_count, bits, 8);
/* pad out to 56 mod 64. */
index = (uint32)((_count[0] >> 3) & 0x3f);
padlen = (index < 56) ? (56 - index) : (120 - index);
update(padding, padlen);
/* append length (before padding) */
update(bits, 8);
/* store state in digest */
encode(_state, _digest, 16);
/* restore current state and count. */
memcpy(_state, oldstate, 16);
memcpy(_count, oldcount, 8);
}
其余接口(公有的)采用适配器模式就可以了。
[html]
void md5::update(const void *input, size_t length)
{
update((const byte*)input, length);
}
void md5::update(const qstring &str)
{
update((const byte*)str.tolatin1().data(), str.length());
}
void md5::update(ifstream &in)
{
if (!in)
{
return;
}
std::streamsize length;
char buffer[buffer_size];
while (!in.eof())
{
in.read(buffer, buffer_size);
length = in.gcount();
if (length > 0)
{
update(buffer, length);
}
}
in.close();
}
void md5::update(const void *input, size_t length)
{
update((const byte*)input, length);
}
void md5::update(const qstring &str)
{
update((const byte*)str.tolatin1().data(), str.length());
}
void md5::update(ifstream &in)
{
if (!in)
{
return;
}
std::streamsize length;
char buffer[buffer_size];
while (!in.eof())
{
in.read(buffer, buffer_size);
length = in.gcount();
if (length > 0)
{
update(buffer, length);
}
}
in.close();
}
*所述实例,并不是示例代码中那样标准的适配器模式。当然可以进行改写,但我认为完全没有必要。设计模式的初衷就是使代码更为美观、高效。
作者:tandesir