Брутально и бессердечно о программировании и проектировании
ГлавнаяФорумАртАнтипаттерныТест-драйвЗаметкиВопрос-ответКнигорецензииСправочная

Pimpl idiom — pointer to implementation

Предположим, что вам необходимо воспользоваться внешним API, но при этом вы не хотите позволить платформно-зависимому коду расползаться по проекту и не хотите чтобы у пользователя была возможность им воспользоваться напрямую. В этом случае с вашей задачей прекрасно справится идиома Pimpl.
 
raw_socket.h
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <memory>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

namespace network
{

enum protocol
{
    tcp,
    udp
};

class raw_socket : public boost::noncopyable
{
public:

    raw_socket(protocol proto);

    void connect(std::string const& host, unsigned int port);

    std::size_t send(void const* data, std::size_t size);
    std::size_t receive(void* data, std::size_t size);

private:

    class impl;
    typedef std::auto_ptr<impl> impl_ptr;
    impl_ptr pimpl;
};

typedef boost::shared_ptr<raw_socket> socket_ptr;

} // namespace network
 
raw_socket.cpp
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "raw_socket.h"
#include "raw_socket.inl"

namespace network
{

raw_socket::raw_socket(protocol proto)
: pimpl(new impl(proto))
{

}

void raw_socket::connect(std::string const& host, unsigned int port)
{
    pimpl->connect(host, port);
}

std::size_t raw_socket::send(void const* data, std::size_t size)
{
    return pimpl->send(data, size);
}

std::size_t raw_socket::receive(void* data, std::size_t size)
{
    return pimpl->receive(data, size);
}

} // namespace network
 
raw_socket.inl
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <windows.h>
#include <wsock2.h>

namespace network
{

class raw_socket::impl
{
public:

    impl(protocol proto);
    ~impl();

    void connect(std::string const& host, unsigned int port);

    std::size_t send(void const* data, std::size_t size);
    std::size_t receive(void* data, std::size_t size);

private:

    SOCKET sck;
};

raw_socket::impl::impl(protocol proto)
{
    sck = socket(/* ... */);
}

raw_socket::impl::~impl()
{
    closesocket(sck);
}

void raw_socket::impl::connect(std::string const& host, unsigned int port)
{
    // ...
    ::connect(/* ... */);
}

std::size_t raw_socket::impl::send(void const* data, std::size_t size)
{
    return static_cast<std::size_t>(::send(sck, data, size));
}

std::size_t raw_socket::impl::receive(void* data, std::size_t size)
{
    return static_cast<std::size_t>(::recv(sck, data, size));
}

} // namespace network
 
main.cpp
0
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "raw_socket.h"

int main()
{
    network::socket_ptr sck(new network::raw_socket(network::tcp));

    sck->connect("www.microsoft.com", 80);

    sck->send(/* ... */);

    sck->receive(/* ... */);

    return 0;
}
 
Паттерн позволяет скрыть от пользователя класс с платформно-зависимым кодом. В нашем случае этот класс — network::raw_socket::impl. Весь платформно-зависимый код невидим для пользователя. Пользователь класса network::raw_socket не сможет напрямую вызвать системные сокетные функции, так как включение системных заголовочных файлов происходит внутри cpp-файла. Паттерн позволяет локализовать весь платформно-зависимый код в одном файле и дает гарантию, что ни ваш пользователь, ни вы сами, не сможете работать напрямую с платформно-зависимым кодом. Таким образом вы получаете полную изоляцию и локализацию платформно-зависимого кода в одном файле. Для того, чтобы выполнить переезд на новую операционную систему, или даже на другой тип платформы, вам достаточно просто переписать этот самый impl. Весь остальной код платформно-независим.
За impl-ом обычно скрывают реализацию работы с сокетами, файлами, объектами синхронизации, и прочими общепринятыми системными сущностями. Основная ценность паттерна заключается в том, что он позволяет работать объектно с платформно-зависимым кодом платформно-независимым образом.

Оглавление
Статистика
© 2007—2009 Inside C++ Коммерческие услугиКонтактная информация

салон эротического массажа. консультация врача генетика. весы ювелирные украина. Mazda 3 новая, продам mazda