簡體   English   中英

普通函數可以模擬OOP嗎?

[英]Can normal functions emulate OOP?

是否可以使用正常功能模擬OOP編程? 與使用靜態變量和匿名函數一樣: http//php.net/manual/en/functions.anonymous.php

靜態變量用於編寫過程代碼,初看起來像OOP。

OOP是一種設計模式,與您使用的語言方面無關。 通過閱讀以下文章,您將從中受益匪淺: OOP與程序代碼 它解釋了編寫面向對象的代碼(即使只有函數)。

此外,您應該意識到函數式編程是一種完全不同的開發范例。 有這種范例的功能語言:JavaScript,Scala,Haskell,Erlang。

我認為我能想象到的最接近的就是編寫所有函數,將第一個參數作為數據結構進行操作。 可以這樣想:

OOP實質上只是將已知的數據結構與適當的行為耦合在一起。

因此,如果您願意相信自己只傳遞函數知道如何使用的數據結構,您可以在程序上對其進行建模,每個“類”在全局空間中有兩個數組,一個用於“實例”,一個用於“函數”(字面意思是一系列的callables,鍵入他們的名字)。

我寫了一些代碼,它們將“類”定義為基本上是方法的集合,而這些方法基本上可以處理他們想要的$self (只要他們都知道會發生什么)。 這是一個非常酷的主意(感謝您的提問!)。 注意匿名函數的使用,理論上可以將它們聚合到一個函數原型數組中,並在許多不同的類上使用(即只有一個“description”或“__toString”類,適用於所有類)。

編輯:工作代碼:

<?php

// The "Runtime" //
function makeObject($class, $constructorArgs) {
  global $classes;
  $constructorArgs = (array) $constructorArgs;
  $instance =  $classes[$class]['instances'][] = array();
  $instance['_class'] = $class;
  $instance = callMethod($instance, 'construct', $constructorArgs);
  return $instance;
}
function callMethod($instance, $method, $args = array()) {
  global $classes;
  return call_user_func_array($classes[$instance['_class']]['methods'][$method], array_merge(array($instance), $args));
}

// Class definition for "Person" //
$classes['Person'] = array();
$classes['Person']['methods'] = array();
$classes['Person']['methods']['construct'] = function($self, $name) {
    $self['name'] = $name;
    return $self;
};
$classes['Person']['methods']['sayHello'] = function($self) 
{
    echo "hello, my name is " . $self['name'] . "\n";
};
$classes['Person']['instances'] = array();


// Begin "Application" code.
// equivalent to: 
// $person = new Person("sally");
// $person->sayHello();

$person = makeObject('Person', "sally");
callMethod($person, "sayHello");

顯然,這可以通過任何有趣和有趣的方式進行擴展。 例如,您可以重做“方法”函數的結構,也可以使用$ parent參數,並允許子類調用其父級,並允許callMethod()在子級未實現時查找繼承的方法。 這很有趣。 請注意,只有最后兩行實際上是“應用程序代碼”...其余的等同於聲明性“設置”代碼(類似於類定義)和“運行時”函數。

是。 當你到達底層時,“對象只是函數的記錄”,這在編程語言理論中是眾所周知的。 也就是說,如果你的語言具有類似記錄的特征和適當的第一類函數(即“閉包”),那么“類”只是一個返回這樣一條記錄的函數。 例如,在一些偽語法中(因為我的PHP很簡陋):

func Point(x, y) {
  var my_x = x
  var my_y = y
  var this = {
    getX : func() { return my_x }
    getY : func() { return my_y }
    move : func(dx, dy) { my_x += dx; my_y += dy }
    dist : func() { return sqrt(this.getX()**2 + this.getY()**2) }
  }
  return this
}

var p = Point(0, 3)
p.move(2, -5)
p.getY()  // -2

注意所有“方法”如何只是關閉局部變量(因此隱藏)的第一類函數。

如果您還想要繼承,那么編碼會更復雜,但仍然可以。

是。 例如,可能用功能語言重載函數在某種程度上等同於OOP中的繼承。 但關鍵是,你甚至不應該想到嘗試用函數式語言編寫代碼看OOP。 將它們視為不同的工具,以實現相同的目標。

