سؤال

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

void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    for(int x = x0; x < x1; x += step)
    {
         MoveToEx(dc, x, y0, NULL);
         LineTo(dc, x, y1);
    }
}
void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    for(int y = y0; y < y1; y += step)
    {
         MoveToEx(dc, x0, y, NULL);
         LineTo(dc, x1, y);
    }
}

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

سؤالي هو كيف يمكنك إعادة كتابة هاتين الوظيفتين في وظيفة واحدة لتجنب هذه المشكلة؟

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

المحلول

رسم خط هو ببساطة ربط نقطتين، ورسم مقياس متزايد (x0,y0) و(x1,y1) في اتجاه معين، من خلال X و/أو من خلال Y.يتلخص هذا، في حالة المقياس، في أي اتجاه (اتجاهات) يحدث (ربما كلا الاتجاهين من أجل المتعة).

template< int XIncrement, YIncrement >
struct DrawScale
{
  void operator()(HDC dc, int step, int x0, int x1, int y0, int y1)
  {
    const int deltaX = XIncrement*step;
    const int deltaY = YIncrement*step;
    const int ymax = y1;
    const int xmax = x1;
    while( x0 < xmax && y0 < ymax )
    {
        MoveToEx(dc, x0, y0, NULL);
        LineTo(dc, x1, y1);
        x0 += deltaX;
        x1 += deltaX;
        y0 += deltaY;
        y1 += deltaY;
    }
  }
};
typedef DrawScale< 1, 0 > DrawScaleX;
typedef DrawScale< 0, 1 > DrawScaleY;

سوف يقوم القالب بعمله:في وقت الترجمة سيقوم المترجم بإزالة كافة العبارات الفارغة، أي.قيمة deltaX أو deltaY هي 0 فيما يتعلق بالوظيفة التي يتم استدعاؤها ويختفي نصف الكود في كل عامل.

يمكنك إضافة عناصر مضادة للاسم المستعار والقلم الرصاص داخل وظيفة uniq هذه والحصول على الكود الذي تم إنشاؤه بشكل صحيح بواسطة المترجم.

يتم قص ولصق هذا على المنشطات ;-)

-- نقطة في البوصة

نصائح أخرى

لماذا لا تقوم باستخراج جسم الدورة إلى وظيفة منفصلة؟ثم يمكنك القيام بالأشياء المضحكة في الوظيفة المستخرجة.

void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    for(int x = x0; x < x1; x += step)
    {
        DrawScale(dc, x, y0, x, y1);
    }
}

void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    for(int y = y0; y < y1; y += step)
    {
        DrawScale(dc, x0, y, x1, y);
    }
}

private void DrawScale(HDC dc, int x0, int y0, int x1, int y1)
{
    //Add funny stuff here

    MoveToEx(dc, x0, y0, NULL);
    LineTo(dc, x1, y1);

    //Add funny stuff here
}

هنا هو الحل الخاص بي


class CoordGenerator
{
public:
    CoordGenerator(int _from, int _to, int _step)
        :from(_from), to(_to), step(_step), pos(_from){}
    virtual POINT GetPoint00() const = 0;
    virtual POINT GetPoint01() const = 0;
    bool Next()
        {
            if(pos > step) return false;
            pos += step;
        }
protected:
    int from;
    int to;
    int step;
    int pos;
};

class GenX: public CoordGenerator
{
public:
    GenX(int x0, int x1, int step, int _y0, int _y1)
        :CoordGenerator(x0, x1, step),y0(_y0), y1(_y1){}
    virtual POINT GetPoint00() const
        {
            const POINT p = {pos, y0};
            return p;
        }
    virtual POINT GetPoint01() const
        {
            const POINT p = {pos, y1};
            return p;
        }
private:
    int y0;
    int y1;
};

class GenY: public CoordGenerator
{
public:
    GenY(int y0, int y1, int step, int _x0, int _x1)
        :CoordGenerator(y0, y1, step),x0(_x0), x1(_x1){}
    virtual POINT GetPoint00() const
        {
            const POINT p = {x0, pos};
            return p;
        }
    virtual POINT GetPoint01() const
        {
            const POINT p = {x1, pos};
            return p;
        }
private:
    int x1;
    int x0;
};

