[英]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類盡可能地可擴展,以防我想要添加更多的層(應放棄代理選項)以及盡可能正確的層。 非常感謝。
當然,有很多方法可以做到這一點。 但是從設計角度來看,保持一致性很重要( 請參見此處: “一致性與概念完整性一致” )。
您對三個容器類RoadMap
, TrafficSignsMap
和PlacesToEatMap
都具有以下原則:
如果要保持一致,則應對MapData
采用相同的方法:使用代理方法(您的第一種選擇)。
就個人而言(但在這里,我們保留客觀事實並輸入主觀意見),我認為這種設計沒有利用面向對象設計的優勢。 我並不是說這很糟糕:這樣做可能有充分的理由。 但不是最佳的。 為什么呢 您的類的用戶無法操縱您的類圍繞其設計的應用程序對象:他不使用路段,而僅使用路段坐標。 例如:如果稍后您決定float
不夠精確,則應使用double
來代替,而每一段代碼都必須進行檢查。 如果您意識到可能有調諧器並且坐標需要為3D,那將是一次真正的維護災難
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.