Các đối tượng trong OOP có phải đại diện cho một thực thể không?


82

Có một đối tượng phải đại diện cho một thực thể?

Bởi một thực thể tôi là một cái gì đó giống như một Product, Motormột ParkingLotvv, một vật lý, hoặc thậm chí một đối tượng khái niệm phi vật chất rõ ràng - một cái gì đó cũng được định nghĩa, với một số dữ liệu cốt lõi thuộc rõ ràng để các đối tượng, và một số chức năng / phương pháp rõ ràng hoạt động trên dữ liệu cốt lõi.

Ví dụ, tôi có thể có một đối tượng của một Demon, một thực thể trong chính nó, một đối tượng tưởng tượng có thể và không phải là vật lý mà là một thực thể tuy nhiên

Một đối tượng có thể chỉ là một tập hợp các phương thức , một tập hợp các thủ tục chung gắn với một mục tiêu chung không?

Ví dụ: một lớp có thể được gọi MotorOperationshoặc MotorActions, trong đó không có thực thể, nhưng các phương thức bên trong lớp thực hiện những việc như

  • getMotorDataFromHTMLForm ()
  • getMotorSản xuất ()
  • selectMotorFromUserRequirements ($ yêu cầu)
  • canMotorCanHandleOperatingConditions ($ condition)
  • computePowerConschargeForMotor ($ id)

Một lớp thường được định nghĩa là dữ liệu trung tâm cho đối tượng + hoạt động trên dữ liệu. Vì vậy, Motorcó thể có một số biến động cơ liên quan đến thông số kỹ thuật của động cơ và có thể có các hoạt động kết hợp các dữ liệu đó để tạo ra một cái gì đó.

Trong trường hợp của tôi, giống như tôi có một lớp với các thao tác trên dữ liệu + dữ liệu được truyền qua lớp, không có dữ liệu tập trung vào "Hoạt động của động cơ", ngoại trừ dữ liệu chuyển qua lớp tạm thời.

Câu hỏi

Các lớp có thể đại diện cho các đối tượng không có thực thể? Nếu không, tại sao họ xấu / không đầy đủ / không OOP-centric? Có những cách họ cần được thay đổi / cải thiện về mặt khái niệm để phù hợp với OOP?


2
+1. Nhưng "có" có nghĩa là nó phải đại diện cho một thực thể, hay nó có nghĩa là chúng có thể đại diện cho các đối tượng không có thực thể?
Panzercrisis

1
Điều đầu tiên tôi nghĩ đến: java.awt và các lớp "Op" của nó (ví dụ: docs.oracle.com/javase/7/docs/api/java/awt/image/ ,), nếu đó là ý bạn. Nó đại diện cho một hoạt động. Bây giờ, tôi không chắc liệu đó có phải là cách thực hành tốt hay không (trông có vẻ kỳ lạ và xấu xí), nhưng nó được bao gồm trong thư viện tiêu chuẩn Java và Java là OOP. Phần lớn.
Lu-ca

1
Không, nó không có, nhưng điều đó không có nghĩa MotorActionshay MotorOperationslà ý tưởng tốt hay không.
dùng253751

1
Câu hỏi này có thể được hưởng lợi từ một đặc điểm kỹ thuật hơn nữa của can .
Revierpost

3
@Dennis Tôi thực sự cảm thấy như bạn đang hỏi tất cả các câu hỏi sai. Thứ nhất bởi vì không có định nghĩa dứt khoát về OOP, thứ hai bởi vì các mô hình chỉ là một phương tiện để kết thúc. Câu hỏi duy nhất quan trọng là "việc viết mã theo cách này có giúp dễ dàng suy luận về tính đúng đắn của nó không?" và "viết mã theo cách này có giúp tái sử dụng dễ dàng hơn không?"
Doval

Câu trả lời:


109

Không , một đối tượng không phải đại diện cho một thực thể.

Trên thực tế, tôi sẽ lập luận rằng khi bạn ngừng suy nghĩ về các đối tượng như các thực thể vật lý là khi cuối cùng bạn nhận được những lợi ích mà OOP hứa hẹn.

Đây không phải là ví dụ tốt nhất, nhưng thiết kế Coffee Maker có lẽ là nơi ánh sáng bắt đầu chiếu vào tôi.

Đối tượng là về tin nhắn. Họ là về trách nhiệm. Họ không nói về Ô tô, Người dùng hoặc Đơn hàng.

Tôi biết chúng tôi dạy OO theo cách này, nhưng nó trở nên rõ ràng sau một vài lần thử làm thế nào về cơ bản là làm thế nào để tìm ra mọi thứ khi bạn cố gắng làm MVC, MVVM hoặc MVWhthing. Mô hình của bạn trở nên cồng kềnh hoặc bộ điều khiển của bạn làm. Để điều hướng, thật tuyệt khi biết rằng bất cứ thứ gì chạm vào Phương tiện đều có trong tệp Xe.ext, nhưng khi ứng dụng của bạn là về Phương tiện, chắc chắn bạn sẽ kết thúc với 3000 dòng mì spaghetti trong tệp đó.