OOP 在理論上促進更清潔的代碼庫,並據說允許更容易地重用代碼。 當它出現時,圍繞着這些概念進行了大量宣傳,許多人甚至會說今天這種概念過於誇張。 功能語言在過去幾年中重新獲得了應有的尊重,許多人已經意識到OOP只是一個BUZZ詞,絕不是代碼質量的保證。

函數式編程有許多編碼技術和方法,可以使它像OOP一樣優雅。 對於任何項目來說,使用正確的工具是一個良好的開端,正確使用它是您應該注意的主要部分。 試圖使一個特定項目的代碼庫看起來像一個功能語言的OOP不會帶來任何好處,並且必然會使某些人感到悲慘:如果不是你,那么必須維護它的人。

您的主要目標之一是讓代碼庫盡可能易於理解,並且有許多特定於函數式編程的方法可以解決這個問題,就像OOP中的方法一樣。 在我(非常謙虛)的觀點中,函數式編程甚至具有優勢,因為它更靈活。

我已經看到並管理了很大的項目,很高興能夠參與其中。還有一些小型的OOP項目非常難以解決。 即使使用正確的工具,在錯誤的手中也會帶來不好的結果。

我的2美分,快樂的編碼!

很多人對OOP的真正含義有不同的看法......我認為OOP是一種以非常具體的方式設計程序的方法,使用對象作為程序或計算的系統隱喻,幫助你灌輸你的結果過程和軟件具有很多非常好,有用和強大的特性。

考慮到這一點,您可以在使用任何語言時應用OOP方法,使用某種語言比使用其他語言更容易...在“OOP”語言中通常最容易使用,而非語言會強迫您編寫OOP代碼(因為這是不可能的),但是它為您提供了一系列功能,如果您想要遵循OOP方法,將使您的生活更輕松......

最后,你需要“模擬OOP”的最困難的“事情”就是能夠使用“行為”或“代碼”作為數據......這可以通過很多方式實現,比如lambda函數,或者第一類函數或函數指針等......大多數現代語言至少支持其中一種。

OOP是關於有一個構造函數,它啟動一個對象,使用this關鍵字“靜態地”訪問其他函數。

所以是的,你可以在不使用“class”,“this”或__construct等語言結構的情況下進行OOP。

正常OOP

class Something{
    public $member_var;

    public function __construct(){
        $this->member_var="x";
    }

    public function fill($strValue){
        $this->member_var=$strValue;
    }
}
$objInstance=new Something();

$objInstance->fill("abc");

OOP使用過程語言結構 (我已經避免了Object類遠離任何OOP的東西,但是最好將它用於$ self類型,也許能夠使用 - > accessor,或利用自動通過引用傳遞):

function Something_constructor(&$self){
    $self=array(
        "member_var"=>"x",
    );
}

function fill(&$self, $strValue){
    $self["member_var"]=$strValue;
}

Something_constructor($arrInstance);

fill($arrInstance, "abc");

使用PHP> = 5.3新的匿名函數功能,您可以在$ self數組/對象中添加成員函數作為屬性,因為您可以直接調用( $self["fill"]("abcde") )。 如果為$ self使用對象數據類型,則可以使用更好的訪問者。

根據你設計代碼的方式,這個程序風格的OOP可能會被調整為在簡單的RPC場景中很好地工作(但是,構造函數永遠不會返回一個可用的$ self對象/數組,所以你也可以去完整的OOP並擁有相同的問題)。

如果進入(object)array()路由,你可以將fill函數作為屬性存儲在對象中,但是你永遠不會有$this引用(不傳遞它作為param)或原型或任何其他類型的繼承。 你最好堅持使用PHP中的class關鍵字,沒有理由去解決它。

如果你還需要繼承,這就是丑陋的地方:你需要創建重命名的函數來覆蓋$self數組/對象的“類型”轉換函數等。

可以辦到。 如果您有復雜的需求(如繼承),它可能會變得非常難看。 如果你有非常簡單的需求,不是那么難看,甚至可能有優勢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM