Bạn có thể thực hiện lập trình hướng đối tượng của Wikipedia mà không cần từ khóa lớp không?


29

Giả sử chúng tôi muốn cung cấp một bản tóm tắt của một "tài khoản" trong ngân hàng. Đây là một cách tiếp cận, sử dụng một functionđối tượng trong Python:

def account():
    """Return a dispatch dictionary representing a bank account.

    >>> a = account()
    >>> a['deposit'](100)
    100
    >>> a['withdraw'](90)
    10
    >>> a['withdraw'](90)
    'Insufficient funds'
    >>> a['balance']
    10
    """
    def withdraw(amount):
        if amount > dispatch['balance']:
            return 'Insufficient funds'
        dispatch['balance'] -= amount
        return dispatch['balance']
    def deposit(amount):
        dispatch['balance'] += amount
        return dispatch['balance']
    dispatch = {'balance': 0,
                'withdraw': withdraw,
                'deposit': deposit}
    return dispatch

Đây là một cách tiếp cận khác sử dụng trừu tượng kiểu (nghĩa là classtừ khóa trong Python):

class Account(object):
    """A bank account has a balance and an account holder.

    >>> a = Account('John')
    >>> a.deposit(100)
    100
    >>> a.withdraw(90)
    10
    >>> a.withdraw(90)
    'Insufficient funds'
    >>> a.balance
    10
    """



    def __init__(self, account_holder):
        self.balance = 0
        self.holder = account_holder

    def deposit(self, amount):
        """Add amount to balance."""
        self.balance = self.balance + amount
        return self.balance

    def withdraw(self, amount):
        """Subtract amount from balance if funds are available."""
        if amount > self.balance:
            return 'Insufficient funds'
        self.balance = self.balance - amount
        return self.balance

Giáo viên của tôi bắt đầu chủ đề "Lập trình hướng đối tượng" bằng cách giới thiệu classtừ khóa và cho chúng tôi thấy những gạch đầu dòng:

Lập trình hướng đối tượng

Một phương pháp để tổ chức các chương trình mô-đun:

  • Rào cản trừu tượng
  • Thông qua
  • Kết hợp thông tin và hành vi liên quan

Bạn có nghĩ rằng cách tiếp cận đầu tiên sẽ đủ để đáp ứng định nghĩa trên? Nếu có, tại sao chúng ta cần classtừ khóa để lập trình hướng đối tượng?


2
Vui mừng bạn đồng ý. =) Mặc dù tôi không biết Python đủ để đưa ra câu trả lời thấu đáo, nhưng bạn có thể thích thú khi biết rằng trong Javascript, cách làm OOP điển hình tương tự như "đối tượng hàm" mà bạn mô tả (mặc dù chúng tôi cũng có sự kế thừa nguyên mẫu cho phép các đối tượng "chia sẻ" các phương thức thay vì có các bản sao riêng biệt của từng phương thức trên mỗi đối tượng; tôi giả sử Python classthực hiện một tối ưu hóa tương tự).
Ixrec

Nếu bạn muốn có câu trả lời chi tiết, bạn nên hỏi một câu hỏi khác hoặc tham gia phòng trò chuyện, nhưng câu trả lời ngắn gọn là (nếu bạn hoàn toàn bỏ qua kế thừa nguyên mẫu, mảng, v.v.) về cơ bản là đúng; hầu hết các đối tượng JS không là gì ngoài từ điển của các khóa chuỗi đến các giá trị tùy ý. foo.bar()thường giống hệt foo['bar']()và trong các trường hợp hiếm hoi, cú pháp sau thực sự hữu ích.
Ixrec


8
Đây là một câu hỏi thực sự quan trọng trên con đường tìm hiểu cơ bản về OOP. Nếu bạn quan tâm, bạn có thể đọc một bài đăng trên blog của tôi nơi tôi tạo một hệ thống đối tượng đơn giản bằng JavaScript mà không cần dựa vào bất kỳ phần OOP nào của ngôn ngữ. Ví dụ đầu tiên của bạn có một thiếu sót quan trọng: Nơi bạn viết object['method'](args), các đối tượng Python thực sự tương đương với object['method'](object, args). Điều này trở nên có liên quan khi một lớp cơ sở gọi các phương thức trong một lớp con, ví dụ như trong Mẫu chiến lược.
amon