Khi bạn có một tin nhắn mới để gửi, bạn có ít nhất một đối tượng mới và có lẽ là một cặp trong số họ. Vì vậy, trong câu hỏi của bạn về một bó phương thức, tôi sẽ tranh luận rằng bạn có khả năng nói về một bó thông điệp. Và mỗi người có thể là đối tượng của riêng mình, với công việc riêng phải làm. Và thế là ổn. Nó sẽ trở nên rõ ràng khi bạn chia tách mọi thứ mà những thứ thực sự, thực sự cần phải được ở bên nhau. Và bạn đặt chúng lại với nhau. Nhưng bạn không bỏ ngay mọi phương pháp vào ngăn kéo thích hợp mơ hồ để thuận tiện nếu bạn muốn thưởng thức OO.

Hãy nói về túi chức năng

Một đối tượng có thể chỉ là một tập hợp các phương pháp và vẫn có OO, nhưng tôi "quy tắc" là khá nghiêm ngặt.

  1. Bộ sưu tập nên có một trách nhiệm duy nhất và trách nhiệm đó không thể chung chung như "Có công cụ cho động cơ". Tôi có thể làm một thứ như mặt tiền của lớp dịch vụ, nhưng tôi nhận thức sâu sắc rằng tôi lười biếng vì lý do điều hướng / khám phá, không phải vì tôi đang cố viết mã OO.

  2. Tất cả các phương pháp nên ở một lớp trừu tượng nhất quán. Nếu một phương thức lấy các đối tượng Motor và một phương thức khác trả về Mã lực, thì có lẽ cách nhau quá xa.

  3. Đối tượng nên làm việc trên cùng một "loại" dữ liệu. Đối tượng này thực hiện công cụ cho động cơ (bắt đầu / dừng), đối tượng này thực hiện mọi việc với chiều dài tay quay, đối tượng này xử lý trình tự đánh lửa, điều này có dạng html. Dữ liệu này có thể hình dung là các trường trên đối tượng và nó có vẻ gắn kết.

Tôi thường xây dựng các đối tượng thuộc loại này khi tôi thực hiện các phép biến đổi, bố cục hoặc chỉ không muốn lo lắng về tính biến đổi.

Tôi thấy tập trung vào trách nhiệm đối tượng dẫn tôi đến sự gắn kết. Phải có một sự gắn kết để trở thành một đối tượng, nhưng không cần phải có bất kỳ trường nào cũng như không có nhiều hành vi để nó trở thành một đối tượng. Nếu tôi đang xây dựng một hệ thống cần 5 phương thức động cơ đó, tôi sẽ bắt đầu với 5 đối tượng khác nhau thực hiện những điều đó. Khi tôi tìm thấy điểm chung, tôi sẽ bắt đầu hợp nhất mọi thứ lại với nhau hoặc sử dụng các đối tượng "người trợ giúp" chung. Điều đó chuyển tôi vào các mối quan tâm mở / đóng - làm cách nào tôi có thể trích xuất một chút chức năng này để tôi không bao giờ phải sửa đổi tệp cụ thể đó một lần nữa mà vẫn sử dụng nó khi cần thiết?

Đối tượng là về tin nhắn

Các lĩnh vực hầu như không quan trọng đối với một đối tượng - nhận và thiết lập các thanh ghi không làm thay đổi thế giới bên ngoài chương trình. Phối hợp với các đối tượng khác sẽ hoàn thành công việc. Tuy nhiên, điểm mạnh của OO là chúng ta có thể tạo ra sự trừu tượng để chúng ta không phải suy nghĩ về tất cả các chi tiết riêng lẻ cùng một lúc. Trừu tượng mà rò rỉ hoặc không có ý nghĩa là có vấn đề, vì vậy chúng tôi suy nghĩ sâu sắc (quá nhiều, có thể) về việc tạo ra các đối tượng phù hợp với mô hình tinh thần của chúng tôi.

Câu hỏi chính: Tại sao hai đối tượng này cần nói chuyện với nhau?

Hãy nghĩ về đối tượng như một cơ quan trong một người - nó có mục đích mặc định và chỉ thay đổi hành vi khi nhận được một thông điệp cụ thể mà nó quan tâm.

Hãy tưởng tượng một kịch bản khi bạn đang băng qua đường và một chiếc ô tô đang đến rất nhanh. Là đối tượng não, tôi phát hiện ra một yếu tố gây căng thẳng. Tôi nói với vùng dưới đồi gửi hormone giải phóng corticotrophin. Tuyến yên nhận được thông điệp đó và giải phóng hormone corticotrophic tuyến thượng thận. Các tuyến thượng thận nhận được thông điệp đó và tạo ra adrenaline. Khi đối tượng cơ nhận được thông điệp adrenaline đó, nó co lại. Khi trái tim nhận được thông điệp tương tự, nó sẽ đập nhanh hơn. Có cả một chuỗi những người chơi tham gia vào việc bắt đầu hành vi phức tạp của việc chạy nước rút trên đường phố và đó là những thông điệp quan trọng. Đối tượng não biết làm thế nào để vùng dưới đồi phát ra cảnh báo, nhưng nó không biết chuỗi đối tượng cuối cùng sẽ khiến hành vi xảy ra. Tương tự như vậy, trái tim không biết adrenaline đến từ đâu,

Vì vậy, trong ví dụ ( đơn giản hóa ) này, đối tượng tuyến thượng thận chỉ cần biết cách lấy ACTH và tạo ra adrenaline. Nó không cần bất kỳ lĩnh vực nào để làm điều đó, nhưng nó vẫn có vẻ như là một đối tượng với tôi.

