Thêm trường vào lớp trong thời gian chạy - mẫu thiết kế


15

Hãy tưởng tượng khách hàng của bạn muốn có khả năng thêm tài sản mới (ví dụ như màu sắc) vào sản phẩm trong eshop của họ trong CMS của họ.

Thay vì có các thuộc tính như các trường:

class Car extends Product {
   protected String type;
   protected int seats;
}

Bạn có thể sẽ làm một cái gì đó như:

class Product {
   protected String productName;
   protected Map<String, Property> properties;
}

class Property {
   protected String name;
   protected String value;
}

Đó là, tạo ra hệ thống loại riêng trên đầu trang hiện có. Tôi cảm thấy như thế này có thể được coi là tạo ngôn ngữ cụ thể cho miền, hoặc không thể?

Có phải cách tiếp cận này là một mẫu thiết kế đã biết? Bạn sẽ giải quyết vấn đề khác nhau? Tôi biết có những ngôn ngữ nơi tôi có thể thêm một trường trong thời gian chạy, nhưng cơ sở dữ liệu thì sao? Bạn có muốn thêm / thay đổi cột hoặc sử dụng đôi khi như được hiển thị ở trên?

Cảm ơn bạn đã dành thời gian :).



Không chắc chắn bạn đang sử dụng ngôn ngữ nào, nhưng nếu đó là C #, bạn có thể sử dụng loại động về cơ bản lưu trữ KVP trong từ điển giống như những gì bạn đang làm trên các sản phẩm và cho phép bạn chỉ cần xử lý các thuộc tính mà không cần phải trực tiếp thêm chúng vào bộ sưu tập như một bộ sưu tập. Bạn sẽ không có gõ mạnh mặc dù. Tôi biết bạn đã yêu cầu một mẫu thiết kế nhưng tôi không cảm thấy bạn sẽ cần bất cứ thứ gì phức tạp để sử dụng chúng. msdn.microsoft.com/en-us/magazine/gg598922.aspx
Tony

Tony: Tôi đang sử dụng Java ở đây, nhưng hãy xem nó là giả coude :). C # có cho phép tôi duy trì đối tượng động đó vào cơ sở dữ liệu không? Tôi nghi ngờ điều đó, vì databse cần biết cấu trúc dữ liệu trước.
Filip

mô hình Desing State a-la Gang-of-Four, làm cho một đối tượng dường như thay đổi loại hoặc lớp của nó trong thời gian chạy. Các lựa chọn thay thế khác là Mẫu thiết kế quan sát hoặc Mẫu thiết kế proxy
Nikos M.

1
Tại sao không chỉ sử dụng kiểu dữ liệu bản đồ? Trong DB, nó có thể được biểu diễn dưới dạng {id} + {id, key, value}, nếu bạn không yêu cầu hiệu suất.
Bóng tối trong mưa

Câu trả lời:


4

Xin chúc mừng! Bạn vừa đi vòng quanh thế giới ngôn ngữ lập trình / loại hệ thống, đến bên kia thế giới từ nơi bạn khởi hành. Bạn vừa hạ cánh trên biên giới của vùng đất đối tượng dựa trên ngôn ngữ động / nguyên mẫu!

Nhiều ngôn ngữ động (ví dụ JavaScript, PHP, Python) cho phép một ngôn ngữ mở rộng hoặc thay đổi các thuộc tính đối tượng khi chạy.

Hình thức cực đoan của điều này là một ngôn ngữ dựa trên nguyên mẫu như Tự hoặc JavaScript. Họ không có lớp học, nói đúng ra. Bạn có thể thực hiện những thứ trông giống như lập trình hướng đối tượng dựa trên lớp với kế thừa, nhưng các quy tắc được nới lỏng rất nhiều so với các ngôn ngữ dựa trên lớp được định nghĩa rõ ràng hơn như Java và C #.

Langauges như PHP và Python sống ở giữa. Họ có hệ thống dựa trên lớp thường xuyên, thành ngữ. Nhưng các thuộc tính đối tượng có thể được thêm, thay đổi hoặc xóa trong thời gian chạy - mặc dù có một số hạn chế (như "ngoại trừ các loại tích hợp") mà bạn không tìm thấy trong JavaScript.

