سؤال

هذا هو سؤالي الأول هنا :)

أعلم أنه لا ينبغي علي التحقق من نوع الكائن ولكن بدلاً من ذلك استخدم Dynamic_cast ، لكن هذا لن يحل مشكلتي.

لدي فئة تسمى التمديد والواجهات التي تسمى iextendable و iinitializable ، iupdatable ، قابلة للضرب ، قابلة للعلاج (الأربعة الأخيرة هي نفسها بشكل أساسي). إذا كان الامتداد ينفذ واجهة iextendable ، فيمكنه تمديد نفسه مع كائنات تمديد مختلفة.

تكمن المشكلة في أنني أريد السماح للتمديد الذي ينفذ iextendenge ليتم تمديده فقط بالتمديد الذي ينفذ نفس الواجهات مثل الامتداد الأصلي.

ربما لا تحرز هذه الفوضى ، لذا أحاول شرحها بالرمز:

class IExtendable
{
public:
 IExtendable(void);

 void AddExtension(Extension*);
 void RemoveExtensionByID(unsigned int);

 vector<Extension*>* GetExtensionPtr(){return &extensions;};
private:
 vector<Extension*> extensions;
};

class IUpdatable
{
public:
 IUpdatable(void);
 ~IUpdatable(void);

 virtual void Update();
};

class Extension
{
public:
 Extension(void);
 virtual ~Extension(void);

 void Enable(){enabled=true;};
 void Disable(){enabled=false;};

 unsigned int GetIndex(){return ID;};

private:
 bool enabled;
 unsigned int ID;

 static unsigned int _indexID;
};

تخيل الآن الحالة التي أقوم بإنشائها ملحقًا مثل هذا:

class MyExtension : public Extension, public IExtendable, public IUpdatable, public IDrawable
{
public:
    MyExtension(void);
    virtual ~MyExtension(void);

    virtual void AddExtension(Extension*);
    virtual void Update();
    virtual void Draw();
};

وأريد أن أسمح لهذا الفئة بتوسيع نفسها فقط مع الامتدادات التي تنفذ نفس الواجهات (أو أقل). على سبيل المثال ، أريد أن يكون قادرًا على أخذ التمديد الذي ينفذ iupdatable ؛ أو كلاهما iupdatable و idrawable ؛ ولكن على سبيل المثال ليس التمديد الذي ينفذ Iloadable. أريد أن أفعل ذلك لأنه عندما يتم استدعاء EG Update () على بعض التمديد الذي ينفذ iextendable و iupdatable ، سيتم استدعاؤه أيضًا في هذه الامتدادات التي تمتد هذا الامتداد.

لذلك عندما أقوم بإضافة بعض الامتداد إلى التمديد الذي ينفذ iextendable وبعض من iupdatable ، قابلة للإلغاء ... أنا مجبر على التحقق مما إذا كان التمديد الذي سيتم إضافة هذه الواجهات أيضًا. لذلك في iextendable :: addextension (تمديد*) سأحتاج إلى فعل شيء مثل هذا:

void IExtendable::AddExtension(Extension* pEx)
{
bool ok = true;
// check wheather this extension can take pEx
// do this with every interface
if ((*pEx is IUpdatable) && (*this is_not IUpdatable))
ok = false;

if (ok) this->extensions.push_back(pEx);

}

ولكن كيف؟ أي أفكار ما هو الحل الأفضل؟ لا أرغب في استخدام Dynamic_cast ومعرفة ما إذا كان يعود فارغًا ... شكرًا

هل كانت مفيدة؟

المحلول

يجب أن تعيد التفكير في التصميم الخاص بك. إذا كنت بحاجة إلى هذا السلوك ، فربما تقدم IUpdateExtendable و IDrawExtendable.

السبب في أن النهج الحالي سيء هو أنه ينتهك مبدأ استبدال Liskov. أنت تقول أساسًا "هذا الكائن يعمل كـ iextending ، لكنه لا يفعل ذلك حقًا ، إلا إذا كان ...." إذا قام الفصل بتنفيذ واجهة ، فيجب أن يكون قابلاً للاستخدام من خلال تلك الواجهة بدون أي الظروف. إذا لم يكن الأمر كذلك ، فهو كابوس الصيانة في انتظار حدوثه.

نصائح أخرى

مجرد حدس ، ولكن اعتمادًا على ما تفعله ملحقاتك ، النمط الزائر قد يساعدك. قد ترغب أيضًا في القراءة على ديكور نمط.

يمكنني دمج كل هذه الواجهات في فصل واحد حتى أحصل على شيء مثل هذا:

class Extension
{
public:
Extension(void);
virtual ~Extension(void);

void AddExtension(Extension* pEx){extensions.push_back(pEx);};

virtual void Initialize()
{
for each (Extension* pEx in extensions) pEx->Initialize();
};

virtual void Load()
{
for each (Extension* pEx in extensions) pEx->Load();
};

virtual void Update()
{
for each (Extension* pEx in extensions) pEx->Update();
};

virtual void Draw()
{
for each (Extension* pEx in extensions) pEx->Draw();
};

private:
vector<Extension*> extensions;
};

ولكن هذا يعني أنه سيتم استدعاء جميع الأساليب على كل امتداد إضافي. على سبيل المثال ، سيتم استدعاء الطرق الفارغة في بعض الامتدادات المضافة التي لا تقوم بتحميل أي محتوى ولا ترسم أي شيء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top