Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;独立访问器/变异器接口的设计模式_C++_Design Patterns_Inheritance_Interface - Fatal编程技术网

C++ C++;独立访问器/变异器接口的设计模式

C++ C++;独立访问器/变异器接口的设计模式,c++,design-patterns,inheritance,interface,C++,Design Patterns,Inheritance,Interface,我有一个数据结构“Person” 我想围绕此结构创建“视图”,以分离对不同成员变量的访问: class PersonRead: public Person { public: string getName() {..} int getAge() {...} ... } class PersonUpdate: public Person { public: void setAddress( string address_ ) {...} void s

我有一个数据结构“Person”

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

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);
...
}
尽管上述代码符合我的目的,但存在以下几个问题:

  • 这里的公共继承并不完全是一种“是一种”关系

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

    struct IndianPerson: public Person {};
    class IndianPersonRead: public IndianPerson, public PersonRead {}; //Person Class common, Diamond pattern here!
    
  • 这种设计模式有名字吗?实现此模式的更好方法是什么?我觉得策略类可能会有所帮助,但我不知道如何实现这一点


    任何例子都会很有帮助

    我认为你的方法根本不正确:
    PersonRead
    PersonUpdate
    都不是人。他们读取和修改个人数据,但实际上并不是
    个人

    同样地,
    IndianPersonRead
    IndianPersonUpdate
    也不是
    IndianPersonRead

    我将这种关系分为以下几点:

    • PersonRead
      使用
      Person
    • PersonUpdate
      使用
      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;
    }
    
    #包括
    #包括
    使用名称空间std;
    结构人
    {
    字符串getname()常量{return name;}
    字符串getaddress()常量{返回地址;}
    void setaddress(常量字符串和地址){address=address}
    void setname(常量字符串&名称){name=name}
    受保护的:
    字符串名;
    智力年龄;
    字符串地址;
    };
    班级人事
    {
    公众:
    字符串getname(constPerson&p){返回p.getname();}
    };
    班级人事更新
    {
    公众:
    void setAddress(Person&p,const string&address){p.setAddress(address)}
    void setname(Person&p,const string&name){p.setname(name);}
    };
    结构印地安人:公众人士
    {
    字符串gettribe()常量{return tribe;}
    void settribe(const string&tribe_){tribe=tribe_;}
    受保护的:
    弦部落;
    };
    结构IndianPersonRead:公共PersonRead
    {
    公众:
    字符串gettribe(const IndianPerson&p)const{return p.gettribe();}
    };
    结构IndianPersonUpdate:公共PersonUpdate
    {
    公众:
    void settribe(IndianPerson&p,const string&t){p.settribe(t);}
    };
    int main(int argc,字符**argv)
    {
    印度人知识产权;
    印度人民议会联盟;
    印度个人阅读知识产权;
    ipU.settribe(ip,“Cheroki”);
    ipU.setname(ip,“Charly”);
    
    cout对于您的场景,这似乎有些过分,但是,如果您想要细粒度地控制哪些类可以在类上调用不同的方法,那么这个习惯用法可能是合适的

    有关此成语的详细说明,请参见

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

    这可以按如下方式使用:

    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();
    }
    

    首先,我同意Tio的观点,PersonUpdate不是人,因此存在错误的继承用法。此外,我认为您需要使用target来表示真实世界,因此像PersonUpdate这样的类是错误的,因为它们表示动作而不是对象

    在您的情况下,一个解决方案可能是使用访问者设计模式,因此用户可以接受一个专门设计的IPersonStream接口,以便在将实现该接口的类中执行序列化。
    Person stream将接受其上的persons属性或Person的memento查看memento设计模式,并将其序列化为xml或任何您想要的格式。

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


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

    +1:我同意这可以改进继承的使用。但是,在尝试编写类似
    的东西时,使用这种层次结构仍然很烦人writePersonDataToFile
    在问题中概述:这样的函数不可能采用正确的类型(
    const Person&
    )但对于例如
    IndianPerson
    实例,它仍然可以正常工作,除非每个人都知道如何序列化自己。假设您不想在每个
    Person
    中都有一个“序列化”方法,您可能需要一个
    PersonSerializer
    类的树(而不是
    PersonRead
    )。
    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();
    }