簡體   English   中英

C ++數據分組類和const訪問

[英]C++ data grouping class and const access

這個問題涉及類設計和連貫的接口(我想)。

假設您有一個小類來代表道路的“幾何” ...它可能包含許多這樣的屬性和方法...

class RoadMap
{
    private:

    struct RoadPiece
    {
        float x1, y1, x2, y2;
    };  

    std::string name;
    float area_width;
    float area_height;

    std::vector<RoadPiece> pieces;

    public:

    const std::string& get_name() const {return name;}
    float get_width() const {return area_width;}
    float get_height() const {return area_height;}
    float get_area() const {return area_width * area_height;}

    void set_width(float v) {area_width=v;}
    void set_height(float v) {area_height=v;}
    void set_name(const std::string v) {name=v;}

    void add_road_piece(float x1, float y1, float x2, float y2)
    {
        //...
    }
}

如您所見,我們正在混合使用const和非const方法。 沒什么大不了的:我們幾乎可以像這樣編寫客戶端代碼

RoadMap m;

m.set_width(100.0);
m.set_height(150.0);
m.set_name("Northern Hills");

//Tedious code here...

std::cout<<"The area of the map is "<<m.get_area()<<std::endl;

現在,讓我們確定我們要向地圖添加“不一定要屬於該地圖的”另一層信息,而是...在客戶端代碼中對其進行補充...例如,交通標志

class TrafficSignsMap
{
    private:

    struct Sign
    {
        enum class types {STOP, YIELD, STEP_ON_IT};
        types type;     
        float x;
        float y;
    }

    std::vector<Sign> signs;

    public:

    void add_stop_sign(float x, float y) {/*Blah blah*/}
    void add_yield_sign(float x, float y) {/*Blah blah*/}
    void add_step_on_it_sign(float x, float y) {/*Blah blah*/}

    const std::vector<Sign>& get_all_signs() {return signs;}
    const std::vector<const Sign const  *> get_signs_in_area(float x1, float y1, float x2, float y2)
    {
        //Do some calculations, populate a vector with pointers to signs, return it...
    }
}

同樣,我們可以編寫各種客戶端代碼,混合各種方式和注冊。 請注意,此時我並不是真的在做這個應用程序,只是以它為例...

無論如何,在編寫了更多代碼之后,我附帶了第三層數據……這次是“ PlacesToEat”。 我不會在這里描述它們,但是您會發現漂移:它獨立存在,但可以與道路或標志共享一定的空間(更像是道路,但是...)。 在第三層(也是最后一層)中,我們找到了一個可以獲取帶有道路,標志和用餐地點信息的文件的地方。 我們認為我們可以編寫一個類來提供文件並為我們存儲信息。 像這樣:

class MapData
{
    private:

    RoadMap roads;
    TrafficSignsMap signs;
    PlacesToEatMap places_to_eat;

    public:

    MapData(const std::string& filename)
    {
        std::ifstream(filename);

        //Read the file... populate our properties...
    }

    const RoadMap& get_road_map() const {return roads;} 
    const TrafficSignsMap& get_signs_map() const {return signs;}
    const PlacesToEatMap& get_places_to_eat_map() const {return places_to_eat;}
};

事情就是這樣……將所有數據分組到一個大容器中之后,我們應該同時提供const和non const訪問,對嗎? 我想獲取所有const數據,但我也應該能夠添加新的用餐場所,而這是我當前界面無法實現的。

現在,我知道可以將MapData類用作代理(增加其在應用程序中的責任感),所以我會去:

MapData MD;
MD.add_stop_sign(10.0, 20.0);   //This, in time, proxies to the inner property.

或者我可以這樣添加const和non const getters(增加我的頭痛):

MapData MD;
float area=MD.get_road_map().get_area();
MD.get_non_const_road_map().add_road(/*blah blah*/);

或者我可以擰緊它,並將這些屬性公開:

public:

RoadMap roads;
TrafficSignsMap signs;
PlacesToEatMap places_to_eat;

或者,我可以使吸氣劑變為非常量,因為我是要修改數據並完成處理的(這里並沒有真正的缺點……我想,我說的是const MapData對象,我不應該無論如何都要更改):

    RoadMap& get_road_map() {return roads;} 
    TrafficSignsMap& get_signs_map() {return signs;}
    PlacesToEatMap& get_places_to_eat_map() {return places_to_eat;}

再次,請注意,該問題已被修正,因為該問題已被修正(為什么路線圖還會存儲尺寸?)。 考慮到這一點,您將如何處理這種情況? 我正在尋找一種方法,可以使MapData類盡可能地可擴展,以防我想要添加更多的層(應放棄代理選項)以及盡可能正確的層。 非常感謝。

當然,有很多方法可以做到這一點。 但是從設計角度來看,保持一致性很重要( 請參見此處: “一致性與概念完整性一致” )。

您對三個容器類RoadMapTrafficSignsMapPlacesToEatMap都具有以下原則:

  • 容器中的對象是私有結構
  • 容器的用戶不知道對象,而僅知道定義對象的數據(例如:路段的四個浮標)。
  • 使用構成對象的數據在容器中進行插入(也檢索?)。

如果要保持一致,則應對MapData采用相同的方法:使用代理方法(您的第一種選擇)。

就個人而言(但在這里,我們保留客觀事實並輸入主觀意見),我認為這種設計沒有利用面向對象設計的優勢。 我並不是說這很糟糕:這樣做可能有充分的理由。 但不是最佳的。 為什么呢 您的類的用戶無法操縱您的類圍繞其設計的應用程序對象:他不使用路段,而僅使用路段坐標。 例如:如果稍后您決定float不夠精確,則應使用double來代替,而每一段代碼都必須進行檢查。 如果您意識到可能有調諧器並且坐標需要為3D,那將是一次真正的維護災難

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM