我正在重构一堆旧代码。我的主要目标是将行为与数据库分离。当前的实现直接访问数据库,这使得很难测试并执行诸如实现缓存层之类的事情......直到这一点,我一直在使用依赖倒置和读者/编写器的组合取得巨大成功,直到我达到了一些我们更复杂的类型。
我有一个抽象的基本用户类,它封装了我们所有用户类型共有的信息。从基类继承的是基本用户类型的许多特化,每个特化都封装了特定于该类型的信息。
如果我有一个指针或对基类的引用,我需要将该用户持久保存到数据库,我如何知道要使用哪个编写器?如果我将编写器用于基类,则特定于派生类的信息将丢失。在基类上放置一个抽象的getUserType()方法然后必须由每个派生实现,这看起来有点像黑客。这可能是双重调度的情况,但实现细节对我来说有点模糊。
class User
{
public:
std::string
name() const
{
return m_name;
}
void
name(const std::string& name)
{
m_name = name;
}
private:
std::string m_name;
}
class EmailUser : User
{
public:
std::list<std::string>
emails() const
{
return m_emails;
}
void
emails(const std::string<std::string>& emails)
{
m_emails = emails;
}
private:
std::set<std::string> m_emails;
}
class UserWriter
{
public:
virtual void
write(User& user) = 0;
}
class DBUserWriter : UserWriter
{
public:
void
write(User& user)
{
SQLExecute("SOME SQL UPDATE STMT %s", user.name());
}
}
class DBEmailUserWriter : UserWriter
{
public:
void
write(User& user)
{
m_baseUserWriter.write(user);
SQLExecute("SOME SQL UPDATE STMT %s", user.email.front());
}
private:
DBUserWriter m_baseUserWriter;
}
答案 0 :(得分:3)
以下是使用维基百科页面中指定的双重调度实现的示例:
#include <iostream>
using namespace std;
class Writer;
class User
{
public:
std::string name() const { return m_name; }
void name(const std::string& name) { m_name = name; }
virtual void accept(Writer & writer) const;
private:
std::string m_name;
};
class EmailUser : public User
{
public:
std::string email() const { return m_email; }
void email(const std::string& email) { m_email = email; }
virtual void accept(Writer & writer) const;
private:
std::string m_email;
};
class Writer
{
public:
void process(const User& user) { user.accept(*this); }
virtual void write(const User& user) { cout << user.name() << endl; }
virtual void write(const EmailUser& user) { cout << user.email() << endl; }
};
class SubWriter : public Writer
{
public:
void process(const User& user) { user.accept(*this); }
void write(const User& user) { cout << "[" << user.name() << endl; }
void write(const EmailUser& user) { cout << "[" << user.email() << endl; }
};
void User::accept(Writer & writer) const { writer.write(*this); }
void EmailUser::accept(Writer & writer) const { writer.write(*this); }
int main()
{
User u;
EmailUser eu;
Writer w;
SubWriter s;
u.name("Hugo Peixoto");
eu.email("hugo.peixoto@gmail.com");
w.process(u);
w.process(eu);
s.process(u);
s.process(eu);
return 0;
}