Lập trình chức năng so với OOP với các lớp


32

Tôi đã quan tâm đến một số khái niệm về lập trình chức năng gần đây. Tôi đã sử dụng OOP một thời gian. Tôi có thể thấy cách tôi sẽ xây dựng một ứng dụng khá phức tạp trong OOP. Mỗi đối tượng sẽ biết cách làm những việc mà đối tượng làm. Hoặc bất cứ điều gì đó là lớp cha mẹ cũng làm. Vì vậy, tôi chỉ có thể nói Person().speak()để làm cho người nói chuyện.

Nhưng làm thế nào để tôi làm những điều tương tự trong lập trình chức năng? Tôi thấy các chức năng là các hạng mục đầu tiên. Nhưng chức năng đó chỉ làm một điều cụ thể. Tôi chỉ đơn giản là có một say()phương thức nổi xung quanh và gọi nó bằng một Person()đối số tương đương để tôi biết loại điều gì đang nói gì đó?

Vì vậy, tôi có thể thấy những điều đơn giản, làm thế nào tôi có thể so sánh OOP và các đối tượng trong lập trình chức năng, để tôi có thể mô đun hóa và sắp xếp cơ sở mã của mình?

Để tham khảo, trải nghiệm chính của tôi với OOP là Python, PHP và một số C #. Các ngôn ngữ mà tôi đang xem có các tính năng chức năng là Scala và Haskell. Mặc dù tôi đang nghiêng về Scala.

Ví dụ cơ bản (Python):

Animal(object):
    def say(self, what):
        print(what)

Dog(Animal):
    def say(self, what):
        super().say('dog barks: {0}'.format(what))

Cat(Animal):
    def say(self, what):
        super().say('cat meows: {0}'.format(what))

dog = Dog()
cat = Cat()
dog.say('ruff')
cat.say('purr')

Scala được thiết kế dưới dạng OOP + FP, vì vậy bạn không phải chọn
Karthik T

1
Vâng tôi biết, nhưng tôi cũng muốn biết vì lý do trí tuệ. Tôi không thể tìm thấy bất cứ thứ gì tương đương với đối tượng trong các ngôn ngữ chức năng. Đối với scala, tôi vẫn muốn biết khi nào / ở đâu / làm thế nào tôi nên sử dụng chức năng trên oop, nhưng IMHO là một câu hỏi khác.
skift

2
"Đặc biệt nhấn mạnh quá mức, IMO là khái niệm chúng tôi không duy trì trạng thái.": Đây là quan niệm sai lầm. Không phải là sự thật rằng FP không sử dụng trạng thái, thay vào đó, FP xử lý trạng thái theo một cách khác (ví dụ: các đơn nguyên trong Haskell hoặc các loại duy nhất trong Clean).
Giorgio


3

Câu trả lời:


21

Những gì bạn đang thực sự hỏi về ở đây là làm thế nào để thực hiện Đa hình trong các ngôn ngữ chức năng, tức là làm thế nào để tạo ra các hàm hoạt động khác nhau dựa trên các đối số của chúng.

Lưu ý đối số đầu tiên cho một chức năng thường tương đương với "đối tượng" trong OOP, nhưng trong các ngôn ngữ chức năng, bạn thường muốn tách các chức năng khỏi dữ liệu, do đó, "đối tượng" có thể là một giá trị dữ liệu thuần túy (không thay đổi).

