4

私はデータ構造「Person」を持っています

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

同じように、IndianPersonReadIndianPersonUpdateはありません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のようなクラスはオブジェクトではなくアクションを表すため、現実の世界を表すためにターゲットを使用してクラスを作成する必要があると思います。

In your case one solution could be to use the visitor design pattern, so the Person could accept a especially designed IPersonStream interface in order to perform the serialization in classes which will implement this interface. Person stream will accept the persons attributes on it or for good the Person's memento take a look on memento design pattern, and serialize it to xml or whatever you want.

于 2012-04-04T10:52:30.400 に答える
0

I don't have a design pattern name, but to resolve your concerns, I would swap the inheritance relation and let Person inherit from the PersonReader and PersonWriter interfaces. This way, objects that must only read from Person use the PersonReader interface and as such promises to not change it.

Personのすべてのメンバーをプライベートにすることで、Personが別の方法でアクセスされないようにすることもできますが、Personから継承するすべてのクラスはこれらのメンバーをプライベートにする必要があります。

于 2012-04-04T11:11:20.170 に答える