Bây giờ nếu ứng dụng của chúng tôi được thiết kế chỉ để chạy nước rút trên đường phố, tôi có thể không cần tuyến yên và các đối tượng tuyến thượng thận. Hoặc tôi chỉ cần một đối tượng tuyến yên chỉ thực hiện một phần nhỏ của những gì chúng ta có thể xem là "mô hình tuyến yên". Tất cả các khái niệm này tồn tại dưới dạng các thực thể khái niệm, nhưng đó là phần mềm và chúng tôi có thể tạo AdrenalineSender hoặc MuscleContractor hoặc bất cứ điều gì và không phải lo lắng nhiều về "tính không hoàn chỉnh" của mô hình của chúng tôi.


4
Tôi đồng ý với nội dung thực tế của câu trả lời này, nhưng tôi cảm thấy như nó hiểu sai câu hỏi. Cụ thể, câu hỏi bao gồm trong thực thể "hoặc một khái niệm, một cái gì đó được xác định rõ". Ví dụ ngược lại với điều này là " MotorOperationshoặc MotorActions". Từ điều này, tôi khá tự tin rằng cả thiết kế lớp gốc lớp cuối cùng từ ví dụ CoffeeMaker đều thuộc định nghĩa "đại diện cho một thực thể" của OP
Ben Aaronson

1
Kiến trúc hệ thống hậu hiện đại DCI xử lý việc này mà không có sự trừu tượng hóa cực độ được tạo ra bởi các kỹ sư yêu cấu trúc. Máy tính nên nghĩ những gì người dùng đang nghĩ, không phải là cách khác. fulloo.info/doku.php?id=what_is_dci
ciscoheat

@BenAaronson Tôi cảm thấy như bạn có thể phát triển đối tượng đó như một khái niệm gắn kết với nỗ lực phối hợp đủ, nhưng tôi đã tìm thấy một xu hướng tập trung vào thực thể để buộc mọi thứ phải tách rời nhau. Các thực thể khuyến khích các ranh giới trong tên của chúng tôi, điều này là tốt, nhưng chúng cũng mang theo khái niệm về tính đúng đắn / đầy đủ, có xu hướng bị tổn thương. Trong các điều khoản vô lý nhất, tôi dành cho một đối tượng FirstNameValidator và chống lại một đối tượng Tên cũng xác thực cho tên và họ.
Steve Jackson


2
Đối tượng là về tin nhắn - câu trả lời của Steve Jackson - điều này hoàn toàn đúng. MOP không có nghĩa là "nhắn tin" như được nghĩ bởi Cha của OO Alan Kay , người cho biết ý tưởng lớn là nhắn tin . Và hơn nữa, tôi xin lỗi vì từ lâu tôi đã đặt ra thuật ngữ "đối tượng" cho chủ đề này bởi vì nó khiến nhiều người tập trung vào ý tưởng ít hơn.
radarbob 11/07/2015

21

Các lớp có thể đại diện cho các đối tượng không có thực thể? Nếu không, tại sao họ xấu / không đầy đủ / không OOP-centric? Có những cách họ cần phải được thay đổi / cải thiện?

Nói tóm lại, bạn có thể làm bất cứ điều gì, nhưng kịch bản cụ thể này sẽ trái với các nguyên tắc OOP :)

Những gì bạn đang mô tả đôi khi được gọi là lớp "tiện ích" - thường là dấu hiệu của mùi mã. Bạn muốn tránh tạo các lớp vì mục đích giữ một số phương thức cùng nhau.

Không phải mọi đối tượng trong ứng dụng của bạn phải được liên kết với một thực thể ngoài đời thực như xe máy hoặc xe hơi; Đó là những đối tượng kinh doanh. Trong ứng dụng của bạn, bạn có thể sử dụng nhiều đối tượng kinh doanh của mình, nhưng bạn cũng sẽ cần thêm một số cách ly cho các hoạt động khác không phải là một phần của các thực thể kinh doanh, như các đối tượng bạn đã liệt kê.

Bạn nên xem qua các mẫu kiến ​​trúc phổ biến - một trong số đó là MVC (Model-View-Controller) .

Nếu tôi phân phối các phương thức bạn đã liệt kê bằng MVC, đây là những gì tôi sẽ làm:

Xem lớp:

  • GetMotorDataFromHTMLForm ()

Lớp mẫu (Cơ bản về động cơ):

  • Nhà sản xuất GetMotor ()
  • CanMotorHandleOperationConditions ()
  • Tính năng lượng tiêu thụ ()

Lớp điều khiển (MotorsContoder):

  • Get ALLMotors ()
  • GetMotorById ()
  • GetMotorByUserRequirements ()

Có vẻ như bạn đang sử dụng PHP; một khung MVC tốt để có một cái nhìn là Laravel . Trong các ví dụ của họ, họ minh họa tốt nơi các phương pháp thuộc về.

Một nguồn thông tin chung chung khác làm thế nào để quyết định các phương thức thuộc về các nguyên tắc GRASPRẮN .


cảm ơn. Về bản chất, đối với tôi, những gì tôi có là một lớp Trình điều khiển với một vài tạp chất được trộn lẫn trong (Model, View, v.v.). Điều đó có nghĩa rằng nếu tôi đổi tên MotorOperationsđể MotorsControllervà làm sạch nó lên một chút, tôi tập hợp các chức năng sẽ phù hợp với OOP?
Dennis

