【描述】適配器模式將某個對象的接口適配為另一個對象所期望的接口。
【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] view plaincopyprint?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] view plaincopyprint?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();
}
*所述實例,並不是示例代碼中那樣標准的適配器模式。當然可以進行改寫,但我認為完全沒有必要。設計模式的初衷就是使代碼更為美觀、高效。