Các ngôn ngữ chức năng nói chung cung cấp các tùy chọn khác nhau để đạt được đa hình:

  • Một cái gì đó giống như đa phương thức gọi một hàm khác dựa trên việc kiểm tra các đối số được cung cấp. Điều này có thể được thực hiện trên loại đối số đầu tiên (có hiệu quả tương đương với hành vi của hầu hết các ngôn ngữ OOP), nhưng cũng có thể được thực hiện trên các thuộc tính khác của đối số.
  • Các cấu trúc dữ liệu giống như nguyên mẫu / đối tượng có chứa các hàm hạng nhất là thành viên . Vì vậy, bạn có thể nhúng một chức năng "nói" bên trong cấu trúc dữ liệu chó và mèo của bạn. Thực tế, bạn đã thực hiện phần mã của dữ liệu.
  • Khớp mẫu - trong đó logic khớp mẫu được tích hợp vào định nghĩa hàm và đảm bảo các hành vi khác nhau cho các tham số khác nhau. Thường gặp ở Haskell.
  • Sự phân nhánh / điều kiện - tương đương với mệnh đề if / other trong OOP. Có thể không có khả năng mở rộng cao, nhưng vẫn có thể phù hợp trong nhiều trường hợp khi bạn có một tập hợp các giá trị có thể có giới hạn (ví dụ: hàm được truyền một số hoặc một chuỗi hoặc null?)

Ví dụ: đây là một triển khai Clojure cho vấn đề của bạn bằng cách sử dụng đa phương thức:

;; define a multimethod, that dispatched on the ":type" keyword
(defmulti say :type)  

;; define specific methods for each possible value of :type. You can add more later
(defmethod say :cat [animal what] (println (str "Car purrs: " what)))
(defmethod say :dog [animal what] (println (str "Dog barks: " what)))
(defmethod say :default [animal what] (println (str "Unknown noise: " what)))

(say {:type :dog} "ruff")
=> Dog barks: ruff

(say {:type :ape} "ook")
=> Unknown noise: ook

Lưu ý rằng hành vi này không yêu cầu bất kỳ lớp rõ ràng nào được xác định: bản đồ thông thường hoạt động tốt. Hàm điều phối (: gõ trong trường hợp này) có thể là bất kỳ hàm tùy ý nào của các đối số.


Không rõ ràng 100%, nhưng đủ để xem bạn đang đi đâu. Tôi có thể xem đây là mã 'động vật' trong một tệp nhất định. Ngoài ra phần trên nhánh / điều kiện là tốt quá. Tôi đã không coi đó là sự thay thế cho if / other.
skift

11

Đây không phải là câu trả lời trực tiếp, cũng không nhất thiết phải chính xác 100% vì tôi không phải là chuyên gia ngôn ngữ chức năng. Nhưng trong cả hai trường hợp, tôi sẽ chia sẻ với bạn kinh nghiệm của tôi ...

Khoảng một năm trước tôi đã ở trong một chiếc thuyền tương tự như bạn. Tôi đã thực hiện C ++ và C # và tất cả các thiết kế của tôi luôn rất nặng về OOP. Tôi đã nghe nói về các ngôn ngữ FP, đọc một số thông tin trực tuyến, lướt qua cuốn sách F # nhưng vẫn không thể thực sự nắm bắt làm thế nào một ngôn ngữ FP có thể thay thế OOP hoặc nói chung là hữu ích vì hầu hết các ví dụ tôi đã thấy quá đơn giản.

Đối với tôi, "bước đột phá" đã đến khi tôi quyết định học trăn. Tôi đã tải xuống python, sau đó đi đến trang chủ dự án euler và chỉ bắt đầu làm một vấn đề khác. Python không nhất thiết phải là ngôn ngữ FP và bạn chắc chắn có thể tạo các lớp trong đó, nhưng so với C ++ / Java / C #, nó có nhiều cấu trúc FP hơn, vì vậy khi tôi bắt đầu chơi với nó, tôi đã đưa ra quyết định có ý thức định nghĩa một lớp trừ khi tôi hoàn toàn phải

Điều tôi thấy thú vị về Python là việc lấy các hàm và "khâu" chúng dễ dàng và tự nhiên như thế nào để tạo ra các hàm phức tạp hơn và cuối cùng, vấn đề của bạn vẫn được giải quyết bằng cách gọi một hàm duy nhất.

Bạn đã chỉ ra rằng khi mã hóa bạn nên tuân theo nguyên tắc trách nhiệm duy nhất và điều đó hoàn toàn chính xác. Nhưng chỉ vì chức năng chịu trách nhiệm cho một nhiệm vụ duy nhất, không có nghĩa là nó chỉ có thể thực hiện mức tối thiểu tuyệt đối. Trong FP, bạn vẫn có mức độ trừu tượng. Vì vậy, các hàm cấp cao hơn của bạn vẫn có thể thực hiện "một" nhưng chúng có thể ủy quyền cho các hàm cấp thấp hơn để triển khai các chi tiết tốt hơn về cách đạt được "một" thứ đó.