13
Như những người khác đã lưu ý, đây là một câu hỏi cảm nhận về OOP. Tuy nhiên, tôi sẽ nhân cơ hội này để lưu ý rằng đây hoàn toàn không phải là cách các ngân hàng thực sự đại diện cho các tài khoản ngân hàng. Các ngân hàng không có đối tượng "tài khoản" có thể thay đổi mà bạn thay đổi khi ghi nợ và ghi có; họ có danh sách các giao dịch chỉ viết và sau đó tính toán số dư từ danh sách các giao dịch. Là một bài tập tốt, hãy thử thực hiện cơ chế đó bằng nhiều ngôn ngữ khác nhau.
Eric Lippert

Câu trả lời:


66

Xin chúc mừng! Bạn đã khám phá lại một thực tế nổi tiếng rằng việc định hướng đối tượng có thể được thực hiện mà không cần hỗ trợ ngôn ngữ lập trình cụ thể. Về cơ bản, nó giống như cách các đối tượng được giới thiệu trong Scheme trong cuốn sách văn bản cổ điển này . Lưu ý rằng Lược đồ không có classtừ khóa hoặc một số loại tương đương và các đối tượng có thể được tạo mà không cần có các lớp.

Tuy nhiên, mô hình hướng đối tượng đã thành công đến mức có rất nhiều ngôn ngữ - và Python cũng không ngoại lệ - cung cấp hỗ trợ tích hợp cho nó. Điều này chỉ đơn giản là để giúp các nhà phát triển sử dụng mô hình dễ dàng hơn và cung cấp một hình thức định hướng đối tượng tiêu chuẩn cho ngôn ngữ đó. Về cơ bản, đó là cùng một lý do tại sao nhiều ngôn ngữ cung cấp một forvòng lặp, mặc dù nó có thể được mô phỏng bằng cách sử dụng một whilevòng lặp chỉ với một hoặc hai dòng mã bổ sung - đơn giản là dễ sử dụng .


"Để cung cấp một hình thức định hướng đối tượng tiêu chuẩn cho ngôn ngữ đó" Tôi có nghe thấy lời chỉ trích về JavaScript không? ;)
jpmc26

1
@ jpmc26: không cố ý. Và dường như có một số tiêu chuẩn được chấp nhận rộng rãi về cách các đối tượng được tạo trong JavaScript.
Doc Brown

@overexchange: bạn có câu hỏi nào không?
Doc Brown

1
@overexchange: Chà, ý nghĩa của OOP đang gây tranh cãi, có nhiều trường phái khác nhau, nhưng định nghĩa SICP khá giống với 3 điểm trong câu hỏi của bạn. Đây chắc chắn là về việc xây dựng các khái niệm trừu tượng, nhưng đừng quên các điểm 2 và 3. Vâng, khái niệm OOP bao gồm "thay đổi trạng thái", nhưng nó cũng cho phép khái niệm "các đối tượng bất biến" (như lớp chuỗi trong Java hoặc C #, Python có một số loại dữ liệu có thể thay đổi và một số loại bất biến là tốt). Và ví dụ đầu tiên của bạn trong câu hỏi của bạn xác nhận cho định nghĩa đó cũng như ví dụ thứ hai của bạn.
Doc Brown

2
@overexchange: điều này quay trở lại định nghĩa của Alain Kay về định hướng đối tượng (người phát minh ra ngôn ngữ nói chuyện nhỏ). Bạn sẽ tìm thấy một câu trả lời toàn diện trong stackoverflow.com/questions/2347973/ bài viết trước đây của SO. IMHO "thông điệp truyền giữa các đối tượng" theo nghĩa SICP chỉ có nghĩa là không truy cập trực tiếp dữ liệu bên trong của đối tượng, chỉ thông qua "giao thức truyền thông được xác định". Trong các ngôn ngữ OO như Python, điều này có thể chỉ có nghĩa là "gọi phương thức của đối tượng".
Doc Brown

13

Tôi đồng ý rằng định nghĩa đầu tiên thỏa mãn ba điểm mà giáo viên của bạn đưa ra. Tôi không nghĩ rằng chúng ta cần từ khóa lớp cho bất cứ điều gì. Dưới vỏ bọc, một đối tượng nào khác ngoài cấu trúc dữ liệu với các loại dữ liệu và chức năng khác nhau để làm việc với dữ liệu? Tất nhiên, các chức năng là dữ liệu là tốt ..

Tôi sẽ còn đi xa hơn và nói rằng việc lập trình hướng đối tượng không phụ thuộc quá nhiều vào các từ khóa mà ngôn ngữ của bạn cung cấp, bạn có thể thực hiện lập trình hướng đối tượng trong C nếu bạn muốn! Trong thực tế, nhân linux sử dụng các kỹ thuật như vậy.

Điều bạn có thể suy ra từ từ khóa ở đây là, ngôn ngữ cung cấp hỗ trợ cho loại cấu trúc này và bạn không cần phải thông qua tất cả các vòng để tự thực hiện lại chức năng (đây là nhiệm vụ khá thú vị trong chinh no!). Chưa kể tất cả các đường cú pháp bạn có thể nhận được là tốt.


thừa kế thì sao? Có phải chúng ta rất quan trọng về các kiểu con / siêu kiểu trong thời gian thực? Cách tiếp cận đầu tiên của tôi có thể không giải trí này !!
trao đổi quá mức

5
Kế thừa là không có cách nào cần thiết cho OOP. Bạn có thể thực hiện kế thừa trong ví dụ đầu tiên của bạn là tốt. Nó không quá "sạch" nhưng có thể giống nhau.
Zavior

3
@Zavior bình luận đó làm tôi nghĩ đến VB6. Đối tượng được định hướng mà không có sự kế thừa thực sự làm cho mã ít sạch hơn, để đặt nó nhẹ nhàng.
RubberDuck

1
@overexchange Khi bạn nghĩ về nó, kế thừa là tất cả về việc chia sẻ mã / hành vi chung giữa các lớp. Không có gì ngăn bạn lặp lại tất cả các mã đó mọi lúc. Sẽ là siêu khủng khiếp để duy trì mặc dù. Có một lý do tại sao thừa kế tồn tại :)
Zavior