@Dennis, Không nhất thiết, hãy xem bộ sưu tập các phương thức của tôi dưới mỗi lớp. Trình điều khiển không phải là một lớp chứa tất cả :) Đó là lớp có hoạt động trên các mô hình của bạn và không có gì nữa. Các phụ thuộc duy nhất của bộ điều khiển thường là DAL (Lớp truy cập dữ liệu) trực tiếp hoặc các dịch vụ cung cấp cho bạn quyền truy cập vào DAL. Bạn không bao giờ muốn truy cập View từ bộ điều khiển (ví dụ: getMotorDataFromHTMLForm), thay vào đó, View của bạn phải là một phụ thuộc vào bộ điều khiển.
Alexus

2
Bạn có thể giải thích lý do tại sao một Utilslớp sẽ là một ví dụ về mùi mã? Chỉ tò mò, vì bản thân tôi rất thích có các hàm sử dụng ngẫu nhiên được bao bọc trong một Utilslớp chứ không phải là các hàm độc lập ... theo kinh nghiệm của tôi, nó làm cho mã dễ đọc hơn một chút, nhưng kinh nghiệm của tôi bị hạn chế.
HC_ 7/07/2015

3
@HC_ Có một lớp Utils giống như có thư mục "Misc" trong bộ sưu tập ảnh của bạn. Nó chỉ ra rằng bạn lười biếng phân công trách nhiệm cho các đối tượng của mình đúng cách / có khả năng thiếu các đối tượng và sử dụng Utils để bù đắp cho điều đó. Có một chỗ cho các lớp Util, đặc biệt là với các hàm tĩnh và phần mở rộng cho các lớp khác, nhưng trước khi bạn tạo một bộ sưu tập như vậy, hãy kiểm tra xem bạn có thể kết hợp chúng vào các lớp OOP thích hợp của mình không :) Một lý do khác đôi khi một lớp chỉ có thể có một phương pháp. Nhưng về phía trước, bạn cần thêm nhiều hơn và lớp Utils trở thành một mớ hỗn độn lớn hơn.
Alexus

Tôi thường kết thúc với THƯ VIỆN Utils, nhưng tôi thường cố gắng nhóm và đặt tên cho các lớp utils của mình một cách mô tả hơn một chút. Ngày nay, có rất nhiều thư viện "tiện ích chung" nguồn mở ngoài kia đã có các tiện ích mục đích chung mà hầu hết mọi người cần, vì vậy tôi sẽ tìm hiểu một chút trước khi tự viết.
Guy Schalnat

15

Các lớp có thể đại diện cho các đối tượng không có thực thể?

Có thể? Đúng. Nên? Có lẽ là không - hoặc ít nhất, không phải là cách bạn diễn đạt mọi thứ.

Các đối tượng thực sự là tốt nhất khi không đại diện trực tiếp cho một đối tượng vật lý vì thực tế thường xuyên ánh xạ mã độc đáo. Nhưng họ cần phải đại diện cho một khái niệm gắn kết hoặc đối tượng mã. Họ cần phải đại diện cho một trách nhiệm gắn kết duy nhất.

Chỉ cần kết hợp một loạt các hàm liên quan tiếp tuyến với nhau là một không gian tên hoặc mô-đun - không phải là một đối tượng theo cách nói OOP. Chúng có thể hữu ích, nhưng chúng không giống nhau và đòi hỏi một cách sử dụng / suy nghĩ khác nhau để hoạt động hiệu quả.


3
bundling a bunch of tangentially related functions together is a namespace: nghe có vẻ giống mô hình thủ tục hơn là hướng đối tượng.
Dennis

@dennis - chính xác (hoặc chức năng nếu bạn gọi nó là Mô-đun). Trộn các mô hình có thể mạnh mẽ. Hoặc nó có thể là lộn xộn khủng khiếp.
Telastyn 7/07/2015

Hoặc cả hai :) - - - - -
Alexus

@Dennis: Hoặc không - kết hợp với nhau chỉ các chức năng liên quan là một thực tiễn đáng ngờ trong bất kỳ mô hình nào.
sdenham

Tôi đang xử lý mã bắt đầu như một cơ sở mã thủ tục. Tại một số thời điểm, một nỗ lực để chuyển đổi nó thành OOD đã được thực hiện, nhưng, hầu hết các lớp được tạo ra để "giữ các chức năng và phương thức", mà không có bất kỳ thiết kế OO thực tế nào. Tôi đã khám phá ra khá nhiều điều như thế này cố gắng thu hẹp khoảng cách giữa các mô hình nhưng không phải ở cái này hay cái kia
Dennis

11

Một lớp nên mô hình hóa một cái gì đó - nếu không nó là vô nghĩa. Tuy nhiên, những gì đang được mô hình hóa có thể không phải là một "vật"; thay vào đó, nó có thể là một đại diện của một cái gì đó không phải là 'thực', nhưng cần thiết để kiểm soát hệ thống được mô hình hóa. Ví dụ, trong một hệ thống điều khiển đèn giao thông, bạn rất có thể có một loại lớp ControlSignal, đại diện cho một tín hiệu được gửi từ một phần của hệ thống đến một phần khác để chỉ ra rằng một số hành động cần phải được thực hiện. Trong "thế giới thực", các tín hiệu này có thể bao gồm các xung điện được truyền qua các dây từ hộp này sang hộp khác. Quá trình mô hình hóa một cái gì đó không "thực" như một đối tượng cụ thể được gọi là "sự thống nhất".

