C++ C++;独立访问器/变异器接口的设计模式
我有一个数据结构“Person” 我想围绕此结构创建“视图”,以分离对不同成员变量的访问: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
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);
...
}
尽管上述代码符合我的目的,但存在以下几个问题:
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();
}