1
@Zavior Ở dạng cơ bản nhất, "phân lớp" là một sự trừu tượng có nội dung "trước khi bạn trả về chức năng gửi và dữ liệu có thứ tự cao hơn mà tôi đang xác định ở đây (mà chúng ta sẽ giả vờ là" lớp "ha ha ha), khởi tạo chức năng điều phối và dữ liệu của 'siêu lớp' được gọi bởi ThisParentFoo ". Đó thực sự là tất cả. Khi nói đến đa thừa kế ngây thơ đó thực sự vẫn là tất cả, nhưng với lời cảnh báo mà bạn giới thiệu "vấn đề kim cương", đó là lý do tại sao nhiều thừa kế hút.
zxq9

9

Tất nhiên bạn có thể!

Ngôn ngữ lập trình tự là một ngôn ngữ hướng đối tượng dựa trên nguyên mẫu động, trong đó mọi thứ đều là đối tượng và không có ý nghĩa về các lớp hoặc bất cứ điều gì. Nó tập trung vào ý tưởng về các đối tượng nguyên mẫu và ý tưởng nhân bản chúng thay vì có các lớp làm khuôn mẫu về cách tạo đối tượng.

Bạn nên kiểm tra http://www.elfl Language.org/ để biết thêm thông tin. Tôi nghĩ nó rất thú vị và nếu bạn thích OOP, bạn nên kiểm tra thứ gì đó không phổ biến.


0

Không phải lúc nào: nó phụ thuộc vào ngôn ngữ. Bạn đã thể hiện khả năng thực hiện điều này trong Python nhưng (nếu câu hỏi của bạn có nghĩa là bất khả tri ngôn ngữ mặc dù thẻ Python) không phải tất cả các ngôn ngữ đều có thể làm điều này. Java, ví dụ, chủ yếu là không thể. Bỏ qua lớp có chứa chính, không có cách nào để xác định các phương thức / trường tùy ý trên một đối tượng được xác định trong chính mà không có từ khóa lớp. Mặc dù các lớp ẩn danh tồn tại nhưng chúng yêu cầu một giao diện và chúng không thể có bất kỳ thành viên nào ngoại trừ những lớp được định nghĩa trong giao diện. Mặc dù có thể định nghĩa các giao diện tùy chỉnh sau đó tạo các lớp ẩn danh cho chúng, nhưng điều này thực sự giống nhau (nhưng ít thuận tiện hơn) chỉ đơn giản là sử dụng một lớp.