void DrawScale(HDC dc, CoordGenerator* g)
{
    do
    {
        POINT p = g->GetPoint00();
        MoveToEx(dc, p.x, p.y, 0);
        p = g->GetPoint01();
        LineTo(dc, p.x, p.y);
    }while(g->Next());
}

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

حسنًا، "الحل" الواضح هو إنشاء دالة واحدة وإضافة معلمة إضافية واحدة (من نوع يشبه التعداد).ثم قم بإجراء if() أو Switch() بالداخل، وقم بتنفيذ الإجراءات المناسبة.لأنه مهلا، وظائف تختلف الوظائف، لذلك يتعين عليك القيام بتلك الإجراءات المختلفة مكان ما.

ومع ذلك، فإن هذا يضيف تعقيدًا في وقت التشغيل (التحقق من الأشياء في وقت التشغيل) في مكان يمكن التحقق منه بشكل أفضل في وقت الترجمة.

لا أفهم ما هي المشكلة في إضافة معلمات إضافية في المستقبل في كلتا الوظيفتين (أو أكثر).تسير الأمور على هذا النحو:

  1. إضافة المزيد من المعلمات لجميع الوظائف
  2. قم بتجميع الكود الخاص بك، فلن يتم تجميعه في مجموعة من الأماكن لأنه لا يمرر معلمات جديدة.
  3. إصلاح جميع الأماكن التي تستدعي تلك الوظائف عن طريق تمرير معلمات جديدة.
  4. ربح!:)

إذا كان C++، بالطبع يمكنك جعل الوظيفة عبارة عن قالب، وبدلاً من إضافة معلمة إضافية، يمكنك إضافة معلمة قالب، ثم تخصيص تطبيقات القالب للقيام بأشياء مختلفة.لكن هذا مجرد تشويش على النقطة في رأيي.يصبح فهم التعليمات البرمجية أكثر صعوبة، ولا تزال عملية توسيعها بمزيد من المعلمات مستمرة بالضبط نفس الشيء:

  1. إضافة معلمات إضافية
  2. ترجمة التعليمات البرمجية، لن يتم تجميعها في مجموعة من الأماكن
  3. إصلاح جميع الأماكن التي تستدعي هذه الوظيفة

لذا، لم تفز بأي شيء، ولكنك جعلت من الصعب فهم التعليمات البرمجية.ليس هدفا يستحق، المنظمة البحرية الدولية.

أعتقد أنني سأتحرك:

     MoveToEx(dc, x0, y, NULL);
     LineTo(dc, x1, y);

في وظيفتها الخاصة DrawLine(x0,y0,x0,y0)، والتي يمكنك الاتصال بها من كل وظيفة موجودة.

إذن هل هناك مكان واحد لإضافة تأثيرات رسم إضافية؟

القليل من القوالب...:)

void DrawLine(HDC dc, int x0, int y0, int x0, int x1)
{
    // anti-aliasing stuff
    MoveToEx(dc, x0, y0, NULL);
    LineTo(dc, x1, y1);
}

struct DrawBinderX
{
    DrawBinderX(int y0, int y1) : y0_(y0), y1_(y1) {}

    void operator()(HDC dc, int i)
    {
        DrawLine(dc, i, y0_, i, y1_);
    }

private:
    int y0_;
    int y1_;

};

struct DrawBinderY
{
    DrawBinderX(int x0, int x1) : x0_(x0), x1_(x1) {}

    void operator()(HDC dc, int i)
    {
        DrawLine(dc, x0_, i, x1_, i);
    }

private:
    int x0_;
    int x1_;

};

template< class Drawer >
void DrawScale(Drawer drawer, HDC dc, int from, int to, int step)
{
    for (int i = from; i < to; i += step)
    {
         drawer(dc, i);
    }
}

void DrawScaleX(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    DrawBindexX drawer(y0, y1);
    DrawScale(drawer, dc, x0, x1, step);
}

void DrawScaleY(HDC dc, int step, int x0, int x1, int y0, int y1)
{
    DrawBindexY drawer( x0, x1 );
    DrawScale(drawer, dc, y0, y1, step);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top