May mắn nhất.


Đúng, đó gần như chính xác là những gì tôi đã nói. Một lớp không có gì khác hơn là một mô hình cho một danh từ . Đó là nó. Không hơn không kém. Một lớp là một danh từ và các phương thức là động từ (hoặc tin nhắn nếu bạn thích). Một kỹ sư cơ sở nghĩ theo những thuật ngữ đơn giản đó có thể đi một chặng đường dài trước khi những sự tương tự đó bị phá vỡ (không giống như cố gắng giả vờ rằng các lớp là mô tả của các đối tượng vật lý - một sự tương tự bắt đầu bị phá vỡ trong gần như dự án đầu tiên của bạn).
Calphool

7

Không. (Tiêu đề được chỉnh sửa để đặt câu hỏi ngược lại!)

ví dụ:

Public class MyRepository
{
    public MyObject GetObject(string id)
    {
        //get data from the DB and build an object
    }
}

hoặc là

Public class MyService
{
    public MyObject3 ProcessData(MyObject1 obj1, MyObject2 obj2)
    {
         //perform a process which is not a sole responsiblity of obj1 or obj2
    }
}

Tuy nhiên, nói chung, lý tưởng đằng sau OOP là tránh xa

public struct Car
{
    public Wheel[] Wheels;
}

public int CountWheelsOnCar(MyCarStruct car)
{
   return car.Wheels.Length;
}

đến

public class Car
{
    private Wheel[] wheels;
    Public int CountWheels()
    {
        return this.wheels.Length;
    }
}

Bạn có nghĩa là họ có thể đại diện cho các đối tượng không có thực thể? (Xem bình luận tôi để lại câu hỏi.)
Panzercrisis

3
Tôi đã lập trình OO quá lâu tôi đoán - khi tôi nhìn vào MyRep repository, tôi lập tức hình dung ra một cái bát thủy tinh trên tủ quần áo của tôi với một đống tiền xu và tào lao trong đó. Tiếp cận và lấy ra một xu, hoặc một nút ....
Bill K

@pan có, như dịch vụ và repo trong ví dụ của tôi
Ewan

@bill bạn già điên khùng !!! Đó là lớp MyButtonAndOrPennyBowl! mã hóa sạch ftw
Ewan

1
Ví dụ thứ hai của bạn trông giống như một hàm được hóa trang thành một đối tượng, mà theo tôi không phải là hợp lý, mặc dù có thể có một số biện minh khác (ví dụ: nếu các hàm không phải là thực thể hạng nhất trong ngôn ngữ. )
sdenham

5

Tôi nghĩ rằng hình dung một cái gì đó trong thế giới thực là hữu ích khi các lớp mã hóa nhưng không cần thiết.

Trong thực tế, tùy thuộc vào mức độ bạn muốn trở thành nghĩa đen, nhiều đối tượng chúng ta làm việc không có đại diện vật lý nào cả. Ví dụ - xem xét kiến ​​trúc MVC. Trong thế giới thực, không có Model hoặc Trình điều khiển mặc dù chúng thường được đại diện bởi các lớp. Cả ba thường đại diện cho một cái gì đó, nhưng không phải lúc nào cũng vậy - nhưng như tôi đã nói, bạn có thể buộc phải phù hợp với thứ gì đó nếu bạn thực sự muốn (và có thể tưởng tượng SOMETHING giúp! Tôi hình dung hầu hết các đối tượng theo một cách nào đó - không phải là bất cứ điều gì bạn đã từng thấy trong thế giới thực).

Hầu hết các "Quy tắc" mà bạn sẽ tìm hiểu về OO chỉ là những hướng dẫn nhằm giúp bạn định hướng suy nghĩ trong OO không nhất thiết là những điều bạn lo lắng nhiều khi bạn sử dụng nó để viết mã hàng ngày.

Theo cách này, bản thân OO không phải là thuốc chữa bách bệnh và nó không giúp ích gì cho bạn trong lần đầu tiên vượt qua giải pháp mã hóa, nhưng tôi nghĩ rằng nếu được thực hiện đúng thì đó là một cách thực sự tuyệt vời để tổ chức mã để nó có thể hơn dễ hiểu sau này Viết mã có thể bảo trì có lẽ là một trong những nhiệm vụ khó khăn nhất trong phát triển phần mềm và trong nhiều trường hợp (bất cứ điều gì đòi hỏi phải gỡ lỗi / bảo trì liên tục) thì đó là điều quan trọng nhất.


5

Có một đối tượng phải đại diện cho một thực thể?

Câu hỏi: Thực thể nào Loggerđại diện?

Không ẩn dụ - theo nghĩa đen.

Khi giải thích OOP cho sinh viên, thật hữu ích khi giải thích các đối tượng có sự tương đồng với thế giới vật lý.

Alan Kay - một trong những người cha của OOP - đã viết như sau:

[...]

