سؤال

ولدي البرمجية التالية ل "المصنع" تنفيذ نمط التصميم.

class Pen{
public:
     virtual void Draw() = 0;
};

class RedPen : public Pen{
public:
     virtual void Draw(){
         cout << "Drawing with red pen" << endl;
     }
};

class BluePen : public Pen{
public:
     virtual void Draw(){
         cout << "Drawing with blue pen" << endl;
     }
};

auto_ptr<Pen> createPen(const std::string color){
     if(color == "red")
         return auto_ptr<Pen>(new RedPen);
     else if(color == "blue")
         return auto_ptr<Pen>(new BluePen);
}

ولكن سمعت أنه يمكن القيام به بطريقة أفضل باستخدام "++ C القوالب". يمكن لأي شخص أن تساعد كيف يتم ذلك وكيف نهج قالب أفضل من هذا؟

وأية أفكار

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

المحلول

في المثال قمت بنشرها، ولا مصنع أو نهج قالب من المنطقي بالنسبة لي. يتضمن حل بي عضو بيانات في فئة القلم.

class Pen {
public:
    Pen() : m_color(0,0,0,0) /* the default colour is black */
    {            
    }

    Pen(const Color& c) : m_color(c)
    {
    }

    Pen(const Pen& other) : m_color(other.color())
    {
    }

    virtual void Draw()
    {
        cout << "Drawing with a pen of color " << m_color.hex();
    }
    void setColor(const Color& c) { m_color = c; }
    const Color& color() const { return m_color; }
private:
    Color m_color;
};

class Color {
public:
    Color(int r, int g, int b, int a = 0) :
        m_red(r), m_green(g), m_blue(other.blue()), m_alpha(a)  
    {
    }

    Color(const Color& other) : 
        m_red(other.red()), m_green(other.green()), 
        m_blue(other.blue()), m_alpha(other.alpha())
    {
    }

    int red() const { return m_red; }
    int green() const  { return m_green; }
    int blue() const { return m_blue; }
    int alpha() const { return m_alpha; }

    std::string hex() const
    {
        std::ostringstream os;
        char buf[3];
        os << "#";

        sprintf(buf, "%2X", red());
        os << buf;

        sprintf(buf, "%2X", green());
        os << buf;

        sprintf(buf, "%2X", blue());
        os << buf;

        sprintf(buf, "%2X", alpha());
        os << buf;

        return os.str();
    }

private:
    int m_red;
    int m_green;
    int m_blue;
    int m_alpha;
}

وبطبيعة الحال، فإن الطبقة لون لها أن تعدل إلى API رسم استخدام - وربما تكون وسيلة أكثر تقدما من هذا واحد (مساحات اللون المختلفة، الخ)

لماذا لا القوالب؟

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

وهكذا، فإن وظيفة تعادل إما أن تأخذ اللون كحجة، أو (كما هو الحال في بلدي على سبيل المثال) لديها اللون كعضو بيانات الطبقة.

نصائح أخرى

وهناك طريقة أخرى لتسجيل حيوي <م> مبدع وظيفة إلى كائن مصنع الدينامية.

BluePen *create_BluePen() { return new BluePen; }
static bool BluePen_creator_registered = 
                       Factory::instance()->registerCreator("BluePen", 
                                                            create_BluePen);

وأحد الآثار للاهتمام في القيام مثل هذه هو أن ساكنة BluePen-creator-registered متغير منطقي سيتم تعيين main() قبل يبدأ مما يجعل تسجيل الآلي.

وتتكون هذه الخطوط في بعض الأحيان من خلال وحدات الماكرو العادية، أي أنه

#define METAIMPL( _name ) \
_name *create_ ## _name() { return new _name; } \
static bool _name ## _creator_registered = \
                        Factory::instance()->registerCreator(# _name, \
                                                             create_ ## _name)

... واستخدامها على مقربة من منشئ

METAIMPL( BluePen ); // auto registers to the Factory

BluePen::BluePen() : Pen() {
   // something
}

وبعد ذلك سوف مهمة مصنع ستكون لتخزين والبحث عن هذه <م> مبدع وظائف. أترك بقية ك <م> ممارسة ؛) أي استخدام ماكرو METADECL

إذا كنت تريد المزيد من المعلومات، انظر هنا تحت الفصل <م> 4.1 معلومات ميتا التي تضم أيضا وسيلة لتتوسع لتشمل الاحتمالات عن مفتش ميزات

وتعلمت هذا من استخدام ET ++ التي كانت مشروعا لميناء MacApp القديم إلى C ++ وX11. في جهد بدأ اريك غاما غيرها للتفكير <م> أنماط التصميم

و... (7 مايو 2011) وأخيرا جاء في جميع أنحاء لدفع مثالا لجيثب
الشبكي : //github.com/epatel/cpp-factory

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

<اقتباس فقرة>   

وعندما كنت تعرف في وقت الترجمة (أي عند كتابة التعليمات البرمجية) التي تريد نوع معين عاد، ثم استخدام قالب. خلاف ذلك، لا يمكنك.

وهذا يعني في التعليمات البرمجية، التي يمكنك القيام بذلك:

template<typename PenType>
auto_ptr<Pen> createPen(){
    return auto_ptr<Pen>(new PenType);
}

وبعد أن في المكان، ثم يمكنك استخدام ذلك مثل

...
auto_ptr<Pen> p = createPen<BluePen>();
...

ولكن هذا القالب حجة، وBluePen، لا يمكن أن يكون متغير التي تم تعيينها إلى نوع في وقت التشغيل. في المثال الخاص بك، يمكنك تمرير السلسلة، والذي يمكن بالطبع أن تكون وضعت في وقت التشغيل. لذلك، عندما تقرأ هذا يمكنك استخدام قوالب C ++، ثم أن التوصية فقط الحقيقية مشروط - بعد ذلك، عندما قراركم، منها القلم لخلق، ويتم ذلك بالفعل في وقت الترجمة. إذا كان هذا الشرط تناسبها، ثم حل القالب <م> من الشيء الصحيح الذي ينبغي القيام به. انها لن تكلفك شيئا في وقت التشغيل، وسوف يكون بالضبط ما تحتاجه.

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

struct Red{};
struct Blue{};

template < typename Color >
class Pen{};

template <>
class Pen< Red >
{
     void Draw(){
         cout << "Drawing with red pen" << endl;
     }
};

template <>
class Pen< Blue >
{
     void Draw(){
         cout << "Drawing with blue pen" << endl;
     }
};

template < typename Color >
std::auto_ptr< Pen< Color > > createPen()
{
     return auto_ptr< Pen< Color > >(new Pen< Color >());
}

هل يمكن إرسال بريد العامة الطبقة المصنع الكائن كطبقة القالب (أو استخدام واحد هو موضح بشكل جيد في هذا <وأ href = "http://www.gamedev.net/page/resources/_/technical/general-programming / أ-عام وجوه خلق-مصنع-r2097 "يختلط =" نوفولو "> gamedev.net المقالة ).

وبهذه الطريقة، إذا كان لديك المصنع أكثر من واحد في التعليمات البرمجية، بل هو عمل أقل لتعريف كل مصنع.

واستكمالا لجوابي أخرى، لمجرد مناقشة نمط مصنع مقابل Useage والقالب:

وو(وأبسط) السبب الرئيسي لاستخدام القوالب، هو أن الشفرة هي متطابقة في كل حالة، باستثناء أنواع البيانات يعمل على. الأمثلة هنا هي حاويات STL. وسيكون من الممكن لكتابة createVector وظيفة مصنع ( "السلسلة")، واكتب بها كل حاوية يدويا - ولكن هذا هو واضح دون المستوى الأمثل

وحتى عندما يختلف الرمز، لا أنواع البيانات فقط، فمن الممكن استخدام التخصصات قالب - ولكن في كثير من الحالات، فإن وظيفة مصنع أكثر منطقية

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

في هذا المثال، هو أكثر بديهية القول ديسيبل :: get_driver (دبك) ونعود يلقي الدرجة المناسبة لنوع واجهة.

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