• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>


            看到這道題,我們就開始設(shè)計(jì)這個(gè)圖像類了,按照面向?qū)ο?#8220;依賴倒置”的設(shè)計(jì)原則,我們站在客戶的立場(chǎng),來考慮我們這個(gè)類該提供哪些接口,很快我們?cè)O(shè)計(jì)了如下一個(gè)類:

            class CSimplePicture
            {
            public:
                CSimplePicture(
            char* init[], int nCount); 
                CSimplePicture(CSimplePicture
            & p1, CSimplePicture& p2, bool bVerCat);

                
            void Frame();
                
            void Print(std::ostream& os) const;
            protected:
                std::vector
            <std::string> m_arData;
            };

            CSimplePicture(char* init[], int nCount);
            根據(jù)字符串?dāng)?shù)組構(gòu)造一幅圖像.

            CSimplePicture(CSimplePicture& p1, CSimplePicture& p2, bool bVerCat);
            根據(jù)兩幅圖像構(gòu)造一幅圖像,bVerCat表明是縱聯(lián)接還是橫聯(lián)接.

            void Frame();
            給圖像對(duì)象加框

            void Print(std::ostream& os) const;
            打印輸出圖像

            std::vector<std::string> m_arData;
            存儲(chǔ)圖像數(shù)據(jù)的字符串?dāng)?shù)組

            下面來考慮具體實(shí)現(xiàn),這個(gè)對(duì)于有一定開發(fā)的經(jīng)驗(yàn)的人來說還是很容易的,就不具體寫了,
            CSimplePicture(char* init[], int nCount)無非是數(shù)據(jù)的拷貝,CSimplePicture(CSimplePicture& p1, CSimplePicture& p2, bool bVerCat)就是把2幅圖片的數(shù)據(jù)連接,合在一起,void Frame()修改里面的數(shù)據(jù)加上邊框,void Print(std::ostream& os) const遍歷字符串?dāng)?shù)組輸出。


            根據(jù)上面的設(shè)計(jì)和實(shí)現(xiàn),應(yīng)該已經(jīng)滿足我們這個(gè)題目的要求了。
            但是客戶的需求是多變的,現(xiàn)在客戶又有一個(gè)新的需求,要求把一幅圖片去掉邊框。
            另外客戶覺得我們這個(gè)圖片類的性能太差了,每次加框或是合成圖片都要大量的內(nèi)存拷貝。

            這時(shí)我們傻眼了,該死的客戶,根據(jù)我們上面的設(shè)計(jì),根本不支持這些新功能,因?yàn)槲覀兇鎯?chǔ)的是圖像的內(nèi)部的字符串?dāng)?shù)據(jù),根本不知道它是不是加框過的,另外我們的圖像數(shù)據(jù)本身就是不支持共享的。

             

            接下來我們就要重新考慮設(shè)計(jì)了,如何讓我們的圖像對(duì)象支持UnFrame(去邊框)操作,關(guān)鍵是要建立我們的圖像類型層次,這樣就可以判斷是否是加框的類對(duì)象,于是有了如下的類層次:
            //圖象接口基類
            class CPic_Base
            {};

            //字符串圖像類
            class CPic_String: public CPic_Base
            {};

            //加框圖像類
            class CPic_Frame: public CPic_Base
            {}

            //縱聯(lián)接圖像類
            class CPic_VCat: public CPic_Base
            {};

            //橫聯(lián)接圖像類
            class CPic_HCat: public CPic_Base
            {};

            然后我們考慮如何共享圖像數(shù)據(jù),這就要用到智能指針了,智能指針在C++里一般有2種實(shí)現(xiàn),一種是STL 里的auto_ptr,還有一種就是基于引用計(jì)數(shù)。auto_ptr的本質(zhì)是擁有關(guān)系,也就是你擁有了這對(duì)象后,別人就不能擁有了,所以這里不符合我們的要求。引用計(jì)數(shù)是個(gè)好東西,對(duì)于共享對(duì)象特別有用,COM里的IUnknow接口就是基于這個(gè)技術(shù)的,還有很多腳本語言里變量自動(dòng)銷毀,實(shí)際上都是基于引用計(jì)數(shù)的技術(shù)。這里分享一個(gè)基于引用計(jì)數(shù)的智能指針類。

            class CRefCountBase
            {
            public:
                CRefCountBase()
                {
                    m_nRefCount 
            = 0;
                }

                
            int GetRefCount() const
                {
                    
            return m_nRefCount;
                }

                
            int AddRefCount()
                {
                    
            return ++m_nRefCount;
                }

                
            int SubRefCount()
                {
                    
            return --m_nRefCount;
                }

                
            void ResetRefCount()
                {
                    m_nRefCount 
            = 0;
                }

            private:
                
            int    m_nRefCount;
            };

            template
            <typename T>
            class CRefPtr
            {
            public:
                T
            * operator->() const
                {
                    
            return m_pRawObj;
                }

                T
            & operator()() const
                {
                    
            return *m_pRawObj;
                }

                T
            & operator*() const
                {
                    
            return *m_pRawObj;
                }

                T
            * GetPtr() const
                {
                    
            return m_pRawObj;
                }

                
            bool IsNull() const
                {
                    
            return m_pRawObj == NULL;
                }

                CRefPtr()
                {
                    m_pRawObj 
            = NULL;
                }

                CRefPtr(T
            * p)
                {
                    m_pRawObj 
            = p;
                    
            if(p != NULL)
                    {
                        p
            ->AddRefCount();
                    }
                }

                CRefPtr(
            const CRefPtr& ref)
                {
                    m_pRawObj 
            = ref.m_pRawObj;
                    
            if(m_pRawObj != NULL)
                    {
                        m_pRawObj
            ->AddRefCount();
                    }
                }

                
            ~CRefPtr()
                {
                    
            if(m_pRawObj != NULL && m_pRawObj->SubRefCount() == 0)
                    {
                        delete m_pRawObj;
                    }
                }

                CRefPtr
            & operator = (const CRefPtr& ref)
                {
                    
            if(this != &ref)
                    {
                        
            if(m_pRawObj != NULL
                            
            && m_pRawObj->SubRefCount() == 0)
                        {
                            delete m_pRawObj;
                        }

                        m_pRawObj 
            = ref.m_pRawObj;

                        
            if(m_pRawObj != NULL)
                        {
                            m_pRawObj
            ->AddRefCount();
                        }
                    }

                    
            return *this;
                }

                
            bool operator == (const CRefPtr& refconst
                {
                    
            return m_pRawObj == ref.m_pRawObj;
                }

                CRefPtr
            <T> Copy()
                {
                    
            if(m_pRawObj != NULL)
                    {
                        T
            * p = new T(*m_pRawObj);
                        p
            ->ResetRefCount();

                        
            return p;
                    }
                    
            else
                    {
                        
            return NULL;
                    }
                }

            private:
                T
            * m_pRawObj;
            };


            這樣使用這個(gè)類:

            class A: public CRefCountBase
            {
            Public:
                Void fun1();
            };

            CRefPtr
            <A> p = new A;
            p
            ->fun1();


            重新設(shè)計(jì)我們的CPic_Base,

            class CPic_Base: public CRefCountBase
            {
            public:
                
            virtual ~CPic_Base() {}

                
            //打印輸出圖像
                void Print(std::ostream& os) const;

                
            //返回圖像寬度
                virtual int GetWidth() const = 0;

                
            //返回圖像高度
                virtual int GetHeight() const = 0;

                
            //返回某行的圖像字符串?dāng)?shù)據(jù)
                virtual std::string GetLineData(int nLineIndex) const = 0;

                
            //返回去掉邊框的對(duì)象
                virtual CRefPtr<CPic_Base> GetUnFrame() const { return NULL; }
            };


            這里Print方法實(shí)現(xiàn)就很簡(jiǎn)單了:

            void CPic_Base::Print(std::ostream& os) const
            {
                
            for(int i=0; i<GetHeight(); ++i)
                {
                    os 
            << GetLineData(i);
                    os 
            << "\n";
                } 
            }


            然后考慮實(shí)現(xiàn)CPic_String

            class CPic_String: public CPic_Base
            {
            public:
                CPic_String(
            char* p[], int nCount);

                
            virtual int GetWidth() const;
                
            virtual int GetHeight() const;
                
            virtual std::string GetLineData(int nLineIndex) const;


            protected:
                std::vector
            <std::string> m_arData;
            };


            這個(gè)類里存儲(chǔ)真正的字符串圖像數(shù)據(jù),里面方法的實(shí)現(xiàn)也很簡(jiǎn)單,和最開始的的第一種實(shí)現(xiàn)類似,就不詳寫了。

            再考慮實(shí)現(xiàn)CPic_Frame

            class CPic_Frame: public CPic_Base
            {
            public:
                CPic_Frame(CRefPtr
            <CPic_Base>& pic);

                
            virtual int GetWidth() const;
                
            virtual int GetHeight() const;
                
            virtual std::string GetLineData(int nLineIndex) const

                
            virtual CRefPtr<CPic_Base> GetUnFrame() const { return m_pic; }

            protected:
                CRefPtr
            <CPic_Base> m_pic;
            };


            可以看到這里我們引用了一個(gè)其他的圖像數(shù)據(jù),而不是真正存儲(chǔ)這些數(shù)據(jù),方法實(shí)現(xiàn)也很簡(jiǎn)單, 主要依賴于m_pic所指向的圖像類,同時(shí)m_pic是個(gè)基于引用計(jì)數(shù)的智能指針, 所以賦值時(shí)也沒有內(nèi)存拷貝, 注意GetUnFrame這個(gè)方法只有這里返回非NULL,表示只有這種對(duì)象支持去邊框。

            CPic_Frame::CPic_Frame(CRefPtr<CPic_Base>& pic)
            : m_pic(pic)
            {
                _ASSERTE(
            !m_pic.IsNull());
            }

            int CPic_Frame::GetWidth() const
            {
                
            return m_pic->GetWidth() + 2;
            }

            int CPic_Frame::GetHeight() const
            {
                
            return m_pic->GetHeight() + 2;
            }

            string CPic_Frame::GetLineData(int nLineIndex) const
            {
                
            int nWidth = GetWidth();
                
            int nHeight = GetHeight();

                _ASSERTE(nLineIndex 
            < nHeight && nLineIndex >= 0); 

                
            if(nLineIndex == 0 //first line and last line
                    || nLineIndex == nHeight - 1)
                {
                    
            int nPadding = nWidth - 2;
                    
            return string("+"+ string(nPadding, '-'+ string("+");
                }
                
            else
                {
                    
            return string("|"+ m_pic->GetLineData(nLineIndex - 1+ string("|");
                }
            }

            再考慮實(shí)現(xiàn)CPic_VCat

            class CPic_VCat: public CPic_Base
            {
            public:
                CPic_VCat(CRefPtr
            <CPic_Base>& pic1, CRefPtr<CPic_Base>& pic2);

                
            virtual int GetWidth() const;
                
            virtual int GetHeight() const;
                
            virtual std::string GetLineData(int nLineIndex) const;

            protected:
                CRefPtr
            <CPic_Base> m_pic1;
                CRefPtr
            <CPic_Base> m_pic2;
            };

            他里面存儲(chǔ)了上下2個(gè)圖像對(duì)象,方法實(shí)現(xiàn)是也不復(fù)雜,就不具體寫了。

            另外CPic_HCat也是類似:

            class CPic_HCat: public CPic_Base
            {
            public:
                CPic_HCat(CRefPtr
            <CPic_Base>& pic1, CRefPtr<CPic_Base>& pic2);

                
            virtual int GetWidth() const;
                
            virtual int GetHeight() const;
                
            virtual std::string GetLineData(int nLineIndex) const;

            protected:
                CRefPtr
            <CPic_Base> m_pic1;
                CRefPtr
            <CPic_Base> m_pic2;
            };


            有了上面的實(shí)現(xiàn),現(xiàn)在我們可以這么實(shí)現(xiàn)我們需要的功能了:

            Int main()
            {
                
            char* init1[] = {"Paris""in the""Spring"};
                CRefPtr
            <CPic_Base> p1 = new CPic_String(init, 3); 

                CRefPtr
            <CPic_Base> p2 = new CPic_Frame(p1);

                CRefPtr
            <CPic_Base> p3 = new CPic_VCat(p1, p2);

                P3
            ->Print(cout);
                CRefPtr
            <CPic_Base> p4 = p2->GetUnFrame();
            }


            這時(shí)我們發(fā)現(xiàn)這樣對(duì)于客戶調(diào)用很不友好,因?yàn)槲覀儍?nèi)部實(shí)現(xiàn)的類層次都暴露給客戶了,而這些信息對(duì)客戶來說應(yīng)該都是透明的,我們應(yīng)該再封裝一個(gè)更簡(jiǎn)單的界面類給客戶。

            于是有了如下的設(shè)計(jì),其實(shí)接口類似我們的第一種實(shí)現(xiàn)。

            class CPicture
            {
            public:
                CPicture(
            char* p[], int nCount);
                CPicture(CPicture
            & p1, CPicture& p2, bool bVerCat);

                
            void Frame();
                
            bool UnFrame();

                friend std::ostream
            & operator << (std::ostream& os, const CPicture& pic);

            protected:
                CRefPtr
            <CPic_Base> m_pic;
            };

            std::ostream
            & operator << (std::ostream& os, const CPicture& pic);


            這樣對(duì)客戶來說他們只需要和CPicture打交道,根本不用關(guān)心內(nèi)部的實(shí)現(xiàn)。
            這個(gè)類的實(shí)現(xiàn)也很簡(jiǎn)單:

            CPicture::CPicture(char* p[], int nCount)
            {
                m_pic 
            = new CPic_String(p, nCount);
            }

            CPicture::CPicture(CPicture
            & pic1, CPicture& pic2, bool bVerCat)
            {
                
            if(!bVerCat)
                {
                    m_pic 
            = new CPic_HCat(pic1.m_pic, pic2.m_pic);
                }
                
            else
                {
                    m_pic 
            = new CPic_VCat(pic1.m_pic, pic2.m_pic);
                }
            }

            void CPicture::Frame()
            {
                m_pic 
            = new CPic_Frame(m_pic);
            }

            bool CPicture::UnFrame()
            {
                CRefPtr
            <CPic_Base> p = m_pic->GetUnFrame();
                
            if(!p.IsNull())
                {
                    m_pic 
            = p;
                }

                
            return !p.IsNull();
            }

            std::ostream
            & operator << (std::ostream& os, const CPicture& pic)
            {
                pic.m_pic
            ->Print(os);
                
            return os;
            }


            下面是我們使用這個(gè)類的代碼:

            char* init1[] = {"Paris""in the""Spring"};
            char* init2[] = {"Hello world""every""thing""is""OK!"};

            int main(int argc, char* argv[])
            {
                CPicture p1(init1, 
            3);
                CPicture p2(init2, 
            5);

                
            //
                std::cout << p1;
                cout 
            <<endl << endl; 

                
            //
                std::cout << p2;
                cout 
            <<endl << endl; 

                
            //
                p2.Frame();
                cout 
            << p2;
                cout 
            <<endl << endl; 

                
            //
                p1.Frame();
                p1.Frame();
                cout 
            << p1;
                cout 
            <<endl << endl;

                
            //
                CPicture pHorCat(p1, p2, false);
                cout 
            << pHorCat;
                cout 
            <<endl << endl; 

                
            //
                CPicture pVerCat(p1, pHorCat, true);
                cout 
            << pVerCat;
                cout 
            <<endl << endl; 

                
            //
                pVerCat.Frame();
                cout 
            << pVerCat;
                cout 
            <<endl << endl; 

                
            //
                pVerCat.Frame();
                cout 
            << pVerCat;
                cout 
            <<endl << endl; 

                
            //
                pVerCat.UnFrame();
                pVerCat.UnFrame();
                cout 
            << pVerCat;
                cout 
            <<endl << endl; 

                system(
            "pause");

                
            return 0;
            }


            可以看到使用起來非常方便和友好,運(yùn)行截圖:


            可以看到使用第二種實(shí)現(xiàn)我們只存儲(chǔ)了一份字符串圖像數(shù)據(jù),同時(shí)有保留了圖像的層次和結(jié)構(gòu)屬性,實(shí)現(xiàn)時(shí)包含了很多設(shè)計(jì)模式,比如Template, Decorate, Composite, Facade等,簡(jiǎn)單而高效。


            最后我們對(duì)這2種實(shí)現(xiàn)方式作下比較:

            方法1的優(yōu)勢(shì)是數(shù)據(jù)完整,修改一個(gè)對(duì)象時(shí)不會(huì)影響其他對(duì)象,因?yàn)槊總€(gè)對(duì)象都是數(shù)據(jù)的單獨(dú)拷貝。劣勢(shì)是低效,不能體現(xiàn)對(duì)象的結(jié)構(gòu)屬性,我們不知道這個(gè)對(duì)象是加邊框的對(duì)象還是上下合成的對(duì)象。


            方法2的優(yōu)勢(shì)是高效,數(shù)據(jù)共享,同時(shí)有保留有對(duì)象的結(jié)構(gòu)屬性。劣勢(shì)是修改一個(gè)對(duì)像時(shí)會(huì)影響其他的對(duì)象,因?yàn)樗麄兛赡苁枪蚕硗粋€(gè)對(duì)象。實(shí)際上,對(duì)于基于引用計(jì)數(shù)的共享對(duì)象,還有一種叫做Write Copy(寫入時(shí)拷貝)的技術(shù),就是如果你要修改一個(gè)對(duì)象,就自己拷貝一份。同時(shí)引用計(jì)數(shù)技術(shù)還有一個(gè)風(fēng)險(xiǎn)就是循環(huán)引用,比如A引用了B,B也引用了A,這2個(gè)對(duì)象就永遠(yuǎn)沒法釋放了,這也是要謹(jǐn)慎的。

             

            上面完美的解決了我們UnFrame(去邊框)的問題,我們正對(duì)我們使用基于引用計(jì)數(shù)的技術(shù)來完美的構(gòu)造字符串圖像類層次而洋洋得意,但是好景不長(zhǎng)。


            一個(gè)星期后,客戶又找到你提了他的新需求,他想讓你的CPicuture類增加一個(gè)功能,能返回一個(gè)XML格式的字符串來告訴他該對(duì)象的構(gòu)造過程。
            比如
            +-------+
            |Paris   |
            |in the |
            |Spring |
            +-------+
            返回的XML串是
            < CPic_Frame >
            <CPic_String> Paris in the Spring </CPic_String>
            </ CPic_Frame >

            +-------+Paris
            |Paris  |in the
            |in the |Spring
            |Spring |
            +-------+

            返回的XML串是:

            < CPic_HCat >
            < CPic_Frame >
            <CPic_String> Paris in the Spring </CPic_String>
            </ CPic_Frame >
            <CPic_String> Paris in the Spring </CPic_String>
            </ CPic_HCat >


            +-------+Paris
            |Paris  |in the
            |in the |Spring
            |Spring |
            +-------+
            Paris
            in the
            Spring

            返回的XML串是:

            <CPic_VCat>
            < CPic_HCat >
            < CPic_Frame >
            <CPic_String> Paris in the Spring </CPic_String>
            </ CPic_Frame >
            <CPic_String> Paris in the Spring </CPic_String>
            </ CPic_HCat >
            <CPic_String> Paris in the Spring </CPic_String>
            </CPic_VCat>

             

            你不禁抱怨道,該死的客戶,上次已經(jīng)因?yàn)橐С諹nFrame功能而讓我改變了最初的設(shè)計(jì),如果沒有客戶的新需求,開發(fā)該是一件多么美好的事情。

            但是抱怨歸抱怨,客戶就是上帝,你還是只能硬這頭皮把事情做完。
            那現(xiàn)在讓我們來考慮如果實(shí)現(xiàn)這一功能。

            一開始想到的當(dāng)然是在我們的CPic_Base基類中增加一個(gè)接口,比如
            String GetStructXMLString();

            但是面向?qū)ο竦脑O(shè)計(jì)原則告訴我們,接口不該隨便改動(dòng),實(shí)際上次CPic_Base里為UnFrame而增加的CRefPtr<CPic_Base> GetUnFrame()接口已經(jīng)讓你覺得很不爽,感覺這個(gè)接口和我們的圖像對(duì)象沒有直接關(guān)系。

            那么我們是否考慮可以重構(gòu)CPic_Base接口,讓它能以插件的形式實(shí)現(xiàn)各種功能,也就是說我們的類層次這里是固定的,但是方法卻可以一直增加而不影響原有的代碼。

            這時(shí)我們想到了Visitor模式,它基本上是為我們這類需求而量身定做的。
            對(duì)于Visitor模式的架構(gòu),基本上是固定的,定義個(gè)IPic_Visitor

            class IPic_Visitor
            {
            public:
                
            virtual void VisitPicString(CPic_String& pic) {};
                
            virtual void VisitPicFrame(CPic_Frame& pic) {} ;
                
            virtual void VisitPicVCat(CPic_VCat& pic) {};
                
            virtual void VisitPicHCat(CPic_HCat& pic) {};

                
            virtual ~IPic_Visitor() {}
            };


            在我們的CPic_Base基類里增加一個(gè)Accept接口virtual void Accept(IPic_Visitor& visitor) = 0;
            這樣圖像對(duì)象就可以讓各種類型的Visitor訪問了,各個(gè)圖像類的實(shí)現(xiàn)也很簡(jiǎn)單:

            void CPic_String::Accept(IPic_Visitor& visitor)
            {
                visitor.VisitPicString(
            *this);
            }
            void CPic_Frame::Accept(IPic_Visitor& visitor)
            {
                visitor.VisitPicFrame(
            *this);
            }
            void CPic_VCat::Accept(IPic_Visitor& visitor)
            {
                visitor.VisitPicVCat(
            *this);
            }
            void CPic_HCat::Accept(IPic_Visitor& visitor)
            {
                visitor.VisitPicHCat(
            *this);
            }


            好了,現(xiàn)在我們用一個(gè)新Visitor來改寫我們?cè)瓉淼腢nFrame功能,

            class CUnFrameVisitor: public IPic_Visitor
            {
            public:
                
            virtual void VisitPicFrame(CPic_Frame& pic);

            public:
                CRefPtr
            <CPic_Base> GetUnFrameResult();

            protected:
                CRefPtr
            <CPic_Base> m_picRet;
            };

            因?yàn)閂isitor方法都是沒有返回值,參數(shù)也是固定的,所以一般都是通過在Visitor里保存成員變量和返回接口來實(shí)現(xiàn)返回值的。
            這樣實(shí)現(xiàn)就很簡(jiǎn)單了:

            void CUnFrameVisitor::VisitPicFrame(CPic_Frame& pic)
            {
                m_picRet 
            = pic.m_pic;
            }

            CRefPtr
            <CPic_Base> CUnFrameVisitor::GetUnFrameResult()
            {
                
            return m_picRet;
            }

             

            可以看到只有訪問 CPic_Frame才有非空的返回值;其他都是用默認(rèn)的空方法,最終返回的也就空對(duì)象。

            這樣我們?cè)谧罱K暴露的CPicture里實(shí)現(xiàn)UnFrame也就很簡(jiǎn)單了:

            bool CPicture::UnFrame()
            {
                CUnFrameVisitor vistor;
                m_pic
            ->Accept(vistor);

                CRefPtr
            <CPic_Base> pRet = vistor.GetUnFrameResult();
                
            if(!pRet.IsNull())
                {
                    m_pic 
            = pRet;
                }

                
            return !pRet.IsNull();
            }


            接下來我們考慮如何實(shí)現(xiàn)客戶的要求返回XML串的需求,實(shí)際上我們前面的Visitor模式已經(jīng)為我們準(zhǔn)備好了條件,我們只需要新增加一個(gè)Visitor

            class CStructXMLVisitor: public IPic_Visitor
            {
            public:
                
            virtual void VisitPicString(CPic_String& pic);
                
            virtual void VisitPicFrame(CPic_Frame& pic);
                
            virtual void VisitPicVCat(CPic_VCat& pic);
                
            virtual void VisitPicHCat(CPic_HCat& pic);

            public:
                std::
            string GetStructXMLString() { return m_strStructXML;}

            protected:
                std::
            string m_strStructXML;
            };


            實(shí)現(xiàn)也不復(fù)雜:

            void CStructXMLVisitor::VisitPicString(CPic_String& pic)
            {
                m_strStructXML 
            = "<CPic_String>";
                
            int nHeight = pic.GetHeight();
                
            for(int i=0;i<nHeight; ++i)
                {
                    m_strStructXML 
            += pic.GetLineData(i);
                }
                m_strStructXML 
            += "</CPic_String>";
            }

            void CStructXMLVisitor::VisitPicFrame(CPic_Frame& pic)
            {
                CStructXMLVisitor v;
                pic.m_pic
            ->Accept(v);
                m_strStructXML 
            = "<CPic_Frame>";
                m_strStructXML 
            += v.GetStructXMLString();
                m_strStructXML 
            += "</CPic_Frame>";
            }

            void CStructXMLVisitor::VisitPicVCat(CPic_VCat& pic)
            {
                m_strStructXML 
            = "<CPic_VCat>";
                CStructXMLVisitor v1;
                pic.m_pic1
            ->Accept(v1);
                m_strStructXML 
            += v1.GetStructXMLString();

                CStructXMLVisitor v2;
                pic.m_pic2
            ->Accept(v2);
                m_strStructXML 
            += v2.GetStructXMLString();

                m_strStructXML 
            += "</CPic_VCat>";
            }

            void CStructXMLVisitor::VisitPicHCat(CPic_HCat& pic)
            {
                m_strStructXML 
            = "<CPic_HCat>";
                CStructXMLVisitor v1;
                pic.m_pic1
            ->Accept(v1);
                m_strStructXML 
            += v1.GetStructXMLString();

                CStructXMLVisitor v2;
                pic.m_pic2
            ->Accept(v2);
                m_strStructXML 
            += v2.GetStructXMLString();

                m_strStructXML 
            += "</CPic_HCat>";
            }


            然后我們?cè)谖覀兊腃Picture界面里增加一個(gè)GetStructXMLString方法,實(shí)現(xiàn)也很簡(jiǎn)單:

            std::string CPicture::GetStructXMLString()
            {
                CStructXMLVisitor v;
                m_pic
            ->Accept(v);
                
            return v.GetStructXMLString();
            }


            可以看到,改用新的設(shè)計(jì)之后,以后我們?cè)儆惺裁葱滦枨螅灰苯釉黾右粋€(gè)Visitor就好了, 所以說設(shè)計(jì)不是一層不變的,要根據(jù)需求不停的重構(gòu)。
            最后貼一下類圖,外部只要和CPicture打交道就可以了:


             

            源代碼下載:  ConsolePicture_1.rar

                           ConsolePicture_2.rar

            注:(1)該題引自《C++沉思錄》
                  (2)C++11里已經(jīng)有基于引用計(jì)數(shù)的智能指針share_ptr, 所以以后就不用自己寫了,循環(huán)引用的問題也可以通過weak_ptr解決.
            posted on 2012-06-12 09:31 Richard Wei 閱讀(5467) 評(píng)論(10)  編輯 收藏 引用 所屬分類: 設(shè)計(jì)模式

            FeedBack:
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 10:08 | sharkcc
            代碼太多,如果考驗(yàn)設(shè)計(jì)能力也貼2張類圖上來看看。
            是采用裝飾模式嗎  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 10:17 | Richard Wei
            @sharkcc
            涉及到很多模式, Template, Decorate, Composite, faced, Visitor等
            嫌文字太多可以直接下載最后的源代碼看, 相信會(huì)有所收獲。  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 10:26 | 小明
            最討厭堆砌設(shè)計(jì)模式,把簡(jiǎn)單的問題復(fù)雜化  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 10:38 | Richard Wei
            @小明
            為模式而模式當(dāng)然不對(duì),但是很多時(shí)候你會(huì)不自覺地用到設(shè)計(jì)模式,因?yàn)橥悊栴}已經(jīng)有了一種被大家證明是最合理的方案(模式)來解決。
            上面的問題你有更好的解決方案嗎?
              回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題[未登錄]
            2012-06-12 11:06 | Simon
            樓主的代碼比文字厲害多了  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 11:12 | Richard Wei
            @Simon
            呵呵, 夸我還是罵我?  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-12 16:02 | 1111
            好像是C++沉思錄里的例子?  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-13 12:51 | leolai
            首先,題目沒有明確給出以后的變化點(diǎn),你只看題目就想去窮盡封裝所有的變化,這在具體設(shè)計(jì)中是極其不現(xiàn)實(shí)的,封裝變化通常是在變化出現(xiàn)時(shí),而更好的手段是刺激變化的時(shí)機(jī),于是就有測(cè)試驅(qū)動(dòng)開發(fā),而不是想法預(yù)測(cè)整個(gè)開發(fā)中的變化,所以就題目而言,第一種寫法比你后面一堆的代碼好,現(xiàn)階段而言,只要適用就行,當(dāng)然如果這些變化能明顯觀察到,后面的做法無可厚非  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-13 13:06 | Richard Wei
            @leolai
            同意。
            一般來說,除非某些設(shè)計(jì)模式你現(xiàn)在確實(shí)適合使用,或是你能預(yù)測(cè)到今后可能的變化,你才應(yīng)該使用該模式。
            否則還是只要滿足當(dāng)前的需要就夠了,等確實(shí)有新需求時(shí)再考慮重構(gòu)你現(xiàn)有的代碼。比如上面有的 去邊框(unframe), 用XML格式打印圖片的組成結(jié)構(gòu) 等,都是新需求。  回復(fù)  更多評(píng)論
              
            # re: 一道考驗(yàn)?zāi)阍O(shè)計(jì)能力的C++編程題
            2012-06-20 11:07 | 畢達(dá)哥拉斯半圓
            不錯(cuò)  回復(fù)  更多評(píng)論
              
            99久久亚洲综合精品成人| 一本久道久久综合狠狠爱| 国产精品久久影院| 国产日韩久久免费影院| 亚洲精品视频久久久| 久久精品国产99国产精品导航| 久久婷婷五月综合色奶水99啪| 久久99精品久久久久久动态图| 久久91这里精品国产2020| 久久久无码精品亚洲日韩京东传媒| 亚洲国产精品无码成人片久久| 狠狠色丁香婷婷久久综合不卡| 人妻无码精品久久亚瑟影视| 久久久亚洲欧洲日产国码二区| 日韩电影久久久被窝网| 国产精品久久久久无码av| 久久精品久久久久观看99水蜜桃| 精品免费久久久久久久| 国产精品成人久久久| 国产精品久久久久乳精品爆| 久久久久AV综合网成人 | 伊人久久综合成人网| 九九久久精品国产| 国产精品美女久久久| 国产成人无码精品久久久性色| 久久久久国产一区二区三区| 久久国产精品一区二区| 久久综合亚洲欧美成人| 久久婷婷五月综合色奶水99啪| 四虎影视久久久免费观看| 国产视频久久| 国产福利电影一区二区三区久久老子无码午夜伦不 | 好久久免费视频高清| 精品久久久噜噜噜久久久| 久久亚洲精品无码AV红樱桃| 97精品国产97久久久久久免费| 伊人 久久 精品| 精品人妻伦九区久久AAA片69| 97久久国产综合精品女不卡| 成人久久免费网站| 国产精品99久久免费观看|