Các quan niệm ban đầu của nó có các phần sau đây.

  • Tôi nghĩ rằng các đối tượng giống như các tế bào sinh học và / hoặc các máy tính cá nhân trên mạng, chỉ có thể giao tiếp với các tin nhắn
  • Tôi muốn thoát khỏi dữ liệu.

[...]

OOP với tôi có nghĩa là chỉ nhắn tin, duy trì và bảo vệ địa phương và

che giấu quá trình nhà nước, và cực kỳ ràng buộc muộn của tất cả mọi thứ.

kiến trúc CT gần như không thể tin được. Tôi nhận ra rằng

ẩn dụ tế bào / toàn máy tính sẽ loại bỏ dữ liệu

nguồn

Từ đó, các đối tượng được hiểu rõ nhất là

  • đối tượng autarkic đóng gói / ẩn dữ liệu

  • giao tiếp với các đối tượng khác qua tin nhắn

Các lớp có thể đại diện cho các đối tượng không có thực thể?

Chắc chắn: Hãy nghĩ về Math


Về ví dụ của bạn:

Ví dụ: một lớp có thể được gọi là MotorOperations hoặc MotorActions, trong đó không có thực thể, nhưng các phương thức bên trong lớp thực hiện những việc như

  • getMotorDataFromHTMLForm ()

  • getMotorSản xuất ()

  • selectMotorFromUserRequirements ($ yêu cầu)

  • canMotorCanHandleOperatingConditions ($ condition)

  • computePowerConschargeForMotor ($ id)

Để quyết định, nơi để đặt các phương pháp này, bạn phải xem xét responsibilities: ai chịu trách nhiệm cho những gì .

getMotorDataFromHTMLForm ()

Bối cảnh của một phương pháp như vậy sẽ là xây dựng một đối tượng động cơ . Nó không phải là trách nhiệm của động cơ để tạo ra chính nó từ dữ liệu lấy thông qua một hình thức . Có ít nhất hai đối tượng liên quan; một là động cơ và một là người tạo ra động cơ .

getMotorSản xuất ()

Bối cảnh điển hình trong đó người ta sẽ viết một phương pháp như vậy là a service.

selectMotorFromUserRequirements ($ yêu cầu)

Điều này cũng sẽ được sử dụng trong một service-ext

canMotorCanHandleOperatingConditions ($ condition)

Đây là một câu hỏi cho một motor-object

computePowerConschargeForMotor ($ id)

Đây cũng là một câu hỏi tốt nhất hỏi một động cơ chính nó.


tl; dr

Phép ẩn dụ objectsnhư các vật thể vật lý gây khó chịu hơn là hữu ích.


wow câu trả lời của bạn mang hơi thở cuộc sống vào OOP! Tôi phải nói rằng tôi không có ý nói về thể chất như là kết thúc tất cả. mục đích của câu hỏi của tôi là "một đối tượng phải là một thingdữ liệu trong đó dữ liệu rõ ràng thuộc về sự vật và chức năng hoạt động rõ ràng trên dữ liệu thuộc về sự vật". Vì vậy, Logger trong trường hợp này, mặc dù không phải là một vật lý, nó là một khái niệm gần giống với "sổ nhật ký vật lý". Liệu nó có dữ liệu là cốt lõi đối với trạng thái của nó hay không và không chỉ là nhất thời với nó, điều đó có thể phụ thuộc vào việc thực hiện và giải thích .. và hơn nữa là câu hỏi của tôi sẽ đi đâu ..
Dennis

nhưng vâng, câu trả lời phải giải quyết sự thiên vị về thể chất của tôi
Dennis

3

Vâng, bạn có thể làm điều này. Nhưng về cơ bản, bạn đang tạo một lớp để cung cấp chức năng tương tự như một thư viện thủ tục. Lý do duy nhất để làm điều đó là nếu ngôn ngữ của bạn thiếu các mô-đun thủ tục (ví dụ: Java hoặc Ruby).

Trong một ngôn ngữ với các mô-đun thủ tục (tôi nghĩ PHP có các mô-đun thủ tục), bạn có thể xem xét chỉ sử dụng một mô-đun thủ tục.

Bạn cũng có thể xem xét việc thiết kế lại lớp của mình để một thể hiện của lớp đại diện cho một đối tượng mạch lạc.

Nhưng chỉ sử dụng ký hiệu OO khi nó mang lại cho bạn thêm sức mạnh, không chỉ vì mục đích là OO!


3

Theo lời của giáo dân

  • Những gì bạn mô tả được gọi là một lớp tiện ích.
  • Nó không có trạng thái, có nghĩa là bạn sẽ không bao giờ thực sự cần phải có một vài trường hợp của nó
  • Tất cả các phương thức là tĩnh, có nghĩa là bạn phải truyền mọi thứ dưới dạng tham số

Các lớp như vậy tồn tại, ví dụ SDK Java có lớp Bộ sưu tập chỉ bao gồm các phương thức tĩnh hoạt động trên hoặc trả về các bộ sưu tập.

Vì vậy, câu trả lời sẽ là không, không phải tất cả các lớp cần được mô hình hóa từ một thực thể miền.

Mặt khác, các lớp như vậy chỉ là một vài hoặc chỉ là một số ít trong một chương trình được thực hiện bằng ngôn ngữ OOP, vì sức mạnh thực sự của OOP nằm ở tính đa hình và đóng gói.

