2010-05-29 84 views
8

在我目前的工作中,我構建了一套嚴重依賴於對象的Perl腳本。 (在Hash上使用Perl的bless()以儘可能接近OO)在鴨子型語言中模擬靜態類型的方面

現在,由於缺乏更好的方式來實現這一點,我公司的大多數程序員都不是很聰明。更糟的是,他們不喜歡閱讀文檔,並且似乎對理解其他人的代碼有困難。牛仔編碼是這裏的遊戲。每當他們遇到問題並嘗試解決問題時,他們都會提出一個可怕的解決方案,它實際上不會解決任何問題,並且通常會使問題變得更糟。

坦率地說,這使我不信任用duck typed language編寫的代碼。作爲一個例子,我發現他們有太多的問題沒有得到誤用對象的明確錯誤。例如,如果類型A具有成員foo,並且他們執行類似instance->goo的操作,則他們不會立即看到問題。它會返回一個空值/未定義的值,他們可能會浪費一個小時來查找原因。然後最終改變別的東西,因爲他們沒有正確識別原來的問題。

所以我的頭腦風暴的方式,以保持我的腳本語言(其快速發展是一個優勢),但是當沒有正確使用對象給出一個清楚的錯誤消息。我意識到,由於沒有編譯階段或靜態類型,錯誤將不得不在運行時。我很好這一點,只要用戶得到一個很明確的通知說:「這個對象沒有X」

由於我的解決方案的一部分,我不希望它被要求他們檢查在嘗試使用它之前存在一個方法/變量。

即使我的工作是在Perl中,我認爲這可以是語言不可知的。

+0

鑑於你處於這種環境中,在寫Perl的同時承認你的同事不瞭解它......這聽起來像你是問題的一部分! – Stephen 2010-05-29 01:58:58

+0

我沒有選擇使用Perl。根據管理層的說法,這或者是這樣。 – Mike 2010-05-29 02:00:52

+0

我處於某種領導地位,但官僚們做出技術決定。我正在努力改變這一點,但我仍然沒有我需要的那麼多的影響力。 – Mike 2010-05-29 02:02:34

回答

15

如果您有添加模塊使用的任何鏡頭,請嘗試Moose。它提供了您在現代編程環境中所需的幾乎所有功能,等等。它具有類型檢查,出色的繼承性,具有內省功能,並且具有用於Perl類的最好的接口之一MooseX::Declare。看看:

use MooseX::Declare; 

class BankAccount { 
    has 'balance' => (isa => 'Num', is => 'rw', default => 0); 

    method deposit (Num $amount) { 
     $self->balance($self->balance + $amount); 
    } 

    method withdraw (Num $amount) { 
     my $current_balance = $self->balance(); 
     ($current_balance >= $amount) 
      || confess "Account overdrawn"; 
     $self->balance($current_balance - $amount); 
    } 
} 

class CheckingAccount extends BankAccount { 
    has 'overdraft_account' => (isa => 'BankAccount', is => 'rw'); 

    before withdraw (Num $amount) { 
     my $overdraft_amount = $amount - $self->balance(); 
     if ($self->overdraft_account && $overdraft_amount > 0) { 
      $self->overdraft_account->withdraw($overdraft_amount); 
      $self->deposit($overdraft_amount); 
     } 
    } 
} 

我覺得這很酷,我自己。 :)它是Perl對象系統的一個層,因此它可以與你已有的東西(基本上)一起工作。

使用Moose,你可以很容易地創建子類型,所以你可以確保你的輸入是有效的。懶惰的程序員同意:爲了使子類型在Moose中工作所做的工作量非常小,做起來更容易。 (從Cookbook 4

subtype 'USState' 
    => as Str 
    => where { 
      ( exists $STATES->{code2state}{ uc($_) } 
      || exists $STATES->{state2code}{ uc($_) }); 
     }; 

而且田田的USState現在是一個類型,你可以使用!沒有大驚小怪,沒有麻煩,只有少量的代碼。如果不正確,它會拋出一個錯誤,並且你的類的所有消費者必須做的是傳遞一個帶有該字符串的標量。如果沒關係(它應該是......對不對?:))他們像正常一樣使用它,並且你的班級不受垃圾影響。那真好!