Chìa khóa với FP tuy nhiên là bạn không có tác dụng phụ. Miễn là bạn coi ứng dụng là chuyển đổi dữ liệu đơn giản với bộ đầu vào và bộ đầu ra được xác định, bạn có thể viết mã FP sẽ thực hiện những gì bạn cần. Rõ ràng không phải mọi ứng dụng sẽ phù hợp với khuôn mẫu này, nhưng một khi bạn bắt đầu thực hiện nó, bạn sẽ ngạc nhiên về số lượng ứng dụng phù hợp. Và đây là lúc tôi nghĩ Python, F # hoặc Scala tỏa sáng vì chúng cung cấp cho bạn các cấu trúc FP nhưng khi bạn cần nhớ trạng thái của mình và "giới thiệu các tác dụng phụ", bạn luôn có thể sử dụng các kỹ thuật OOP thật và đã thử.

Kể từ đó, tôi đã viết cả đống mã python như các tiện ích và các tập lệnh trợ giúp khác cho công việc nội bộ và một số trong số chúng được mở rộng khá xa nhưng bằng cách nhớ các nguyên tắc RẮN cơ bản, hầu hết các mã đó vẫn được duy trì rất linh hoạt và linh hoạt. Giống như trong OOP, giao diện của bạn là một lớp và bạn di chuyển các lớp xung quanh khi bạn cấu trúc lại và / hoặc thêm chức năng, trong FP bạn thực hiện chính xác điều tương tự với các hàm.

Tuần trước tôi đã bắt đầu viết mã bằng Java và kể từ đó, hầu như trên cơ sở hàng ngày tôi được nhắc nhở rằng khi ở OOP, tôi phải thực hiện các giao diện bằng cách khai báo các lớp bằng các phương thức ghi đè các hàm, trong một số trường hợp tôi có thể đạt được điều tương tự trong Python bằng cách sử dụng biểu thức lambda đơn giản, ví dụ, 20-30 dòng mã mà tôi đã viết để quét một thư mục, sẽ có 1-2 dòng trong Python và không có lớp nào.

Bản thân FP là ngôn ngữ cấp cao hơn. Trong Python (xin lỗi, trải nghiệm FP duy nhất của tôi) tôi có thể kết hợp việc hiểu danh sách bên trong một sự hiểu biết danh sách khác với lambdas và những thứ khác được đưa vào và toàn bộ điều sẽ chỉ có 3-4 dòng mã. Trong C ++, tôi hoàn toàn có thể hoàn thành điều tương tự, nhưng vì C ++ ở cấp độ thấp hơn, tôi sẽ phải viết nhiều mã hơn 3-4 dòng và khi số dòng tăng lên, việc đào tạo SRP của tôi sẽ bắt đầu và tôi sẽ bắt đầu suy nghĩ về cách chia mã thành các phần nhỏ hơn (nghĩa là nhiều chức năng hơn). Nhưng vì lợi ích của khả năng bảo trì và ẩn chi tiết triển khai, tôi sẽ đặt tất cả các chức năng đó vào cùng một lớp và biến chúng thành riêng tư. Và ở đó bạn có nó ... Tôi vừa tạo một lớp trong khi ở python tôi sẽ viết "return (.... lambda x: .. ....)"


Vâng, nó không trực tiếp trả lời câu hỏi, nhưng vẫn là một câu trả lời tuyệt vời. Khi tôi viết các tập lệnh hoặc gói nhỏ hơn trong python, tôi cũng không luôn sử dụng các lớp. nhiều lần chỉ cần có nó trong một định dạng gói phù hợp hoàn hảo. đặc biệt là nếu tôi không cần nhà nước. Tôi cũng đồng ý rằng việc hiểu danh sách cũng rất hữu ích. Kể từ khi đọc về FP, tôi đã nhận ra chúng có thể mạnh hơn bao nhiêu. điều đó sau đó đã khiến tôi muốn tìm hiểu thêm về FP, so với OOP.
skift

