美文网首页
C++ ISP Interface Segregation Pr

C++ ISP Interface Segregation Pr

作者: FredricZhu | 来源:发表于2024-07-01 21:10 被阅读0次

    本例将care_taker程序拆分为两个单独的care_taker对象,一个是sunlight_care_taker_t, 一个是moisture_care_taker_t。
    本例采用C++的命名空间机制进行了分层。同时采用python的下划线命名法。
    程序的目录结构如下


    图片.png

    完整的代码如下,
    https://gitlab.com/zhuge20100104/cpp_practice/-/tree/master/solid_cpp/02_plant_care_isp?ref_type=heads

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.3)
    
    project(02_plant_care_isp)
    
    set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig/")
    
    set ( CMAKE_CXX_FLAGS "-pthread")
    set(CMAKE_CXX_STANDARD 20)
    add_definitions(-g)
    
    include_directories(
        ${INCLUDE_DIRS}
        ${CMAKE_CURRENT_SOURCE_DIR}/include
    )
    
    LINK_DIRECTORIES(${LINK_DIRS})
    
    file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 
    file( GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/**/**/*.cc)
    
    foreach( main_file ${main_file_list} )
        file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
        string(REPLACE ".cpp" "" file ${filename})
        add_executable(${file}  ${main_file} ${SOURCES})
        target_link_libraries(${file} pthread)
    endforeach( main_file ${main_file_list})
    

    main.cpp

    #include <thread>
    #include <mutex>
    #include "care_taker/moisture_care_taker.h"
    #include "care_taker/sunlight_care_taker.h"
    #include "sensors/moisture_sensor.h"
    #include "sensors/sunlight_sensor.h"
    
    void run() {
        std::mutex sensor_mutex;
        sensors::sunlight_sensor_t sunlight_sensor(std::chrono::seconds(2), sensor_mutex);
        sensors::moisture_sensor_t moisture_sensor(std::chrono::seconds(3), sensor_mutex);
    
        care_taker::sunlight_care_taker_t sunlight_care_taker;
        care_taker::moisture_care_taker_t moisture_care_taker;
        
        moisture_sensor.subscribe(moisture_care_taker);
        sunlight_sensor.subscribe(sunlight_care_taker);
    
        std::thread sunlight_sensor_thread(sunlight_sensor);
        std::thread moisture_sensor_thread(moisture_sensor);
    
        sunlight_sensor_thread.join();
        moisture_sensor_thread.join();
    }
    
    int main(int argc, char* argv[]) {
        run();
        return EXIT_SUCCESS;
    }
    

    care_taker/i_moisture_care_taker.h

    #ifndef _FREDIRC_I_MOISTURE_CARE_TAKER_H_
    #define _FREDIRC_I_MOISTURE_CARE_TAKER_H_
    
    namespace care_taker {
    
    class i_moisture_care_taker_t {
    public:
        virtual ~i_moisture_care_taker_t() = default;
    
        virtual void pour_water() = 0;
        virtual void sprinkle_water() = 0;
    };
    
    } // namespace care_taker
    
    #endif
    

    care_taker/i_sunlight_care_taker.h

    #ifndef _FREDRIC_I_SUNLIGHT_CARE_TAKER_H_
    #define _FREDRIC_I_SUNLIGHT_CARE_TAKER_H_
    
    namespace care_taker { 
    
    class i_sunlight_care_taker_t {
    public:
        ~i_sunlight_care_taker_t() = default;
    
        virtual void open_window_blinds() = 0;
        virtual void close_window_blinds() = 0;
    };
    
    } // namespace care_taker
    #endif
    

    care_taker/moisture_care_taker.h

    #ifndef _FREDIRC_MOISTURE_CARE_TAKER_H_
    #define _FREDIRC_MOISTURE_CARE_TAKER_H_
    #include "care_taker/i_moisture_care_taker.h"
    
    namespace care_taker {
    
    class moisture_care_taker_t: public i_moisture_care_taker_t {
    public:
        void pour_water() override;
        void sprinkle_water() override;
    };
    } // end care_taker
    #endif
    

    care_taker/sunlight_care_taker.h

    #ifndef _FREDRIC_SUNLIGHT_CARE_TAKER_H_
    #define _FREDRIC_SUNLIGHT_CARE_TAKER_H_
    
    #include "care_taker/i_sunlight_care_taker.h"
    
    namespace care_taker { 
    
    class sunlight_care_taker_t: public i_sunlight_care_taker_t {
        bool m_window_blinds_open {true};
        
    public:
        void open_window_blinds() override;
        void close_window_blinds() override;
    };
    
    } // namespace care_taker
    #endif
    

    care_taker/moisture_care_taker.cc

    #include "care_taker/moisture_care_taker.h"
    
    #include <iostream>
    
    namespace care_taker {
    
    void moisture_care_taker_t::pour_water() {
        std::cout << "pouring water on Aloe" << std::endl;
    }
    
    void moisture_care_taker_t::sprinkle_water() {
        std::cout << "sprinkling water on Aloe" << std::endl;
    }
    
    }
    

    care_taker/sunlight_care_taker.cc

    #include "care_taker/sunlight_care_taker.h"
    #include <iostream>
    
    namespace care_taker {
    
    void sunlight_care_taker_t::open_window_blinds() {
        if(!m_window_blinds_open) {
            m_window_blinds_open = true;
            std::cout << "Opened window blinds for Aloe" << std::endl;
        }
    }
    
    void sunlight_care_taker_t::close_window_blinds() {
        if(m_window_blinds_open) {
            m_window_blinds_open = false;
            std::cout << "Closed window blinds for Aloe" << std::endl;
        }
    }
    
    }
    

    sensors/moisture_sensor.h

    #ifndef _FREDRIC_MOISTURE_SENSOR_H_
    #define _FREDRIC_MOISTURE_SENSOR_H_
    #include <chrono>
    #include <mutex>
    #include <set>
    
    #include "care_taker/i_moisture_care_taker.h"
    
    namespace sensors {
    
    class moisture_sensor_t {
        std::chrono::seconds const m_sleep_time;
        std::mutex& m_mutex;
        std::set<care_taker::i_moisture_care_taker_t*> m_care_takers;
        int const m_min = 0;
        int const m_max = 10;
        int const m_threshold = 3;
    
    public:
        moisture_sensor_t(std::chrono::seconds, std::mutex&);
        void subscribe(care_taker::i_moisture_care_taker_t&);
        void operator()();
    
    
    private:
        bool is_air_too_dry();
        bool is_soil_too_dry();
        int get_air_moisture();
        int get_soil_moisture();
    
    };
    
    }
    #endif
    

    sensors/sunlight_sensor.h

    #ifndef _FREDRIC_SUNLIGHT_SENSOR_H_
    #define _FREDRIC_SUNLIGHT_SENSOR_H_
    #include <chrono>
    #include <mutex>
    #include <set>
    #include <optional>
    
    #include "care_taker/i_sunlight_care_taker.h"
    
    namespace sensors {
    
    class sunlight_sensor_t {
        using time_point_t = decltype(std::chrono::system_clock::now());
    
        std::chrono::seconds const m_sleep_time;
    
        std::mutex& m_mutex;
        std::set<care_taker::i_sunlight_care_taker_t*> m_care_takers;
    
        std::optional<time_point_t> m_sunlight_on_from;
        std::optional<time_point_t> m_sunlight_off_from;
    
        int const m_thresold = 2;
        bool m_sensor_on = true;
    
    public:
        sunlight_sensor_t(std::chrono::seconds const, std::mutex&);
        void subscribe(care_taker::i_sunlight_care_taker_t&);
        void operator()();
    
    private:
        void update_state(bool const);
        bool is_too_much_sunlight(bool const);
        bool is_too_little_sunlight(bool const);
        bool is_sunlight() const;
    
    };
    
    } // sensors
    
    #endif
    
    

    sensors/moisture_sensor.cc

    #include "sensors/moisture_sensor.h"
    
    #include <thread>
    #include <random>
    
    namespace sensors {
    
    moisture_sensor_t::moisture_sensor_t(std::chrono::seconds sleep_time, std::mutex& mutex_):
        m_sleep_time(sleep_time), m_mutex(mutex_) {
    
    }
    
    void moisture_sensor_t::subscribe(care_taker::i_moisture_care_taker_t& care_taker) {
        m_care_takers.insert(&care_taker);
    }
    
    void moisture_sensor_t::operator()() {
        for(;;) {
            std::unique_lock<std::mutex> lock(m_mutex);
            if(is_air_too_dry()) {
                for(auto care_taker : m_care_takers) {
                    care_taker->sprinkle_water();
                }
            }
            if(is_soil_too_dry()) {
                for(auto care_taker : m_care_takers) {
                    care_taker->pour_water();
                }
            }
    
            lock.unlock();
            std::this_thread::sleep_for(m_sleep_time);
        }
    }
    
    bool moisture_sensor_t::is_air_too_dry() {
        return get_air_moisture() < m_threshold;
    }
    
    bool moisture_sensor_t::is_soil_too_dry() {
        return get_soil_moisture() < m_threshold;
    }
    
    int moisture_sensor_t::get_air_moisture() {
        static std::mt19937 generator;
        return std::uniform_int_distribution<int>(m_min, m_max)(generator);
    }
    
    int moisture_sensor_t::get_soil_moisture() {
        static std::mt19937 generator;
        return std::uniform_int_distribution<int>(m_min, m_max)(generator);
    }
    
    }
    

    sensors/sunlight_sensor.cc

    #include "sensors/sunlight_sensor.h"
    #include <iostream>
    #include <thread>
    #include <random>
    
    namespace sensors {
    sunlight_sensor_t::sunlight_sensor_t(std::chrono::seconds const sleep_time, std::mutex& mutex_):
        m_sleep_time{sleep_time},
        m_mutex{mutex_}
    {
    
    } 
    
    void sunlight_sensor_t::subscribe(care_taker::i_sunlight_care_taker_t& care_taker) {
        m_care_takers.insert(&care_taker);
    }
        
    void sunlight_sensor_t::operator()() {
        for(;;) {
            std::unique_lock<std::mutex> lock(m_mutex);
            auto const sunlight = is_sunlight();
            update_state(sunlight);
            std::cout << "sun shines: " << std::boolalpha << sunlight << std::endl;
            if(is_too_much_sunlight(sunlight)) {
                for(auto& p: m_care_takers) {
                    p->close_window_blinds();
                }
                m_sensor_on = false;
            } else if(is_too_little_sunlight(sunlight)) {
                for(auto& p: m_care_takers) {
                    p->open_window_blinds();
                }
                m_sensor_on = true;
            }
            lock.unlock();
            std::this_thread::sleep_for(m_sleep_time);
        }
    }
    
    
    void sunlight_sensor_t::update_state(bool const sunlight) {
        auto const current_time = std::chrono::system_clock::now();
    
        if(sunlight && m_sensor_on) {
            m_sunlight_on_from = m_sunlight_on_from? *m_sunlight_on_from: current_time;
            m_sunlight_off_from = std::nullopt;
        } else if(!sunlight) {
            m_sunlight_off_from = m_sunlight_off_from? *m_sunlight_off_from: current_time;
            m_sunlight_on_from = std::nullopt;
        }
    }
    
    
    bool sunlight_sensor_t::is_too_much_sunlight(bool const sunlight) {
        if(sunlight) {
            auto const time_now = std::chrono::system_clock::now();
            std::chrono::duration<double> elapsed_secs = time_now - *m_sunlight_on_from;
            return elapsed_secs.count() > m_thresold;
        }
        return false;
    }
    
    bool sunlight_sensor_t::is_too_little_sunlight(bool const sunlight) {
        if(!sunlight) {
            auto const time_now = std::chrono::system_clock::now();
            std::chrono::duration<double> elapsed_secs = time_now - *m_sunlight_off_from;
            return elapsed_secs.count() > m_thresold;
        }
        return false;
    }
    
    bool sunlight_sensor_t::is_sunlight() const {
        static bool sun_shines = false;
        static std::mt19937 generator;
        auto prob = std::uniform_int_distribution<int>(1, 100)(generator);
        if(prob >= 80) {
            sun_shines = !sun_shines;
        }
    
        return sun_shines;
    }
    
    }
    

    程序输出的效果如下,


    图片.png

    相关文章

      网友评论

          本文标题:C++ ISP Interface Segregation Pr

          本文链接:https://www.haomeiwen.com/subject/vdzmcjtx.html