• C++程序设计方法6:算法横向拆分


    例子1:负载监视器,如何在一个程序中实现对这些不同条件的适应呢?
    
    int main()
    {
        WindowDisplay display;
        Monitor monitor(&display);
        while(running())
        {
            monitor.getLoad();
            monitor.getTotalMemory();
            monitor.getUseMemory();
            monitor.getNetworkLatency();
    
            monitor.show();
            sleep(1000);
        }
    
    }
    
    enum MonitorType {Win32,Win64,Ganglia};
     
    MonitorType type = Ganglia;
    
    float Monitor::getLoad()
    {
        switch(type)
        {
            case Win32:
            //get system load via win32 APIs
            return load;
            case Win64:
            //get system load via Win64 APIs
            return load;
            case Ganglia:
            //get system load via ganglia interface
            return load;
        }
    }
    改进:使用模板方法;
    class Monitor
    {
    public:
        virtual void getLoad() = 0;
        virtual void getTotalMemory() = 0;
        virtual void getUseMemory() = 0;
        virtual void getNetworkLatency() = 0;
    
        Monitor(Display *display);
        virtual ~Monitor();
        void show();
    protected:
        float load,latency;
        long totalMemory,usedMemory;
        Display *m_display;
    };
    
    void Monitor::show()
    {
        m_display->show(load,totalMemory,usedMemory,latency);
    }
    
    class MonitorImpl1:public Monitor
    {
    public:
        void getLoad();
        void getTotalMemory();
        void getUsedMemory();
        void getNetworkLatency();
    };
    
    void MonitorImpl1::getLoad()
    {
        //load = ...;
    }
    
    void MonitorImpl1::getTotalMemory()
    {
        //totalMemory = ...;
    }
    
    
    存在问题:
        如果几组函数接口的实现互相独立,分别有N,M,K种实现方法,那么,实现子类的个数将是N*M*K种,
        这样方法无非不是最好的;
    
        分析:
            存在两种不同层面的变化,应该有所区分:
            在实现层面上:对于每个功能,存在多种实现方法;
            1.相对于基类是可变的,每种变化对应于一个派生类
            2.这种变化表现在编译器,是一种相对静态的可变
            在组织层面上:“大”类的功能由一系列子功能构成
            1·子功能之间是互相独立的,应当将这些子功能拆分到不同的“小”中
            2.组合是自由变化的,动态的,可变的,通过实现子功能的“小”类对象的组合来完成
            3.这种变化表现在运行期,是一种更加动态的可变;
        隔离不同层面的“变”:
            1.静态的可变用继承;
            2.动态的可变用组合;
        单一责任:
            1.单一责任原则
            类的功能应该是内聚的,一个类只承担一项功能;
            表现为:修改、派生一个类只应该有一个理由,只能够由单个变化因素引起;
            2.将多个不同的功能交由一个类来实现,违反了单一责任原则;
            当一个功能需要变化时,不得不修改或者派生新的实现类;
            把这两个层次的“变”分离开
            剥离出新的接口
            每个功能(算法)的实现定义为一个接口(称为策略)
            与接口的不同实现组成一个策略类的体系;
        把这两种层次的“变”分离开
            用组合替代继承
            用功能(算法)接口之间的组合来实现功能(算法)之间的组合
        再看看问题:
            剥离新的接口
            由三个策略接口分别定义不同的功能,每个策略接口有一系列不同的实现;
            用组合替代继承
            Monitor类中保存一组“策略”接口类的实例,这些实例可以自由组合和动态
            替换;
    class LoadStrategy
    {
    public:
        virtual float getLoad() = 0;
    };
    
    class LoadStrategyImpl1:public LoadStrategy
    {
    public:
        float getLoad()
        {
        //get load here...
        return load;
        }
    };
    
    class LoadStrategyImpl2: public LoadStrategy
    {
        public:
            float getLoad()
            {
                //get load here...
                return load;
            }
    };
    
    class MemoryStrategy
    {
    public:
        virtual long getTotal() = 0;
        virtual long getUsed() = 0;
    };
    
    class MemoryStrategyImpl1:public MemoryStrategy
    {
    public:
        long getTotal()
        {
            //get total memory here...
            return total;
        }
        long getUsed()
        {
            //get used memory here...
            return used;
        }
    };
    
    class MemoryStrategyImpl2:public MemoryStrategy
    {
    //
    }
    
    class Monitor
    {
    public:
        Monitor(LoadStrategy *loadStrategy,MemoryStrategy *memStrategy,
        LatencyStrategy *latencyStrategy,Display *display);
        void getLoad();
        void getTotalMemory();
        void getUsedMemory();
        void getNetworkLatency();
        void show();
    private:
        LoadStrategy *m_loadStrategy;
        MemoryStrategy *m_memStrategy;
        LatencyStrategy *m_latencyStrategy;
        float load,latency;
        long totalMemory,usedMemory;
        Display *m_display;
    };
    
    //
    Monitor::Monitor(LoadStrategy *loadStrategy,MemoryStrategy *memStrategy
    ,LatencyStrategy *latencyStrategy,Display *display):
    m_loadStrategy(loadStrategy),m_memStrategy(memStrategy),
    m_latencyStrategy(latencyStrategy),m_display(display),
    load(0.0),latency(0.0),totalMemory(0),usedMemory(0)
    {
    
    }
    
    void Monitor::show()
    {
        m_display->show(load,totalMemory,usedMemory,latency);
    }
    
    代码实现:
    void Monitor::getLoad()
    {
        load = m_loadStrategy->getLoad();
    }
    
    void Monitor::getTotalMemory()
    {
        totalMemory = m_memStrategy->getTotal();
    }
    
    void Monitor::getUsedMemory()
    {
        useMemory = m_memStrategy->getUsed();
    }
    
    void Monitor::getNetworkLatency()
    {
        latency = m_latencyStrategy->getLatency();
    }
    
    int main(int argc, char *argv[])
    {
        GangliaLoadStrategy loadStrategy;
        WinMemoryStrategy memoryStrategy;
        pingLatencyStrategy latencyStrategy;
    
        WindowsDisplay display;
        Monitor monitor(&loadStrategy,&memoryStrategy,&latencyStrategy,&display);
        while(running())
        {
            monitor.getLoad();
            monitor.getTotalMemory();
            monitor.getUsedMemory();
            monitor.getNetworkLatency();
    
            monitor.show();
            sleep(10000);
        }
    }
    
    //灵活性:运行期
    class Monitor
    {
    public:
        //...
        void setLoadStrategy(LoadStrategy *loadStrategy);
        void setMemoryStrategy(MemoryStrategy *memoryStrategy);
        void setLatencyStrategy(LoadStrategy *latencyStrategy);
    };
    
    int main()
    {
        Monitor monitor(//);
        //...
        LoadStrategyImpl2 newLoadStrategy;
        monitor.setLoadStrategy(&newLoadStrategy);
        monitor.getLoad();
        //...
    }
    
    //委托与接口的进一步分解
    //结果的显示
    class Monitor
    {
    public:
        //...
        void show();
    protected:
        float load,latency;
        long totalMemory,usedMemory;
        Display* m_display;
    };
    
    void Monitor::show()
    {
        m_display->show(load,totalMemory,usedMemory,latency);
    }
    
    执行过程:
    Monitor将“显示”的任务“委托”给了Display,由Display真正完成显示的工作;
    委托模式:Delegation,Wrapper,Helper...
    int mian()
    {
        //...
        monitor.show();
        //调用代码:
        /*
        void Monitor::show()
        {
            m_display->show(load,totalMemory,usedMemory,latency);
        }
        //区分是WindowDisplay还是ConsoleDisplay
        void WindowDisplay::show();
        void ConsoleDisplay::show();
        */
    
    //}
    //对于guidisplay的各个类,大量的重复代码(代码冗余,维护难度加大)
    //解决办法:分析“变”与“不变”
    //任何绘图的基础都时画点,画法不一样;
    //不同GUI,实现画点的接口API不同;
    //把变与不变分离开来,抽象出新的接口;
    //分离(抽象)新的接口;
    
    
    
    /*
    分离出新的接口:
    Bridge模式
    把抽象部分与实现部分分离,使他们可以独立变化
    class Display
    {
    public:
        virtual void show(float load,long totalMemory,long usedMemory,
        float latency) = 0;
        virtual ~Display()  {}
    };
    
    class ConsoleDisplay:public Display
    {
    public:
        void show(float load,long totalMemory,long usedMemory,float latency)
        {
            cout <<"load=" << load << endl;
            cout << "totalMemory=" << totalMemory << endl;
            cout << "usedMemory=" << usedMemory << endl;
            cout << "latency=" << latency << endl;
        }
    };
    新的接口
    class GUIDisplay:public Display
    {
    public:
        //virtual void show(float load,long totalMemory,long usedMemory,
        float latency) = 0;
        GUIDisplay(GUIDisplayImpl* impl):m_impl(impl) {}
        ~GUIDisplay();
        GUIDisplay(const GUIDisplay &d);
        GUIDisplay& operator=(const GUIDisplay &d);
    
    protected:
        void drawLine(int a,int b, int c, int d);
        void drawRect(int a, int b, int c, int d);
        //...
    private:
        void drawPoint(int x, int y);
        void drawText(int a, int b,string text);
        GUIDisplayImpl* m_impl;
    }
    
    //
    //新的接口定义与使用
    class GUIDisplayImpl
    {
     int use;
     friend class GUIDisplay;
    public:
        GUIDisplayImpl():use(1){}
        virtual void drawPoint(int x, int y) = 0;
        virtual void drawText(int a , int b, string text) = 0;
    };
    
    void GUIDisplay::drawPoint(int x, int y)
    {
        m_impl->drawPoint(x,y);
    }
    
    void GUIDisplay::drawText(int x, int y, string text)
    {
        m_impl->drawText(x,y,text);
    }
    
    实现新的接口
    class WindowDisplayImpl:public GUIDisplayImpl
    {
    public:
        WindowDisplayImpl() {//init it here...}
        ~WindowDisplayImpl();
        void drawPoint(int x,int y);
        void drawText(int x, int y, string text);
    }
    
    void WindowDisplayImpl::drawPoint(int x, int y)
    {
        SetPixel(hdc,x,y,foreColor);
    }
    
    void windowsDisplayImpl::drawText(int x,int y, string text)
    {
        TextOut(hdc,x,y,text.c_str(),text.len());
    }
    
    class XWinDisplayImpl:public GUIDisplayImpl
    {
    public:
        XWinDisplayImpl(){//init it here...}
        ~XWinDisplayImpl() {}
        void drawPoint(int x, int y);
        void drawText(int x, int y,string text);
    }
    
    void XWinDisplayImpl::drawPoint(int x,int y)
    {
        XDrawPoint(display,win,gc,x,y);
    }
    
    void XWinDisplayImpl::drawText(int x,int y,string text)
    {
        XDrawString(display,win,gc,x,y,text,text.len());
    }
    
    void GUIDisplay::drawLine(int x1,int y1, int x2, int y2)
    {
        for(int x =x1;x < x2;x++)
        {
            y = x1 + (x-x1)*(y2-y1)/(x2-x1);
            drawPoint(x,y);
        }
    }
    
    void GUIDisplay::drawRect(int x1,int y1,int x2, int y2)
    {
        drawLine(x1,y1,x2,y1);
        drawLine(x2,y1,x2,y2);
        drawLine(x1,y1,x1,y2);
        drawLine(x1,y2,x1,y1);
    }
    
    另外一个层面的可变部分:使用继承实现GUIDisplay
    class Layout1:public GUIDisplay
    {
    public:
        Layout1(GUIDisplayImpl *impl):GUIDisplay(impl){}
        void show(float load,long totalMemory,long usedMemory,float latency);
    }
    
    void Layout1::show(float load,long totalMemory,long usedMemory,float latency)
    {
        drawRect(10,10,300,20);
        drawText(10,10,float2str(load));
        //.....
    }
    
    
    class Layout2:public GUIDisplay
    {
    public:
        Layout2(GUIDisplayImpl *impl):GUIDisplay(impl){}
        void show(float load,long totalMemory,long usedMemory,float latency);
    }
    
    void Layout2::show(float load,long totalMemory,long usedMemory,float latency)
    {
        drawRect(10,10,30,300);
        int miny = load*290/100 + 10;
        for(int y = 300; y > miny; y-=3)
        {
        }
    }
    怕什么真理无穷,进一寸有一寸的欢喜。---胡适
  • 相关阅读:
    解决 DBMS_AW_EXP: BIN$*****==$0 not AW$
    物化视图(materialized view) 实现数据迁移、数据定时同步
    Mysql exists 与 in
    ORACLE DATAGUARD 进程
    ORACLE DATAGUARD SWITCHOVER 步骤
    Oracle Dataguard failover 操作步骤
    Python 包管理(PYPA)
    Emacs Org-mode 4 超连接
    Emacs Org-mode 3 表格
    ycmd for emacs 代码自动补全
  • 原文地址:https://www.cnblogs.com/hujianglang/p/6706735.html
Copyright © 2020-2023  润新知