Bạn có thể sử dụng chuyên môn mẫu để tách các phần chỉ có mục đích trên đối tượng không phải là const.
Sau đây là triển khai cho lớp đồ chơi. Nó có một thành viên c-mảng đơn v với 10 ints, và, cho mục đích của chúng ta, nó chỉ hợp lệ khi mỗi một phần tử trong số chúng bằng 0.
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
};
Xem mà tôi đã thực hiện một hàm thành viên, có thể chữa một vị trí không hợp lệ, và một constructor tốt đẹp mà khởi nó như là một đối tượng không hợp lệ (không làm điều đó: D)
Kể từ khi chúng ta sẽ sử dụng các mẫu, chúng ta cần phải di chuyển việc thực hiện chu kỳ kiểm tra/sửa lỗi bên ngoài lớp. Để các chức năng liên quan có thể truy cập v
và phương pháp fix()
, chúng tôi sẽ kết bạn với bạn bè. mã của chúng tôi bây giờ trông giống như:
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
check()
's thực hiện rất đơn giản:
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
Bây giờ đây là phần khó khăn. Chúng tôi muốn chức năng fix()
của chúng tôi để thay đổi hành vi dựa trên độ chói. Để làm được điều đó, chúng tôi sẽ cần chuyên về mẫu. Đối với một đối tượng không phải const, nó sẽ sửa chữa vị trí. Đối với một const, nó sẽ không làm gì cả:
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
Cuối cùng, chúng ta viết của chúng tôi is_valid()
và make_valid()
phương pháp, và ở đây chúng tôi có đầy đủ việc thực hiện:
#include <iostream>
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
bool is_valid() const {return check(*this);} // since this is const, it will run check with a const ten_zeroes object
void make_valid() { check(*this);} // since this is non-const , it run check with a non-const ten_zeroes object
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
int main(){
ten_zeroes a;
std::cout << a.is_valid() << a.is_valid(); // twice to make sure the first one didn't make any changes
a.make_valid(); // fix the object
std::cout << a.is_valid() << std::endl; // check again
}
Tôi hy vọng bạn không nhớ các main()
hoạt động ở đó. Nó sẽ kiểm tra đồ chơi nhỏ của chúng tôi, và đầu ra 001
, như mong đợi. Bây giờ bất kỳ bảo trì trên mã này sẽ không phải đối phó với trùng lặp mã, những gì bạn có thể có ý định để tránh. Tôi hy vọng nó sẽ có ích.
Tất nhiên, nếu bạn định ẩn các chi tiết triển khai này khỏi người dùng cuối cùng, bạn nên chuyển chúng đến một không gian tên chi tiết thích hợp. Tôi sẽ để lại điều đó cho bạn :)
Kiểm tra phân tách và "sửa lỗi" thành hai chức năng khác nhau? Kiểm tra là 'const' và sửa chữa không? – crashmstr
Tôi đồng ý với @crashmstr, có một chức năng làm hai việc khác nhau là mùi thiết kế xấu. –
Trên thực tế, đã có tên 'CheckValidity' gợi ý rằng hàm này chỉ thực hiện kiểm tra và có thể là const. Nếu bạn muốn 'MakeValid' nó là một cái gì đó khác nhau (và nó không nên const ...) – user463035818