Sự đánh đổi lớn cho sự năng động này là hiệu suất. Quên ngôn ngữ gõ mạnh hay yếu như thế nào, hoặc nó có thể được biên dịch thành mã máy tốt đến mức nào. Các đối tượng động phải được biểu diễn dưới dạng bản đồ / từ điển linh hoạt, thay vì các cấu trúc đơn giản. Điều này thêm chi phí cho mọi đối tượng truy cập. Một số chương trình cố gắng hết sức để giảm chi phí này (ví dụ như với phép gán kwarg ảo và các lớp dựa trên vị trí trong Python), nhưng chi phí phụ thường chỉ ngang bằng với khóa học và giá nhập học.

Quay trở lại thiết kế của bạn, bạn đang ghép khả năng có các thuộc tính động vào một tập hợp con của các lớp. A Productcó thể có các thuộc tính thay đổi; có lẽ là một Invoicehoặc Ordersẽ và không thể. Đó không phải là một cách tồi để đi. Nó cho phép bạn linh hoạt để có sự thay đổi ở nơi bạn cần, trong khi vẫn ở trong một hệ thống ngôn ngữ và loại nghiêm ngặt, kỷ luật. Về mặt trái, bạn chịu trách nhiệm quản lý các thuộc tính linh hoạt đó và có thể bạn sẽ phải làm như vậy thông qua các cơ chế trông hơi khác so với các thuộc tính bản địa hơn. p.prop('tensile_strength')thay vì p.tensile_strength, ví dụ, và p.set_prop('tensile_strength', 104.4)hơn làp.tensile_strength = 104.4. Nhưng tôi đã làm việc với và xây dựng nhiều chương trình bằng Pascal, Ada, C, Java và thậm chí các ngôn ngữ động sử dụng chính xác quyền truy cập getter-setter như vậy cho các loại thuộc tính không chuẩn; Cách tiếp cận rõ ràng là khả thi.

Bởi, sự căng thẳng giữa các loại tĩnh và một thế giới rất đa dạng là vô cùng phổ biến. Một vấn đề tương tự thường thấy khi thiết kế lược đồ cơ sở dữ liệu, đặc biệt là đối với các kho lưu trữ dữ liệu quan hệ và tiền quan hệ. Đôi khi, nó được xử lý bằng cách tạo ra các "siêu hàng" có đủ độ linh hoạt để chứa hoặc xác định sự kết hợp của tất cả các biến thể tưởng tượng, sau đó nhồi bất kỳ dữ liệu nào đi vào các trường đó. Các WordPress wp_postsbảng , ví dụ, có các lĩnh vực như comment_count, ping_status, post_parentpost_date_gmtđó chỉ là thú vị trong một số trường hợp, và rằng trong thực tế thường chuyển sang màu trắng. Một cách tiếp cận khác là một bảng rất bình thường , bình thường như wp_options, giống như của bạnPropertylớp học. Mặc dù nó đòi hỏi quản lý rõ ràng hơn, các mục trong đó hiếm khi trống. Cơ sở dữ liệu hướng đối tượng và tài liệu (ví dụ MongoDB) thường có thời gian xử lý các tùy chọn thay đổi dễ dàng hơn, vì chúng có thể tạo và thiết lập các thuộc tính khá nhiều theo ý muốn.


0

Tôi thích câu hỏi, hai xu của tôi:

Hai cách tiếp cận của bạn hoàn toàn khác nhau:

  • Cái đầu tiên là OO ans gõ mạnh - nhưng không thể mở rộng
  • Cái thứ hai được gõ yếu (chuỗi đóng gói bất cứ thứ gì)

Trong C ++, nhiều người sẽ sử dụng biến thể std :: map of boost :: để đạt được kết hợp cả hai.

Vi phạm: Lưu ý rằng một số ngôn ngữ, chẳng hạn như C #, cho phép tạo kiểu động. Đó có thể là một giải pháp tốt cho vấn đề chung về việc thêm thành viên một cách linh hoạt. Tuy nhiên, các loại "sửa đổi / thêm" sau khi biên dịch làm hỏng chính hệ thống loại đó và làm cho các loại "đã sửa đổi" của bạn gần như vô dụng (ví dụ: làm thế nào bạn truy cập vào các thuộc tính được thêm như vậy, vì bạn thậm chí không biết chúng tồn tại? là sự phản ánh có hệ thống đối với từng đối tượng ... kết thúc bằng một ngôn ngữ động thuần túy _ bạn có thể tham khảo từ khóa .NET 'động')


Tạo các kiểu trong thời gian chạy thú vị nhưng quá kỳ lạ đối với tôi (Tôi đang lập trình bằng Java). Giải pháp như vậy sẽ không hoạt động, nếu tôi muốn lưu trữ đối tượng trong cơ sở dữ liệu, điều mà tôi luôn tin tưởng mạnh mẽ. Giải pháp gõ yếu mà tôi đã đề xuất có thể được lưu trữ trong cơ sở dữ liệu một cách dễ dàng.
Filip