Câu trả lời chính xác. Nói chuyện với tất cả mọi người đang đứng bên cạnh bể bơi funcctional nhưng không chắc có nên nhúng ngón chân xuống nước hay không
Robben_Ford_Fan_boy

Và Ruby ... Một trong những triết lý thiết kế của nó tập trung vào các phương thức lấy khối mã làm đối số, thường là một tùy chọn. Và đưa ra suy nghĩ cú pháp sạch và mã hóa theo cách này là dễ dàng. Thật khó để suy nghĩ và sáng tác như thế này trong C #. C # writ chức năng là dài dòng và mất phương hướng, nó cảm thấy bị cuốn vào ngôn ngữ. Tôi thích điều đó Ruby đã giúp suy nghĩ chức năng dễ dàng hơn, để thấy tiềm năng trong hộp suy nghĩ C # đã nói của tôi. Trong phân tích cuối cùng tôi thấy chức năng và OO là bổ sung; Tôi muốn nói rằng Ruby chắc chắn nghĩ như vậy.
radarbob

8

Trong Haskell, gần nhất bạn có là "lớp". Lớp này mặc dù không giống như lớp trong Java và C ++ , sẽ hoạt động cho những gì bạn muốn trong trường hợp này.

Trong trường hợp của bạn, đây là cách mã của bạn sẽ trông như thế nào.

Lớp động vật một nơi 
nói :: Chuỗi -> âm thanh 

Sau đó, bạn có thể có các kiểu dữ liệu riêng lẻ thích ứng với các phương thức này.

ví dụ Animal Dog ở đâu
nói s = "sủa" ++ s 

EDIT: - Trước khi bạn có thể nói chuyên về Dog, bạn cần nói với hệ thống rằng Dog là động vật.

dữ liệu Dog = \ - một cái gì đó ở đây - \ (động vật bắt nguồn)

EDIT: - Dành cho Wilq.
Bây giờ nếu bạn muốn sử dụng say trong hàm say foo, bạn sẽ phải nói với haskell rằng foo chỉ có thể hoạt động với Animal.

foo :: (Động vật a) => a -> Chuỗi -> Chuỗi
foo a str = nói một str 

Bây giờ nếu bạn gọi foo với chó thì nó sẽ sủa, nếu bạn gọi với mèo thì nó sẽ kêu meo meo.

chính = làm 
let d = dog (\ - tham số cstr - \)
    c = mèo  
trong chương trình $ foo d "Hello World"

Bây giờ bạn không thể có bất kỳ định nghĩa khác về chức năng nói. Nếu nói được gọi với bất cứ thứ gì không phải là động vật, nó sẽ gây ra lỗi biên dịch.


Tôi phải thực sự hiểu thêm một chút về haskell để hiểu đầy đủ về thi, nhưng tôi nghĩ rằng tôi hiểu ý chính của nó. Tôi vẫn tò mò mặc dù làm thế nào điều này sẽ phù hợp với một cơ sở mã phức tạp hơn.
skift

Động vật nitpick nên được viết hoa
Daniel Gratzer

1
Làm thế nào để hàm say biết rằng bạn gọi nó trên Dog nếu nó chỉ lấy một Chuỗi? Và không phải "bắt nguồn" chỉ cho một số lớp dựng sẵn?
WilQu

6

Các ngôn ngữ chức năng sử dụng 2 cấu trúc để đạt được đa hình:

  • Chức năng đặt hàng đầu tiên
  • Generics

