2016-08-13 60 views
1

Elixir執行橫切關注點的方式是什麼?假設我想檢查一個用戶是否已經取消訂閱電子郵件 - 是否可以在任何電子郵件發送功能執行之前這樣做?在Elixir文檔中找不到交錯其他功能的任何內容......就像rails中的before_filter,但是在獨立的Elixir應用程序中。可能會發送多個電子郵件 - 通知,市場營銷,交易等。添加每個未訂閱?手動檢查每個功能是非常必要的。 Elixir有更好的方法嗎?Elixir - 橫切關注點

+0

這只是我的意見,但我認爲你可以只寫有一個功能,比方說,一個特殊的模塊,接受用戶,檢查他是否有訂閱,如果他這樣做,發送電子郵件。然後你可以在需要它的地方使用這個模塊。這樣做會更加明確,不會給你帶來一些回調魔術。 – JustMichael

+0

@JustMichael - 這不重複嗎?我也在考慮一個模塊,但由於該電子郵件模塊中的每個功能都需要執行相同的操作,因此在每個函數中檢查相同的內容都不符合DRY原則。此外,我正在尋找Elixir在嘗試學習語言時提供的不同替代方案 – sat

+0

DRY原則不是一項法律 - 只是一個很好的指導方針。有時候不可能避免重複。雖然不重複代碼是一個偉大的目標,但可讀和可維護的代碼也很重要。另外,你認爲AOP如何實現這一點?你認爲他們不重複代碼來做到這一點?它只是隱藏在視野之外。 –

回答

0

在Rails中,使用before_filter實際上導致了糟糕的設計。我知道用這種方式編寫代碼更容易,但是過了一段時間,代碼庫會不斷增加,在這些回調中添加更多的邏輯,並且開始放鬆對它們的控制。

您可以在不使用回調的情況下使用簡單的函數來執行相同的操作,並且可以通過一種必要的方式保持控制(更容易推理和調試)。

假設你有一個具有多個電子郵件功能

defmodule Mailer do 
    def send_email1(params) do 
    # do work 
    end 

    def send_email2(params) do 
    end 

    # ... 
end 

取而代之的模塊添加某種可以簡單的代碼添加到每個這些功能正確的before_filter?這很簡單,很容易理解發生了什麼。

defmodule Mailer do 
    def send_email1(params) do 
    if can_send?(params) do 
     # do work 
    end 
    end 

    # ... 
end 

現在你發現你有重複的邏輯。那麼......您可以將檢查邏輯移動到一個更新的功能,並至少從這些功能中刪除if。但是你也可以創建一個新的抽象,並保持共享邏輯。

defmodule Mailer do 
    def send_email(email_name, params) do 
    if can_send?(params) do 
     do_send_email(email_name, params) 
    end 
    end 

    defp do_send_email("email1", params) do 
    # do work 
    end 
    # ... 
end 

這比任何帶回調的替代方法都簡單得多。你保持對它的控制。如果需要,添加或更改共享邏輯並添加條件邏輯很容易。

0

我喜歡使用Elixir的module attributes來啓動一連串的tail-call優化函數調用。這可以很容易地在一個地方聲明你的回調。

defmodule MyMod do 

    @before_filter [:check_email] 

    def check_email(1), do: true 
    def check_email(state), do: false 

    def save(state) do 
    save(state, @before_filter) 
    end 

    defp save(state, []) do 
    # do actual save 
    {:ok, state} 
    end 

    defp save(state, [callback|tail]) do 
    if :erlang.apply(__MODULE__, callback, [state]) do 
     save(state, tail) 
    else 
     {:error, callback, state} 
    end 
    end 
end