Doc Brown có một câu trả lời tuyệt vời nhưng điểm tôi đang cố gắng đưa ra là tôi chắc chắn có ít nhất một ngôn ngữ sẽ không cho phép giải pháp của bạn.


Là người mới bắt đầu, để tìm hiểu khái niệm "Lập trình hướng đối tượng", vâng, tôi đang cố gắng trở thành bất khả tri ngôn ngữ. Tôi nghĩ rằng "Doc Brown" đã đưa ra câu trả lời trên cùng một dòng, anh ấy nói với tôi đọc sicp text-chap3, không liên quan gì đến bất kỳ cú pháp ngôn ngữ nào.
trao đổi quá mức vào

Tôi ước tôi sẽ đặt tên cho một ngôn ngữ hoàn toàn yêu cầu sử dụng các lớp để xác thực câu trả lời của tôi. Nhưng tôi chỉ biết một vài ngôn ngữ và than ôi Java cho phép làm việc xung quanh. C ++ có cấu trúc và Javascript phẳng cho phép những gì bạn thể hiện. Tôi nghi ngờ Smalltalk và Eiffel có thể yêu cầu lớp học vì tôi nghe nói chúng có cấu trúc chặt chẽ.
SkySpirus7

Như Doc Brown, nếu tôi đã học oop bằng cách sử dụng lược đồ, tôi sẽ không hỏi câu hỏi này. Thật không may, phiên bản của khóa học SICP mà tôi đang học sử dụng python.
trao đổi quá mức

1
Mọi chương trình Java hợp lệ phải chứa classtừ khóa để điều đó không gây nhiều bất ngờ. Nhưng bạn hoàn toàn có thể triển khai hệ thống đối tượng của riêng mình trên đầu hệ thống đối tượng của Java, mặc dù tôi không biết tại sao bạn muốn làm điều đó.
Brian Gordon

1. Java thực sự đặc biệt về vấn đề này, vì đơn giản là nó đã vứt bỏ tất cả các từ khóa khác có thể được sử dụng để tạo cấu trúc dữ liệu tùy chỉnh. Hầu như tất cả các ngôn ngữ khác mà tôi biết có hồ sơ hoặc đóng cửa. 2. Ngay cả trong java, bạn có thể lập trình trên bộ nhớ được xây dựng từ một mảng. Và bạn có thể thực hiện định hướng đối tượng trong đó, chỉ sử dụng classtừ khóa vì ngôn ngữ yêu cầu bạn đặt các chức năng của mình trong các lớp. Tất nhiên, điều này cực kỳ lý thuyết, nhưng ngay cả trong Java, bạn có thể thực hiện Định hướng đối tượng mà không cần các lớp dựng sẵn!
cmaster

0

Định nghĩa của giáo viên của bạn hoàn toàn bỏ lỡ điểm quan trọng nhất của lập trình hướng đối tượng, một điều làm cho nó hữu ích và độc đáo. "Tin nhắn đi qua" là một loạt những điều vô nghĩa được những người dân Smalltalk mơ ước, và đó là một thất bại ở mọi nơi mà nó đã được thử. Sức mạnh thực sự của OOP là một thứ được gọi là sự thay thế Liskov , và mặc dù khái niệm này khá đơn giản để mô tả và hiểu, nhưng việc triển khai cơ bản đủ phức tạp mà về cơ bản là không thể thực hiện được nếu không có sự hỗ trợ ở cấp độ ngôn ngữ.

Ý tưởng về sự thay thế Liskov là bất cứ nơi nào mà mã của bạn đang mong đợi một biến của một loại nhất định, nó sẽ có thể chấp nhận bất kỳ loại nào có nguồn gốc từ loại đó và vẫn hoạt động chính xác mà không cần phải có kiến ​​thức về các chi tiết của loại dẫn xuất.

Ví dụ, khung GUI sử dụng thay thế Liskov ở mọi nơi. Họ có xu hướng có một Controllớp cơ sở có thể đại diện cho "bất kỳ điều khiển" nào, định nghĩa một giao diện biết về các hành động cơ bản như vẽ, thay đổi kích thước và đáp ứng đầu vào của người dùng. Nếu bạn bấm vào một điều khiển, khung UI sẽ gọi một Clickphương thức trên điều khiển mà không cần phải quan tâm đến loại điều khiển đó là gì, và sau đó để điều khiển xử lý nhấp chuột theo cách thích hợp cho lớp của chính nó. Một Buttonđiều khiển nên làm một cái gì đó hoàn toàn khác khi nhấp vào hơn một TextBoxđiều khiển, để chỉ đưa ra một ví dụ.