Tạo mã đa hình với những mã này hoàn toàn khác với cách OOP sử dụng kế thừa và phương thức ảo. Mặc dù cả hai ngôn ngữ này đều có thể có sẵn bằng ngôn ngữ OOP yêu thích của bạn (như C #), hầu hết các ngôn ngữ chức năng (như Haskell) đều có thể lên đến mười một. Rất hiếm khi chức năng là không chung chung và hầu hết các chức năng có chức năng như tham số.

Thật khó để giải thích như thế này và nó sẽ đòi hỏi nhiều thời gian của bạn để học cách mới này. Nhưng để làm điều này, bạn cần hoàn toàn quên OOP, vì đó không phải là cách nó hoạt động trong thế giới chức năng.


2
OOP là tất cả về đa hình. Nếu bạn nghĩ OOP liên quan đến việc có các chức năng gắn với dữ liệu của bạn, thì bạn không biết gì về OOP.
Euphoric

4
Tính đa hình chỉ là một khía cạnh của OOP và tôi nghĩ không phải là vấn đề mà OP thực sự yêu cầu.
Doc Brown

2
Đa hình là khía cạnh quan trọng của OOP. Mọi thứ khác đều ở đó để hỗ trợ nó. OOP không có kế thừa / phương thức ảo gần như chính xác như lập trình thủ tục.
Euphoric

1
@ErikReppen Nếu "không cần áp dụng giao diện" thường xuyên, thì bạn không làm OOP. Ngoài ra, Haskell cũng có các mô-đun.
Euphoric

1
Bạn không phải lúc nào cũng cần một giao diện. Nhưng chúng rất hữu ích khi bạn cần chúng. Và IMO một phần quan trọng khác của OOP. Đối với các mô-đun đi trong Haskell, tôi nghĩ rằng điều này có lẽ là gần nhất với OOP cho các ngôn ngữ chức năng, khi có liên quan đến tổ chức mã. Ít nhất là từ những gì tôi đã đọc cho đến nay. Tôi biết họ vẫn rất khác nhau.
skift

0

nó thực sự phụ thuộc vào những gì bạn muốn thực hiện.

nếu bạn chỉ cần một cách để tổ chức hành vi dựa trên các tiêu chí chọn lọc, bạn có thể sử dụng ví dụ: từ điển (bảng băm) với các đối tượng hàm. trong python nó có thể là một cái gì đó dọc theo dòng:

def bark(what):
    print "barks: {0}".format(what) 

def meow(what):
    print "meows: {0}".format(what)

def climb(how):
    print "climbs: {0}".format(how)

if __name__ == "__main__":
    animals = {'dog': {'say': bark},
               'cat': {'say': meow,
                       'climb': climb}}
    animals['dog']['say']("ruff")
    animals['cat']['say']("purr")
    animals['cat']['climb']("well")

tuy nhiên, lưu ý rằng (a) không có 'trường hợp' chó hoặc mèo và (b) bạn sẽ phải tự theo dõi 'loại' đối tượng của mình.

như ví dụ : pets = [['martin','dog','grrrh'], ['martha', 'cat', 'zzzz']]. sau đó bạn có thể làm một danh sách hiểu[animals[pet[1]]['say'](pet[2]) for pet in pets]


0

Ngôn ngữ OO đôi khi có thể được sử dụng thay cho ngôn ngữ cấp thấp để giao tiếp trực tiếp với máy. C ++ Chắc chắn, nhưng ngay cả đối với C # cũng có bộ điều hợp và như vậy. Mặc dù viết mã để điều khiển các bộ phận cơ học và kiểm soát phút trên bộ nhớ tốt nhất nên giữ càng gần mức thấp càng tốt. Nhưng nếu câu hỏi này liên quan đến phần mềm hướng đối tượng hiện tại như Line Of Business, ứng dụng web, IOT, Dịch vụ web và phần lớn các ứng dụng được sử dụng hàng loạt, thì ...

Trả lời, nếu có

Độc giả có thể thử làm việc với Kiến trúc hướng dịch vụ (SOA). Đó là, DDD, N-Layered, N-Tiered, Hexagonal, sao cũng được. Tôi chưa thấy một ứng dụng kinh doanh lớn sử dụng hiệu quả OO "Truyền thống" (Bản ghi hoạt động hoặc Mô hình phong phú) như được mô tả trong thập niên 70 và 80 trong thập kỷ qua +. (Xem chú thích 1)

Lỗi không phải ở OP, nhưng có một vài vấn đề với câu hỏi.

  1. Ví dụ bạn cung cấp chỉ đơn giản là để chứng minh tính đa hình, nó không phải là mã sản xuất. Đôi khi các ví dụ chính xác như thế được thực hiện theo nghĩa đen.

  2. Trong FP và SOA, Dữ liệu được tách ra khỏi Logic nghiệp vụ. Đó là, Dữ liệu và Logic không đi cùng nhau. Logic đi vào Dịch vụ và Dữ liệu (Mô hình miền) không có hành vi Đa hình (Xem Lưu ý 2).

  3. Dịch vụ và chức năng có thể là đa hình. Trong FP, bạn thường xuyên truyền các hàm dưới dạng tham số cho các hàm khác thay vì các giá trị. Bạn có thể làm tương tự trong các ngôn ngữ OO với các loại như Callable hoặc Func, nhưng nó không chạy tràn lan (Xem Lưu ý 3). Trong FP và SOA, Mô hình của bạn không phải là Dạng đa hình, chỉ có Dịch vụ / Chức năng của bạn. (Xem chú thích 4)

  4. Có một trường hợp xấu về mã hóa cứng trong ví dụ đó. Tôi không chỉ nói về chuỗi "chó sủa" màu đỏ. Tôi cũng đang nói về CatModel và DogModel. Điều gì xảy ra khi bạn muốn thêm một con cừu? Bạn phải đi vào mã của bạn và tạo mã mới? Tại sao? Trong mã sản xuất, tôi chỉ muốn thấy một AnimalModel với các thuộc tính của nó. Tệ nhất, một AmphibianModel và FowlModel nếu thuộc tính và cách xử lý của chúng quá khác nhau.

Đây là những gì tôi mong đợi sẽ thấy trong Ngôn ngữ "OO" hiện tại:

public class Animal
{
    public int AnimalID { get; set; }
    public int LegCount { get; set; }
    public string Name { get; set; }
    public string WhatISay { get; set; }
}

public class AnimalService : IManageAnimals
{
    private IPersistAnimals _animalRepo;
    public AnimalService(IPersistAnimals animalRepo) { _animalRepo = animalRepo; }

    public List<Animal> GetAnimals() => _animalRepo.GetAnimals();

    public string WhatDoISay(Animal animal)
    {
        if (!string.IsNullOrWhiteSpace(animal.WhatISay))
            return animal.WhatISay;

        return _animalRepo.GetAnimalNoise(animal.AnimalID);
    }
}

Lưu lượng cơ bản

Làm thế nào để bạn chuyển từ các lớp trong OO sang lập trình chức năng? Như những người khác đã nói; Bạn có thể, nhưng bạn không thực sự. Quan điểm trên là để chứng minh rằng bạn thậm chí không nên sử dụng Classes (theo nghĩa truyền thống của thế giới) khi thực hiện Java và C #. Khi bạn có thể viết mã theo Kiến trúc hướng dịch vụ (DDD, Layered, Tiered, Hexagonal, bất cứ điều gì), bạn sẽ tiến gần hơn một bước đến chức năng vì bạn tách dữ liệu (Mô hình miền) khỏi các hàm logic (Dịch vụ) của bạn.

Ngôn ngữ OO một bước gần hơn với FP

Bạn thậm chí có thể đưa nó đi xa hơn một chút và chia Dịch vụ SOA của bạn thành hai loại.

Loại tùy chọn Loại 1 : Giao diện chung - Dịch vụ triển khai cho Điểm vào. Đây sẽ là các Điểm vào "không trong sạch" có thể gọi vào chức năng khác "Tinh khiết" hoặc "Không trong sạch". Đây có thể là Điểm vào của bạn từ API RESTful.

Loại tùy chọn 2 : Dịch vụ logic kinh doanh thuần túy. Đây là các lớp tĩnh có chức năng "Pure". Trong FP, "Pure" có nghĩa là không có tác dụng phụ. Nó không đặt rõ ràng Trạng thái hoặc Kiên trì ở bất cứ đâu. (Xem chú thích 5)

Vì vậy, khi bạn nghĩ về các Lớp trong Ngôn ngữ hướng đối tượng, được sử dụng trong Kiến trúc hướng dịch vụ, nó không chỉ mang lại lợi ích cho Mã OO của bạn, nó bắt đầu làm cho Lập trình hàm có vẻ rất dễ hiểu.

Ghi chú

Lưu ý 1 : Thiết kế hướng đối tượng "Giàu có" hoặc "Ghi lại hoạt động" ban đầu vẫn còn. Có rất nhiều mã kế thừa như thế khi người ta "làm đúng" một thập kỷ trở lên. Lần trước tôi đã thấy loại mã đó (được thực hiện chính xác) là từ một trò chơi video Codebase trong C ++, nơi họ đang kiểm soát bộ nhớ chính xác và có không gian rất hạn chế. Không phải nói Kiến trúc FP và hướng dịch vụ là những con thú và không nên xem xét phần cứng. Nhưng họ đặt khả năng liên tục thay đổi, được duy trì, có kích thước dữ liệu thay đổi và các khía cạnh khác là ưu tiên. Trong trò chơi video và AI máy, bạn điều khiển tín hiệu và dữ liệu rất chính xác.

Lưu ý 2 : Mô hình miền không có Hành vi đa hình, cũng không có Phụ thuộc bên ngoài. Họ là "Cô lập". Điều đó không có nghĩa là họ phải thiếu máu 100%. Họ có thể có rất nhiều logic liên quan đến việc xây dựng và thay đổi tài sản có thể thay đổi của họ, nếu điều đó được áp dụng. Xem DDD "Đối tượng giá trị" và các thực thể của Eric Evans và Mark Seemann.

Lưu ý 3 : Linq và Lambda rất phổ biến. Nhưng khi người dùng tạo một chức năng mới, họ hiếm khi sử dụng Func hoặc Callable làm tham số, trong khi ở FP, thật lạ khi thấy một ứng dụng không có các chức năng theo mẫu đó.

Lưu ý 4 : Không nhầm lẫn Đa hình với Kế thừa. Một CatModel có thể kế thừa AnimalBase để xác định Thuộc tính nào mà Động vật thường có. Nhưng như tôi chỉ ra, những Người mẫu như thế này là Mùi Mã . Nếu bạn thấy mẫu này, bạn có thể xem xét phá vỡ nó và biến nó thành dữ liệu.

Lưu ý 5 : Hàm thuần có thể (và làm) chấp nhận hàm làm tham số. Hàm đến có thể không tinh khiết, nhưng có thể là thuần túy. Đối với mục đích thử nghiệm, nó sẽ luôn luôn tinh khiết. Nhưng trong sản xuất, mặc dù được coi là nguyên chất, nhưng nó có thể chứa tác dụng phụ. Điều đó không thay đổi thực tế rằng hàm thuần túy là thuần túy. Mặc dù chức năng tham số có thể không tinh khiết. Không khó hiểu! : D


-2

Bạn có thể làm một cái gì đó như thế này .. php

    function say($whostosay)
    {
        if($whostosay == 'cat')
        {
             return 'purr';
        }elseif($whostosay == 'dog'){
             return 'bark';
        }else{
             //do something with errors....
        }
     }

     function speak($whostosay)
     {
          return $whostosay .'\'s '.say($whostosay);
     }
     echo speak('cat');
     >>>cat's purr
     echo speak('dog');
     >>>dogs's bark

1
Tôi đã không đưa ra bất kỳ phiếu bầu tiêu cực. Nhưng tôi đoán là vì cách tiếp cận này không phải là chức năng không hướng đối tượng.
Manoj R

1
Nhưng khái niệm được truyền đạt gần với khớp mẫu được sử dụng trong lập trình chức năng, tức là $whostosaytrở thành kiểu đối tượng xác định những gì được thực thi. Ở trên có thể được sửa đổi để chấp nhận bổ sung một tham số khác $whattosayđể một loại hỗ trợ nó (ví dụ 'human') có thể sử dụng nó.
syockit
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.