駝鹿有這麼多好東西。

相信我。一探究竟。 :)

+2

+1爲Moose :) – DVK 2010-05-29 10:44:56

+0

Moose是否有將$ object - > {member}轉換爲錯誤的方法?我認爲這是OP想要的。 – Schwern 2010-05-29 21:58:56

+2

查找MooseX :: InsideOut。它應該使$ object - > {member}無效,同時仍然能夠使用上面描述的所有antlered善良。 – 2010-05-30 00:42:19

4

在Perl,

  • 使它要求use strictuse warnings是在代碼

  • 你可以嘗試讓一個幾乎私有成員變量的100%通過創建closures。一個很好的例子是http://www.usenix.org/publications/login/1998-10/perl.html中的「私人成員變量,排序」部分。除非你真的知道你在做什麼(並且要求他們閱讀你的代碼並進行研究以瞭解如何),否則他們不是100%私人的,但是如何訪問卻不太明顯。

  • 如果你不想使用閉包,下面的方法效果很好幾分:

    讓所有對象的成員變量(又名對象在Perl哈希鍵)包裹在存取。有很多方法可以從編碼標準POV中有效地完成此操作。最不安全的是Class :: Accessor :: Fast。我相信穆斯有更好的方法,但我不熟悉穆斯。

    請務必在私有會議名稱中隱藏實際的成員變量,例如$object->{'__private__var1'}將是成員變量,而$object->var1()將是一個getter/setter訪問器。

    注意:最後,Class :: Accessor :: Fast是壞的,因爲它的成員變量與訪問器共享名稱。但是您可以使用像Class :: Accessor :: Fast一樣簡單的構建器,併爲「foo」創建諸如$ obj - > {'__ private__foo'}之類的關鍵值。

    這不會阻止他們在腳下自己射擊,但會使其難以做到這一點。

    在你的情況,如果他們使用$obj->goo$obj->goo(),他們會得到一個運行時錯誤,至少在Perl中。

    他們當然可以不做$obj->{'__private__goo'},但如果他們因純粹的懶惰而做了奇聞趣事的牛仔廢話,後者比做正確的$obj->foo()要多得多。

    您也可以掃描檢測$object->{"_類型字符串的代碼庫,儘管從描述中可能不會起到很大的威懾作用。

+3

@jrockway - 足夠公平 - 對我來說不好的措辭。我會刪除exaggregatrion。但正如我在「私人的名義」選項中所說的那樣,遊戲的名字是「做壞事比做好事更難」。 – DVK 2010-05-29 10:37:39

4

您可以使用Class::InsideOutObject::InsideOut它給你真正的數據隱私。而不是將數據存儲在一個幸運的散列引用中,而是使用一個祝福的標量引用作爲詞法數據散列的關鍵。長話短說,如果你的同事嘗試$obj->{member}他們會得到一個運行時錯誤。 $obj沒有什麼可以讓他們抓住,除了通過訪問器,沒有簡單的方法來獲取數據。

這裏是a discussion of the inside-out technique and various implementations

+0

我記得幾年前有很多關於內向物體的討論,他們似乎是新的熱點,但他們現在幾乎已經脫離了雷達。任何想法爲什麼他們失寵了?他們是否存在實際問題或者他們是否被穆斯黯然失色? – 2010-05-30 13:01:24

+0

AFAIK大部分導致問題的問題已得到解決,它是5.10(已回溯到5.8)的一個重要特性,即添加字段哈希(請參閱Hash :: Util :: FieldHash)以正確支持它們。也許現在實施問題已經解決了它不值得談論的問題? – Schwern 2010-05-30 21:05:08

相關問題