1

私はxmlパーサーを書いていますが、オブジェクトをクラスに一般的に追加して、オブジェクトの実際のタイプをオンにする必要があります。問題は、単にaddElement(BaseClass *)であるインターフェースを維持し、オブジェクトを正しく配置したいということです。

void E_TableType::addElement(Element *e)
{
    QString label = e->getName();
    if (label == "state") {
        state = qobject_cast<E_TableEvent*>(e);
    }
    else if (label == "showPaytable") {
        showPaytable = qobject_cast<E_VisibleType*>(e);
    }
    else if (label == "sessionTip") {
        sessionTip = qobject_cast<E_SessionTip*>(e);
    }
    else if (label == "logoffmedia") {
        logoffMedia = qobject_cast<E_UrlType*>(e);
    }
    else {
        this->errorMessage(e);
    }
}

これは、オブジェクトファクトリである呼び出し元のクラスです。myElementはE_TableTypeのインスタンスです。

F_TableTypeFactory::F_TableTypeFactory()
{
    this->myElement = myTable = 0;
}

void F_TableTypeFactory::start(QString qname)
{
     this->myElement = myTable = new E_TableType(qname);
}

void F_TableTypeFactory::fill(const QString& string)
{
  // don't fill complex types.
}

void F_TableTypeFactory::addChild(Element* child)
{
    myTable->addElement(child);
}

Element* F_TableTypeFactory::finish()
{
    return myElement;
}

void F_TableTypeFactory::addAttributes(const QXmlAttributes &attribs) {
    QString tName = attribs.value(QString("id"));
    myTable->setTableName(tName);
}
4

3 に答える 3

2

ここでポリモーフィズムの使用を検討しましたか?共通のインターフェースを各具象クラスで実装できる場合、このコードはすべてなくなり、将来的には単純で簡単に変更できるようになります。例えば:

class Camera {
public:
    virtual void Init() = 0;
    virtual void TakeSnapshot() = 0;
}

class KodakCamera : Camera {
public:
    void Init() { /* initialize a Kodak camera */ };
    void TakeSnapshot() { std::cout << "Kodak snapshot"; }
}

class SonyCamera : Camera {
public:
    void Init() { /* initialize a Sony camera */ };
    void TakeSnapshot() { std::cout << "Sony snapshot"; }
}

したがって、ハードウェアデバイス(この場合はカメラ)を含むシステムがあると仮定します。写真を撮るにはデバイスごとに異なるロジックが必要ですが、コードはサポートされているカメラを備えたシステムをサポートする必要があるため、コード全体にswitchステートメントが散らばっていないようにします。そこで、抽象クラスを作成しましたCamera

各具象クラス(つまりSonyCamera、、KodakCamera)の実装には、異なるヘッダー、異なるライブラリへのリンクなどが含まれますが、それらはすべて共通のインターフェースを共有します。どちらを作成するかを前もって決める必要があります。それで...

std::unique_ptr<Camera> InitCamera(CameraType type) {
    std::unique_ptr<Camera> ret;
    Camera *cam;
    switch(type) {
    case Kodak:
        cam = new KodakCamera();
        break;
    case Sony:
        cam = new SonyCamera();
        break;
    default:
        // throw an error, whatever
        return;
    }

    ret.reset(cam);
    ret->Init();
    return ret;
}

int main(...) {
    // get system camera type
    std::unique_ptr<Camera> cam = InitCamera(cameraType);
    // now we can call cam->TakeSnapshot 
    // and know that the correct version will be called.
}

これで、を実装する具体的なインスタンスができましたCameraTakeSnapshot関係ないので、コードのどこでも正しいタイプをチェックせずに呼び出すことができます。正しいハードウェアの正しいバージョンが呼び出されることがわかっています。これがお役に立てば幸いです。

以下のコメントによると:

ポリモーフィズムを使おうとしていますが、要素が大きく違うと思います。たとえば、E_SessionTipにはamount要素とstatus要素があり、E_UrlにはURLがあります。私はこれをプロパティシステムの下で統一することができましたが、それから私はすべての素晴らしいタイピングを完全に失います。ただし、これが機能する方法をご存知の場合は、提案を受け付けています。

共通のインターフェースを共有するタイプにXMLデータを書き込む責任を渡すことを提案します。たとえば、次のようなものの代わりに:

void WriteXml(Entity *entity) {
   switch(/* type of entity */) {
      // get data from entity depending
      // on its type and format
   }

   // write data to XML
}

このようなことをします:

class SomeEntity : EntityBase {
public:
    void WriteToXml(XmlStream &stream) {
        // write xml to the data stream.
        // the entity knows how to do this,
        // you don't have to worry about what data
        // there is to be written from the outside
    }
private:
    // your internal data
}

void WriteXml(Entity *entity) {
    XmlStream str = GetStream();
    entity->WriteToXml(stream);
}

それはあなたのために働きますか?私は以前にこれを正確に行ったことがあり、それは私のために働いた。お知らせ下さい。

于 2012-07-02T17:34:11.913 に答える
1

ビジターパターンを見てください、それはあなたを助けるかもしれません

于 2012-07-02T21:08:33.440 に答える
1

ダブルディスパッチは興味深いかもしれません。テーブル(あなたの場合)は基本要素の仮想メソッドを呼び出し、それが次にテーブルにコールバックします。この2番目の呼び出しは、オブジェクトの動的タイプを使用して行われるため、適切なオーバーロードされたメソッドがTableクラスで見つかります。

#include <iostream>

class Table;  //forward declare
class BaseElement
{
public:
   virtual void addTo(Table* t);
};
class DerivedElement1 : public BaseElement
{
   virtual void addTo(Table* t);
};
class DerivedElement2 : public BaseElement
{
   virtual void addTo(Table* t);
};
class Table
{
public:
   void addElement(BaseElement* e){ e->addTo(this); }
   void addSpecific(DerivedElement1* e){ std::cout<<"D1"; } 
   void addSpecific(DerivedElement2* e){ std::cout<<"D2"; } 
   void addSpecific(BaseElement* e){ std::cout<<"B"; } 
};
void BaseElement::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement1::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement2::addTo(Table* t){ t->addSpecific(this); }

int main()
{
Table t;
DerivedElement1 d1;
DerivedElement2 d2;
BaseElement b;

t.addElement(&d1);
t.addElement(&d2);
t.addElement(&b);
}

出力:D1D2B

于 2012-07-02T21:15:54.320 に答える