C++ 接口和对象分离的技术
这是Effective C++ Item 31的内容.
先看一下这个类
class Person {
public:
Person(const std::string& name, const Date& birthday,
const Address& addr);
std::string name() const;
std::string birthDate() const;
std::string address() const;
...
private:
std::string theName; // implementation detail
Date theBirthDate; // implementation detail
Address theAddress; // implementation detail
};
为了通过编译在这里在定义 Person 类的文件中,必须包含:
#include <string>
#include "date.h"
#include "address.h"
不幸的是,这样就建立了Person头文件和这些头文件之间的编译依赖关系。
显然,所有Person类的客户都依赖上面三个头文件.这可不是啥么好玩的事情.
一旦这些头文件所依赖的文件发生了变化,所有使用Person 类头文件的文件一样必须重新编译!!!!!
好在Effective C++给出两种解决的方法,个人倾向于第二种(这也是Jacobson的Minimal/Enxtension 理论推荐的),
虽然会牺牲一些运行时间和内存,但代码结构会很清晰也有利于扩展,这是后话.
1.Handle 方法
Person.h
#include <string>
#include <memory>
class PersonImpl;
class Date;
class Address;
class Person {
public:
Person(const std::string& name, const Date& birthday,
const Address& addr);
std::string name() const;
Date birthDate() const;
Address address() const;
...
private:
std::tr1::shared_ptr<PersonImpl> pImpl;
};
Person.cpp
#include "Person.h"
#include "PersonImpl.h"
Person::Person(const std::string& name, const Date& birthday,
const Address& addr)
: pImpl(new PersonImpl(name, birthday, addr))
{
}
std::string Person::name() const
{
return pImpl->name();
}
Date Person::birthDate() const
{
return pImpl->birthDate();
}
Address Person::address() const
{
return pImpl->address();
}
PersonImpl.h
#include <string>
#include "date.h"
#include "address.h"
class PersonImpl {
public:
PersonImpl(const std::string& name, const Date& birthday,
const Address& addr);
std::string name() const;
Date birthDate() const;
Address address() const;
...
private:
std::string theName; // implementation detail
Date theBirthDate; // implementation detail
Address theAddress; // implementation detail
};
PersonImpl.cpp
#include "PersonImpl.h"
PersonImpl::PersonImpl(const std::string& name, const Date& birthday,
const Address& addr)
:theName(name),
theBirthDate(birthday),
theAddress(addr)
{
}
std::string PersonImpl::name() const
{
return theName;
}
Date PersonImpl::birthDate() const
{
return theBirthDate;
}
Address PersonImpl::address() const
{
return theAddress;
}
2.Abstrat Interface 方法
一个 Person 的 Interface 类可能就像这样
class Person {
public:
virtual ~Person();
virtual std::string name() const = 0;
virtual Date birthDate() const = 0;
virtual Address address() const = 0;
};
这个类的客户必须针对 Person 的指针或引用编程,因为实例化包含纯虚函数的类是不可能的。
一个 Interface 类的客户必须有办法创建新的对象。
他们一般通过调用一个为“可以真正实例化的派生类”扮演构造函数的角色的函数做到这一点的。
class Person {
public:
...
static std::tr1::shared_ptr<Person> // return a tr1::shared_ptr to a new
create(const std::string& name, // Person initialized with the
const Date& birthday, // given params; see Item 18 for
const Address& addr); // why a tr1::shared_ptr is returned
...
};
RealPerson.h
class RealPerson: public Person {
public:
RealPerson(const std::string& name, const Date& birthday,
const Address& addr)
: theName(name), theBirthDate(birthday), theAddress(addr)
{}
virtual ~RealPerson() {}
std::string name() const; // implementations of these
Date birthDate() const; // functions are not shown, but
Address address() const; // they are easy to imagine
private:
std::string theName;
Date theBirthDate;
Address theAddress;
};