Elixir中模块的结构重用

时间:2015-09-29 15:03:15

标签: elixir

有什么机制可以实现结构重用:定义一个结构,其中包含另一个结构的所有字段以及它自己的一些结构。

我有这些看起来像这样的结构

defmodule VideoView do
  defstruct name: nil, description: nil, video_link: nil, ...
end

defmodule ImagesView do
  defstruct name: nil, description: nil, images: [], ...
end

defmodule Model3DView do
  defstruct name: nil, description: nil, model: nil, ...
end

其中有7个。在我的UML中,它们都来自Viewnamedescription。我希望他们所有人都能分享这些共同的领域,特别是如果我决定添加或删除一个公共领域,这可能是当前方法的真正痛苦。

3 个答案:

答案 0 :(得分:10)

正如其他人所建议的那样,你应该再考虑一下你是否真的从重新使用结构中获得了那么多。

如果仍然需要它来减少大量复制,可以使用模块属性来初始存储struct选项。然后,您可以使用defstruct重复使用它们,并通过函数公开其他模块:

defmodule View do
  @common_fields [name: nil, description: nil]
  def common_fields, do: @common_fields
  defstruct @common_fields
end

如果您不打算单独使用View,可以直接将公共字段放在函数中:

defmodule View do
  def common_fields do
    [name: nil, description: nil]
  end
end

然后,您可以使用其他结构中的公共字段,如下所示:

defmodule VideoView do
  defstruct View.common_fields ++ [video_link: nil, ...]
end

defmodule ImagesView do
  defstruct View.common_fields ++ [images: [], ...]
end

defmodule Model3DView do
  defstruct View.common_fields ++ [model: nil, ...]
end

答案 1 :(得分:2)

据我所知,没有简单明了的方法1.如果你对宏进行了充分的处理,你可能会想出一个。 Elixir中的结构实际上是一个零参数__struct__/0的函数,它返回一个映射 使用默认值。

您可以将另一个模块的功能导入到您的模块中,并且可以使用您自己的定义覆盖另一个模块中定义的功能,如果 其他模块中的函数定义为可重写。

use OtherModule

但是你不能导出那些函数,你只能导出定义的函数 在模块中。

如果你想继承Elixir不是你想要使用的语言。 Elixir不是继承,而是专注于功能的组合和数据的转换。从OO世界带来很多行李只会让你失望。

在这种情况下,如果您需要来自另一个模块的数据结构,您应该考虑组合而不是继承。一种方法是

defstruct other_module: struct(Other_Module), foo: nil , bar: 1 

在大多数情况下,Elixir是一种基于表达式的语言,您几乎总能为运行时函数调用交换数据值,反之亦然。

答案 2 :(得分:1)

  1. 结构重用:
  2. 一个。首先考虑你真的需要重用结构。听起来好像你正在考虑将结构作为对象的一种形式。不是那样的。

    湾如果我们更好地了解您的用例,那么建议您采取行动将会有所帮助。

    1. 功能重用:
    2. 一个。你认为这是错误的。在OO中,通过派生类中的继承和覆盖函数实现不同的行为。在FP中没有必要,因为你可以简单地将新功能作为参数传递给函数。

      请考虑以下示例代码:

      defmodule FReuseExample do
         def func1 do
            IO.puts "func1"
         end
      
         def func2 do
            IO.puts "func2"
         end
      
         def my_varying_func(f) do
            f.()
         end
      end
      

      然后我会这样称呼它:

      FReuseExample.my_varying_func(&FReuseExample.func1/0)
      

      或者如果我需要func2中指定的行为,那么我就这样做:

      FReuseExample.my_varying_func(&FReuseExample.func2/0)
      

      重点是我不需要继承层次结构。我可以简单地将我需要的行为作为参数传递给函数。继承的最初目的是根据所使用的更具体的类型来修改行为。如果我可以直接传递行为,我不再需要继承来获取它。