0

Tạo một kiểu trong thời gian chạy nghe có vẻ phức tạp hơn nhiều sau đó chỉ cần tạo một lớp trừu tượng. Nó là rất phổ biến để tạo ra một sự trừu tượng để tách các hệ thống.

Hãy để tôi chỉ ra một ví dụ từ thực tiễn của tôi. Trao đổi Moscow có cốt lõi giao dịch được gọi là Plaza2 với API của thương nhân. Thương nhân viết chương trình của họ để làm việc với dữ liệu tài chính. Vấn đề là dữ liệu này rất lớn, phức tạp và rất dễ bị thay đổi. Nó có thể thay đổi sau khi một sản phẩm tài chính mới được giới thiệu hoặc các quy định bù trừ thay đổi. Bản chất của những thay đổi trong tương lai không thể dự đoán được. Theo nghĩa đen, nó có thể thay đổi mỗi ngày và các lập trình viên nghèo nên chỉnh sửa mã và phát hành phiên bản mới, và các nhà giao dịch tức giận nên sửa đổi hệ thống của họ.

Quyết định rõ ràng là che giấu tất cả địa ngục tài chính đằng sau một sự trừu tượng. Họ đã sử dụng trừu tượng các bảng SQL nổi tiếng. Phần lớn nhất trong lõi của họ có thể hoạt động với bất kỳ lược đồ hợp lệ nào, giống như phần mềm của thương nhân có thể tự động phân tích lược đồ và tìm hiểu xem nó có tương thích với hệ thống của họ không.

Trở lại ví dụ của bạn, việc tạo ra một ngôn ngữ trừu tượng trước một số logic là điều bình thường. Nó có thể là "tài sản", "bảng", "thông điệp" hoặc thậm chí là ngôn ngữ của con người, nhưng chú ý đến những nhược điểm của phương pháp này:

  • Thêm mã để phân tích cú pháp và xác nhận (và nhiều thời gian hơn khóa học). Mọi thứ trình biên dịch đã làm cho bạn với kiểu gõ tĩnh bạn phải làm trong thời gian chạy.
  • Thêm tài liệu về tin nhắn, bảng hoặc các nguyên thủy khác. Tất cả sự phức tạp đi từ mã đến một loại lược đồ hoặc tiêu chuẩn. Dưới đây là một ví dụ về lược đồ địa ngục tài chính được đề cập ở trên: http://ftp.moex.com/pub/FORTS/Plaza2/p2gate_en.pdf (hàng chục trang của bảng)

0

Có phải cách tiếp cận này là một mẫu thiết kế đã biết?

Trong XML và HTML, đây sẽ là các thuộc tính cho một nút / phần tử. Tôi cũng đã nghe chúng được gọi là các thuộc tính mở rộng, cặp tên / giá trị và tham số.

Bạn sẽ giải quyết vấn đề khác nhau?

Đó là cách tôi sẽ giải quyết vấn đề, vâng.

Tôi biết có những ngôn ngữ nơi tôi có thể thêm một trường trong thời gian chạy, nhưng cơ sở dữ liệu thì sao?

Một cơ sở dữ liệu sẽ giống như Java, theo một số ý nghĩa. Trong pesudo-sql:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

Điều này sẽ tương ứng với Java

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Lưu ý rằng không cần lớp Thuộc tính, vì Bản đồ lưu tên làm khóa.

Bạn có muốn thêm / thay đổi cột hoặc sử dụng đôi khi như được hiển thị ở trên?

Tôi đã thử điều bổ sung / thay đổi cột và đó là một cơn ác mộng. Nó có thể được thực hiện, nhưng mọi thứ không đồng bộ và tôi không bao giờ làm cho nó hoạt động tốt. Cấu trúc bảng tôi đã nêu ở trên đã thành công hơn nhiều. Nếu bạn cần phải thực hiện tìm kiếm và trật tự do của, hãy xem xét sử dụng một thuộc tính bảng đối với từng loại dữ liệu ( date_attributes, currency_attributes, vv) hoặc thêm một số thuộc tính như cột cơ sở dữ liệu cũ tốt trong bảng sản phẩm. Báo cáo thường dễ dàng hơn nhiều để viết trên các cột cơ sở dữ liệu sau đó các bảng phụ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.