4

我有一个数据结构“人”

struct Person
{
  protected:
    string name;
    int age;
    string address;
    ...
}

我想围绕这个结构创建“视图”,以分离出对不同成员变量的访问:

class PersonRead: public Person
{
  public:
    string getName() {..}
    int getAge() {...}
    ...
}
class PersonUpdate: public Person
{
  public:
    void setAddress( string address_ ) {...}
    void setAge( int age_ ) {...}
    ...
}

我用它来只公开那些真正需要的方法/变量:

int main()
{
...
    writePersonDataToFile ( (PersonRead) personObj );
    updatePersonData ( (PersonUpdate) personObj);
...
}

虽然上面的代码符合我的目的,但有几个问题,包括:

  1. 这里的公共继承并不完全是“is-a”关系

  2. 我需要从 Person 派生 IndianPerson 以及所有相应的接口。这会导致不良的菱形图案:

    struct IndianPerson: public Person {};
    class IndianPersonRead: public IndianPerson, public PersonRead {}; //Person Class common, Diamond pattern here!
    

这种设计模式有名字吗?有什么更好的方法来实现这种模式?我有一种感觉政策类可能会有所帮助,但无法弄清楚如何实现这一点

任何例子都会有很大帮助

4

4 回答 4

4

对于您的场景,这可能看起来有点矫枉过正,但是,如果您想要细粒度地控制哪些类可以在您的类上调用不同的方法,那么c++ 客户律师惯用语可能是合适的。

有关此成语的详细说明,请参见http://drdobbs.com/184402053

这是一个粗略的示例(注意:虽然它基于我当前使用的生产代码,但尚未编译):

class Person
{
public:
   /// constructor destructor etc:

private:
    string getName() { return name; }

public:
    /// Writer Attourney that access to allows class PersonReader access 
    /// to getXXX functions
    class ReaderAttorney
    {
    private:
        /// Add additional reader member functions...
        static string readName( Person& p )
        { 
            return p.getName();
        }

        // Make any classes that shuold be allowde read access friends of the 
        // attorney here
        friend class PersonReader;
    };

    /// Writer Attourney that access to allows class PersonWriter access 
    /// to setXXX functions
    class WriterAttorney
    {
    private:
        /// Add additiona reader member functions...
        static string setName( Person& p, const string& newName )
        { 
            p.setName( newName );
        }
        friend class PersonWriter;
    };

private:
    string name;
    int age;
    string address;
};

这可以按如下方式使用:

void PersonWriter::setPersonDetails( const string& name, int age .... )
{
   // PersonWriter is a frend of WriterAttorney and is granted access
   Person::WriterAttorney::setName( name );
   Person::WriterAttorney::setName( age );

   // Note this will fail, since PersonWriter is not a friend of 
   // ReaderAttorney, ergo it is not granted read permission:
   Person::ReaderAttorney::readName();
}
于 2012-04-04T10:40:08.877 回答
2

我认为您的方法根本不正确:PersonRead并且PersonUpdate不是人。他们读取和修改 Person 数据,但实际上并非如此Person

以同样的方式,IndianPersonRead并且IndianPersonUpdate不是IndianPerson.

我将这种关系分开如下:

  • PersonRead利用Person
  • PersonUpdate利用Person
  • IndianPerson继承自Person:是Person
  • IndianPersonRead继承自PersonRead和使用IndianPerson
  • IndianPersonUpdate继承自PersonUpdate 和使用IndianPerson

我展示了我的方法的一个例子:

#include <string>
#include <iostream>
using namespace std;

struct Person
{
    string getname() const { return name; }
    string getaddress() const { return address; }
    void setaddress(const string & address_) { address = address_; }
    void setname(const string & name_) { name = name_; }

    protected:
        string name;
        int age;
        string address;
};

class PersonRead
{
    public:
        string getname(const Person & p) { return p.getname(); }
};

class PersonUpdate
{
    public:
        void setAddress(Person & p, const string & address_ ) {p.setaddress(address_); }
        void setname(Person & p, const string & name_ ) {p.setname(name_); }
};

struct IndianPerson : public Person
{
    string gettribe() const { return tribe; }
    void settribe(const string & tribe_) { tribe = tribe_; }
    protected:
    string tribe;
};

struct IndianPersonRead : public PersonRead
{
    public:
        string gettribe(const IndianPerson & p) const { return p.gettribe(); }
};

struct IndianPersonUpdate : public PersonUpdate
{
    public:
    void settribe(IndianPerson & p, const string & t)   { p.settribe(t); }
};

int main(int argc, char **argv)
{
    IndianPerson ip;
    IndianPersonUpdate ipU;
    IndianPersonRead ipR;

    ipU.settribe(ip, "Cheroki");
    ipU.setname(ip, "Charly");
    cout << ipR.getname(ip) << " : " << ipR.gettribe(ip) << endl;
}
于 2012-04-04T10:39:11.600 回答
0

首先,我同意 Tio 的观点 PersonUpdate 不是 Person 所以继承使用错误。另外我相信你需要让你的类带有目标来代表现实世界,所以像 PersonUpdate 这样的类是错误的,因为它们代表的是动作而不是对象。

在您的情况下,一种解决方案可能是使用访问者设计模式,因此 Person 可以接受特别设计的 IPersonStream 接口,以便在将实现此接口的类中执行序列化。人员流将接受其上的人员属性,或者人员的纪念品看看纪念品设计模式,并将其序列化为 xml 或您想要的任何内容。

于 2012-04-04T10:52:30.400 回答
0

我没有设计模式名称,但为了解决您的顾虑,我会交换继承关系,让 Person 从 PersonReader 和 PersonWriter 接口继承。这样,只能从 Person 读取的对象使用 PersonReader 接口,因此承诺不会更改它。

通过将 Person 的每个成员设为私有,您甚至可以确保不以其他方式访问 Person,但是从 Person 继承的每个类都应该将这些成员设为私有。

于 2012-04-04T11:11:20.170 回答