Nó sẽ giống như sử dụng một chiếc máy bay để đi từ nơi này đến nơi khác không phải bằng cách bay mà bằng cách lái nó trên đường cao tốc. Máy bay có bánh xe giống như ô tô, nhưng chúng dự định bay.


2

Không, một lớp chỉ đại diện cho thứ gì đó có thể được khởi tạo, có thành viên và có thể được kế thừa từ đó.

Trong thực tế, ngôn ngữ của bạn có thể có các lớp tĩnh, thậm chí không được khởi tạo nhiều lần.

.NETMath là một ví dụ tuyệt vời về lớp "chuyên nghiệp" không đại diện cho thực thể (trừ khi bạn muốn hiểu triết học về toán học là gì ...), và cũng xảy ra để minh họa trường hợp sử dụng hợp pháp của lớp đó. Nó chỉ có các phương thức và 2 trường (cả hai đại diện cho các hằng số riêng lẻ).

Hệ thống phân cấp lớp của một thư viện tương tự Math.Net, nhóm các phương thức toán học / số thành các lớp theo loại. Ở đây các lớp không đại diện cho một thực thể, mà là một phạm trù logic.

Bản thân tôi thường kết thúc việc tạo các lớp (tĩnh) không gì khác hơn là một túi các hàm liên quan (tĩnh) hoặc một nhóm các hằng số được nhóm một cách thuận tiện ở một vị trí trung tâm. Tôi sẽ không cho rằng đây là thiết kế tốt, nhưng đôi khi nó là giải pháp đơn giản nhất.


1
Thực tế là các phương thức liên quan đến toán học được đặt trong .NET / BCL vào một lớp riêng vì các phương thức tĩnh không phải là một điều cần thiết hoặc xem xét thiết kế mà là hậu quả của một thực tế là không có phương thức tự do trong C #. Trong C ++, các hàm như vậy có thể được nhóm lại thành một không gian tên.
Vlad

1

Các câu trả lời cho câu hỏi của bạn cuối cùng xoay quanh việc người ta định nghĩa chính xác các thuật ngữ như "lớp" và "thực thể". Bạn đã làm rất tốt việc xác định cái sau, cho phép cả hai thực thể vật lý và khái niệm. Nhưng thuật ngữ "đẳng cấp" đối với những người theo chủ nghĩa thuần túy sẽ luôn là "một nhà máy sản xuất các đối tượng có biểu hiện bên trong cụ thể" và đối với những người theo chủ nghĩa thực dụng, thuật ngữ này sẽ bao hàm những thứ Java hoặc C ++ mà những người theo chủ nghĩa thuần túy coi thường. Ditto cho thuật ngữ "OOP", mà những người theo chủ nghĩa thực dụng có thể nói Java và C ++ làm, nhưng những người theo chủ nghĩa thuần túy sẽ hiểu ý của Alan Kay khi ông nhận xét ["Tôi đã phát minh ra thuật ngữ hướng đối tượng và tôi có thể nói với bạn rằng tôi đã không có C ++ trong tâm trí "] ( Vậy * đã làm gì * Alan Kay thực sự có nghĩa là gì bởi thuật ngữ" hướng đối tượng "? ).

Nếu bạn có quan điểm thực dụng, bạn có thể chấp nhận các lớp tiện ích không có cá thể của bạn. Nhưng quan điểm thuần túy là thú vị hơn. OOP, theo Kay, luôn thiên về các thông điệp hơn là các lớp học. Vì vậy, câu hỏi của bạn:

Các lớp có thể đại diện cho các đối tượng không có thực thể?

Số Lớp phân loại đối tượng. Các lớp theo định nghĩa các thực thể mà bạn gửi một thông điệp như newđể tạo ra một đối tượng. Một đối tượng là một thực thể được tạo ra từ một lớp. Các lớp tồn tại để sản xuất, và thực sự phân loại các đối tượng. Đó là những gì các lớp học làm. Các lớp làm đối tượng. Chúng tôi sử dụng các lớp để phân loại các đối tượng. Vì vậy, nếu C chỉ là một nhóm các phương thức không cho phép khởi tạo hoặc phân lớp, thì không thể có bất kỳ đối tượng nào được phân loại theo C, vì vậy C không phải là một lớp.

Nếu không, tại sao họ xấu / không đầy đủ / không OOP-centric?

Chúng không tệ. Đừng gọi họ là lớp học. Một bó các phương thức OOPable: một cái gì đó bạn có thể gửi tin nhắn để gọi một phương thức, nhưng nó không phải là một lớp trừ khi nó có thể khởi tạo một đối tượng. Bạn có biết Ruby không? Trong Ruby một mô-đun là một bó các phương thức. Một lớp là một mô-đun có thể khởi tạo các đối tượng. Không có gì xấu về một mô-đun . Nhưng điều làm cho một lớp khác với một mô-đun (theo thuật ngữ OOP thuần túy) là một lớp có thể có các thể hiện. Một mô-đun chỉ là một số phương pháp. Sự nhầm lẫn là C ++ và Java và các ngôn ngữ khác sử dụng thuật ngữ "lớp" cho cả lớp và mô-đun .