Vì vậy, có, bạn có thể tạo một cái gì đó tương tự như các đối tượng bằng cách sử dụng thủ thuật hàm lồng nhau được mô tả ở trên, nhưng vì bạn không thể nhận được sự kế thừa và thay thế Liskov theo cách đó, nên nó là một sự thay thế cực kỳ hạn chế cho OOP thực sự.


Trong ngôn ngữ C, tôi không thể nói 'struct Parent {}' và sau đó 'struct con {struct Parent * ptr;}'? Đây có phải là kế thừa trong cú pháp ngôn ngữ không oop?
trao đổi quá mức

@overexchange: Đó là một nỗ lực không phải OO để giả mạo nó, nhưng trình biên dịch sẽ không cho phép bạn thay thế cái này bằng cái khác. (Bạn không thể chuyển một child*hàm parent*thành một đối số, ít nhất là không có kiểu chữ.) Và thậm chí tệ hơn, các cấu trúc C không thể có các phương thức ràng buộc với chúng và không có hỗ trợ cho các phương thức ảo , đó là Điều gì làm cho phép thuật thay thế Liskov hoạt động, vì vậy bạn phải xây dựng VMT bằng tay, đây là một quá trình phức tạp dễ làm hỏng.
Mason Wheeler

1
Nhân Linux sử dụng mô phỏng một số kỹ thuật OO, tất cả đều phải được mã hóa thủ công mà không cần hỗ trợ ngôn ngữ. Điều này dẫn đến rất nhiều cơ hội cho các lỗi, vốn là Linux, được đối trọng bởi một ứng dụng tự do của Luật Linus. Vâng, điều đó là có thể làm - Turing tương đương chứng minh điều này - nhưng quan điểm của tôi là cực kỳ khó để có được ngay mà không có sự hỗ trợ ngôn ngữ vẫn đứng vững. Ngoài ra, tại sao tất cả những câu hỏi về C khi câu hỏi là về Python? Trong C, không thể thực hiện thủ thuật lồng nhau ở vị trí đầu tiên.
Mason Wheeler

1
@overexchange Từ khi nào Java là "thiên đường lập trình viên"?
Brandin

1
Truyền tin nhắn không phải là một thất bại trong các hệ thống OOP kiểu Smalltalk, Erlang hoặc thậm chí Java, trong đó "tin nhắn" có nghĩa là một cái gì đó khác với "chức năng gọi" khi nó có nghĩa là "phương thức gọi"). Tin nhắn! = Chức năng gọi. Tin nhắn chính hãng không chỉ thành công, nó dường như là cách duy nhất chúng ta biết để viết các hệ thống đồng thời và mạnh mẽ. Đây là trực giao để triển khai OOP kiểu Java mà không cần từ khóa 'lớp'. Nó có thể được thực hiện. Nó không phải lúc nào cũng hữu ích. Nhắn tin là bên cạnh điểm.
zxq9

-1

Trả lời nhanh

Có, Lập trình viên có thể áp dụng Lập trình hướng đối tượng mà không cần "Lớp học".

Câu trả lời mô tả dài nhàm chán

Có một số biến thể của "Định hướng đối tượng", suy nghĩ, khái niệm đầu tiên xuất hiện trong tâm trí của nhiều lập trình viên là "Các lớp học".

Có, Lập trình viên có thể áp dụng Lập trình hướng đối tượng mà không cần "Lớp học", nhưng, bị giới hạn ở các tính năng và giới hạn từ mỗi ngôn ngữ lập trình.

Bài đăng của bạn được gắn thẻ là Python , do đó, tiêu đề câu hỏi của bạn có thể giống như "Cách triển khai lập trình hướng đối tượng mà không cần các lớp trong Python".

Tôi hiện đang sử dụng cụm từ "Lập trình hướng đối tượng và lớp", để xác định từ các biến thể khác như "Tạo mẫu" của Javascript hoặc "Dựa trên cơ bản" hoặc mô phỏng trong "Pure C" bằng cách sử dụng "functor".

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.