Trước hết, đừng nhầm lẫn điều này với thiết kế hướng dữ liệu.
Sự hiểu biết của tôi về Thiết kế hướng dữ liệu là về việc tổ chức dữ liệu của bạn để xử lý hiệu quả. Đặc biệt là liên quan đến các lỗi nhớ cache, v.v. Mặt khác, Data Driven Design là về việc cho phép dữ liệu kiểm soát nhiều hành vi chương trình của bạn (được mô tả rất tốt theo câu trả lời của Andrew Keith ).
Giả sử bạn có các đối tượng bóng trong ứng dụng của mình với các thuộc tính như màu sắc, bán kính, độ nảy, vị trí, v.v.
Phương pháp hướng đối tượng
Trong OOP bạn sẽ mô tả các quả bóng như thế này:
class Ball {
Point position;
Color color;
double radius;
void draw();
};
Và sau đó bạn sẽ tạo ra một bộ sưu tập các quả bóng như thế này:
vector<Ball> balls;
Phương pháp định hướng dữ liệu
Tuy nhiên, trong Thiết kế hướng dữ liệu, bạn có nhiều khả năng viết mã như thế này:
class Balls {
vector<Point> position;
vector<Color> color;
vector<double> radius;
void draw();
};
Như bạn có thể thấy không còn đơn vị nào đại diện cho một Quả bóng nữa. Đối tượng bóng chỉ tồn tại ngầm.
Điều này có thể có nhiều lợi thế, hiệu suất khôn ngoan. Thông thường chúng tôi muốn thực hiện các hoạt động trên nhiều quả bóng cùng một lúc. Phần cứng thường muốn khối bộ nhớ lớn liên tục hoạt động hiệu quả.
Thứ hai, bạn có thể thực hiện các hoạt động chỉ ảnh hưởng đến một phần của các thuộc tính bóng. Ví dụ: nếu bạn kết hợp màu sắc của tất cả các quả bóng theo nhiều cách khác nhau, thì bạn muốn bộ đệm của bạn chỉ chứa thông tin màu. Tuy nhiên, khi tất cả các thuộc tính bóng được lưu trữ trong một đơn vị, bạn cũng sẽ kéo theo tất cả các thuộc tính khác của một quả bóng. Mặc dù bạn không cần chúng.
Ví dụ sử dụng bộ nhớ cache
Giả sử mỗi quả bóng chiếm 64 byte và một Điểm mất 4 byte. Một khe bộ nhớ cũng mất 64 byte. Nếu tôi muốn cập nhật vị trí của 10 quả bóng, tôi phải kéo 10 * 64 = 640 byte bộ nhớ vào bộ đệm và nhận 10 lỗi bộ nhớ cache. Tuy nhiên, nếu tôi có thể làm việc các vị trí của các quả bóng dưới dạng các đơn vị riêng biệt, điều đó sẽ chỉ mất 4 * 10 = 40 byte. Điều đó phù hợp với một lần tìm nạp bộ đệm. Do đó, chúng tôi chỉ nhận được 1 lỗi nhớ cache để cập nhật tất cả 10 quả bóng. Những con số này là tùy ý - Tôi giả sử một khối bộ đệm lớn hơn.
Nhưng nó minh họa cách bố trí bộ nhớ có thể ảnh hưởng nghiêm trọng đến các lần truy cập bộ đệm và do đó hiệu suất. Điều này sẽ chỉ tăng tầm quan trọng khi sự khác biệt giữa tốc độ CPU và RAM mở rộng.
Cách bố trí bộ nhớ
Trong ví dụ bóng của tôi, tôi đã đơn giản hóa vấn đề rất nhiều, bởi vì thông thường đối với bất kỳ ứng dụng thông thường nào, bạn có thể sẽ truy cập nhiều biến số cùng nhau. Ví dụ: vị trí và bán kính có thể sẽ được sử dụng cùng nhau thường xuyên. Sau đó, cấu trúc của bạn sẽ là:
class Body {
Point position;
double radius;
};
class Balls {
vector<Body> bodies;
vector<Color> color;
void draw();
};
Lý do bạn nên làm điều này là nếu dữ liệu được sử dụng cùng nhau được đặt trong các mảng riêng biệt, có nguy cơ chúng sẽ cạnh tranh cho cùng một vị trí trong bộ đệm. Như vậy tải cái này sẽ vứt cái kia.
Vì vậy, so với lập trình hướng đối tượng, các lớp bạn kết thúc không liên quan đến các thực thể trong mô hình tinh thần của vấn đề. Vì dữ liệu được gộp lại với nhau dựa trên việc sử dụng dữ liệu, bạn sẽ không luôn có tên hợp lý để đặt các lớp của mình trong Thiết kế hướng dữ liệu.
Liên quan đến cơ sở dữ liệu quan hệ
Suy nghĩ đằng sau Thiết kế hướng dữ liệu rất giống với cách bạn nghĩ về cơ sở dữ liệu quan hệ. Tối ưu hóa cơ sở dữ liệu quan hệ cũng có thể liên quan đến việc sử dụng bộ đệm hiệu quả hơn, mặc dù trong trường hợp này, bộ đệm không phải là bộ đệm CPU mà là các trang trong bộ nhớ. Một nhà thiết kế cơ sở dữ liệu tốt cũng có thể sẽ phân tách dữ liệu được truy cập không thường xuyên vào một bảng riêng thay vì tạo một bảng có số lượng cột lớn chỉ một vài trong số các cột được sử dụng. Anh ta cũng có thể chọn không chuẩn hóa một số bảng để dữ liệu không phải được truy cập từ nhiều vị trí trên đĩa. Giống như với Thiết kế hướng dữ liệu, các lựa chọn này được thực hiện bằng cách xem xét các mẫu truy cập dữ liệu là gì và nơi tắc nghẽn hiệu suất.