Bây giờ, để xem xét một trong những ví dụ cụ thể của bạn, bạn hỏi về một MotorOperationslớp mà bạn có thể gửi tin nhắn computePowerConsumptionForMotorvới đối số id. Nó có tệ không? Ít nhất là nó không vi phạm Nguyên tắc Đừng hỏi . Chúng ta phải tạo một lớp động cơ và gửi powerConsumptiontin nhắn không? Có thể không phải 100% thời gian, nhưng có lẽ cố gắng làm những việc như vậy sẽ dẫn đến một số hiểu biết tốt đẹp về mã của bạn. Hoặc, nó có thể dẫn đến một vụ nổ của các lớp nhỏ sẽ là xấu.

Có những cách họ cần được thay đổi / cải thiện về mặt khái niệm để phù hợp với OOP?

Nếu "làm OOP" là quan trọng đối với bạn, thì bạn sẽ muốn tìm cách để kiến ​​trúc sư một hệ thống thành các thành phần giao tiếp bằng cách gửi tin nhắn cho nhau. Đó chỉ là những gì OOP , hoặc ít nhất là những gì coiner của thuật ngữ này có trong tâm trí. Các lớp tiện ích không phải là OOP trong quan điểm này. Nhưng với một số người, họ có thể.

Cố gắng tạo ra toàn bộ hệ thống lớn từ hàng triệu sinh vật, hơi thở, vật thể, tất cả được tạo ra từ các lớp học, có thể hoạt động cho một số dự án. Nhưng nếu bạn thấy mình tạo ra các lớp nhân tạo, nghe sai, thì các mô-đun nên được giới thiệu. Cố gắng nhấn mạnh các lớp và sử dụng các mô-đun khi các lớp khả thi sẽ là vô lý.

TL; DR - các gói phương thức không phải lúc nào cũng xấu. Hãy thử sử dụng các lớp khả thi trước. Chỉ quay lại "mô-đun" khi cần.


0

Lấy các ví dụ đã cho:

getMotorDataFromHTMLForm()
selectMotorFromUserRequirements($requirements)

Chúng trông giống như các phương thức "nhà máy", sẽ trả về một Motorđối tượng. Thứ hai ngụ ý rằng bạn đang tạo một đối tượng mới để đáp ứng các yêu cầu hoặc bạn có cơ sở dữ liệu hoặc bộ sưu tập động cơ trong bộ nhớ mà bạn đang kiểm tra. Trong trường hợp đó nên là một phương pháp trên đó. Hoặc nó có thể là một phương thức trên đối tượng yêu cầu.

getMotorManufacturers()

Bạn lấy chúng từ đâu? Đó là những gì nên là một phương pháp.

canMotorCanHandleOperatingConditions($conditions)
computePowerConsumptionForMotor($id)

Chúng trông giống như chúng nên là phương pháp trên Motor.


Đúng. nó là một "gói các phương thức có thể không liên quan" (gọi tắt là BOPUM). Tôi đồng ý với ý kiến ​​của Nhà máy và Động cơ. getMotorManufacturerslà để trả lại tất cả các nhà sản xuất động cơ từ cơ sở dữ liệu. Tôi không chắc chắn nơi đó đi. Tôi sẽ mất một chút thời gian để làm sáng tỏ BOPUM này để đặt những thứ họ cần đến ..
Dennis

Tôi đang nhận được getMotorManufacturerstừ cơ sở dữ liệu. Cơ sở dữ liệu không thể có phương thức ... Hiện tại tôi có mẫu DataMapper truy vấn cơ sở dữ liệu, khởi tạo một mảng và điền nó với Motor Object (cũng chứa thông tin Nhà sản xuất), sau đó trả lại mảng đó cho người gọi. Người gọi là MotorOperationslớp của tôi , đến lượt nó được gọi từ một ProductSelectionlớp (chứa thuật toán được sử dụng để chọn Động cơ và thông tin động cơ được tải là dữ liệu cho thuật toán đó)
Dennis

0

Một đối tượng là một tập hợp các phương thức và dữ liệu có độ gắn kết cao. Họ thuộc về một lớp vì họ có liên quan với nhau rất cao và nhà nước được giữ lại.

Điều này đúng cho dù bạn sử dụng thiết kế lớn lên phía trước và cố gắng mô hình hóa mọi thứ, hoặc thiết kế nổi dần nơi bạn lặp lại và phát triển đối tượng thành bất cứ điều gì phù hợp với nhu cầu của hệ thống tại thời điểm đó.

Nếu bạn không có lý do để duy trì trạng thái, có lẽ bạn không có bất kỳ lý do nào để khởi tạo một đối tượng, điều đó có nghĩa là có lẽ không có lý do gì để có một lớp. Trừ khi, ngôn ngữ bạn sử dụng không có khả năng xác định không gian tên ngoài việc sử dụng lớp. Trong đó sử dụng lớp sẽ tốt vì nó sẽ là thành ngữ.

Tôi không thể nghĩ về bất kỳ khía cạnh tiêu cực nào đối với việc sử dụng các lớp theo cách này ngoài cách điển hình. Việc mời chi phí và sự phức tạp không cần thiết của bạn bằng cách phải khởi tạo một "không gian tên". Bất cứ ai hỗ trợ mã này sẽ tự hỏi nơi dữ liệu có chi phí tải nhận thức bổ sung (rất có thể là chi phí một lần cho mỗi người). Đó là một cách sử dụng bất thường mà không có bất kỳ giá trị bổ sung.

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.