Tôi là người tin tưởng mạnh mẽ vào triết lý thiết kế sau:Thiết kế giao diện API tốt hơn để chuyển cấu trúc từ một lớp này sang lớp khác
1> Dịch vụ phải được triển khai càng gần nơi dữ liệu được lưu trữ.
2> Getter và Setter là điều ác và cần được sử dụng cẩn thận.
Tôi không nên tranh luận ở trên hai đối số ở đây và cho rằng chúng có các cạnh của chúng.
Đây là thách thức mà tôi đang gặp phải. Tôi có hai lớp (ví dụ: AComputer
và A
) trong đó Máy tính cung cấp một số dịch vụ cho A và A giữ tất cả các thành viên dữ liệu cơ bản.
Sự thật: Tôi không được phép kết hợp AComputer
bên trong A
do thiết kế hệ thống. Tôi biết, nó đã phá vỡ quan điểm của tôi 1> nơi tính toán nên ở lại với dữ liệu.
Khi truyền dữ liệu từ A
đến AComputer
, chúng tôi phải vượt qua 10 (khoảng) tham số riêng lẻ và do đó tốt hơn là thiết kế cấu trúc để thực hiện điều đó. Hầu hết dữ liệu được lưu trữ trong AComputer
là bản sao trực tiếp các dữ liệu được lưu trữ trong A
. Chúng tôi đã chọn lưu trữ các dữ liệu đó bên trong AComputer
vì các chức năng khác trong AComputer
cũng cần các biến đó.
Dưới đây là câu hỏi (tôi yêu cầu cho thực hành tốt nhất xem xét bảo trì API & sửa đổi):
1> chúng ta nên xác định đèo cấu trúc PassData
ở đâu?
2> Chúng tôi có nên cung cấp getter/setter cho cấu trúc PassData
không?
Tôi đã cung cấp mã mẫu như sau để minh họa chi tiết câu hỏi của tôi. Tốt nhất là tôi có thể tìm thấy một API nguồn mở thực sự đã giải quyết cùng một vấn đề để tôi có thể học hỏi từ nó.
Nếu bạn xem riêng tư PassData m_data;
được xác định trong lớp AComputer
, tôi thực hiện điều này với mục đích. Nói cách khác, nếu chúng tôi thay đổi triển khai cơ bản của AComputer
, chúng tôi có thể thay thế PassData m_data;
bằng các biến riêng lẻ hoặc một biến nào khác nhưng KHÔNG phá vỡ giao diện của PassData
. Vì vậy, trong thiết kế này, tôi KHÔNG cung cấp một getter/setter cho cấu trúc PassData
.
Cảm ơn bạn
class AComputer
{
public:
struct PassData
{ // int type just used as an illustration. Real data has different types,
// such as double, data, string, enum, etc.
// Note: they are not exact copies of variables from A but derived from them
int m_v1;
// from m_v1 to m_v10
//...
int m_v10;
};
// it is better to store the passed-in data since other functions also need it.
AComputer(const PassData& pd) : m_data(pd) {}
int GetCombinedValue() const
{ /* This function returns a value based the passed-in struct of pd */ }
private:
PassData m_data;
};
class A
{
private:
int m_i1;
// from m_i1 to m_i10
// ...
int m_i10;
// from m_i11 to m_i20
// ...
int m_i20;
boost::shared_ptr<AComputer> m_pAComputer;
public:
A()
{
AComputer::PassData aData;
// populate aData ...
m_pAComputer = boost::shared_ptr<AComputer>(new AComputer(aData));
}
int GetCombinedValue() const
{
return m_pAComputer->GetCombinedValue();
}
};
Các đối số có liên quan thực sự tất cả 'int' (hoặc tất cả một loại bất kỳ) không? Nếu vậy, tôi nghĩ rằng tôi chỉ cần vượt qua một 'std :: vector'. Nếu bạn muốn truy cập chúng theo tên, tôi định nghĩa một enum trong 'AComputer' cung cấp tên cho các subscript, vì vậy bạn có thể sử dụng' argument [m_i1] 'thay vì' argument [0] '. –
Điểm tốt. Các đối số có đầy đủ các loại khác nhau, chẳng hạn như int, double, string, date, etc. Tôi sẽ cập nhật OP của tôi để xóa bỏ sự nhầm lẫn. – q0987
Cái gì ?! Bạn có hai triết lý thiết kế, và vì một lý do nào đó * có * để phá vỡ số 1. Bây giờ bạn hỏi chúng tôi xem bạn có nên phá vỡ số 2 không? Tôi đã bỏ lỡ điều gì ở đây? –