装饰器,属性,方面和特征之间有什么区别?

时间:2016-10-20 21:17:41

标签: computer-science decorator theory traits aspect

从纯计算机科学(或计算语言学)的角度来看,我想知道这些词之间的区别:

  • 装饰
  • 属性
  • 方面
  • 性状

各种语言以不同的方式利用这些词语和功能。例如,在Python中,装饰器[根据Python Wiki](强调我的):

  

装饰器动态改变函数,方法或类的功能,而不必直接使用子类或更改正在装饰的函数的源代码。

这让我感觉非常类似于面向方面的编程工具,如PostSharp或DynamicProxy。即:

   [Profile]
   private static void SleepSync()
   {
       Thread.Sleep(200);
   }

来源:PostSharp Examples

在C#和Java(以及无数其他语言)中,属性可以指Decorator-ish模式(C#)或字段(Java)。

在C ++中通过boost或PhP通过内置的 trait 字,我们可以使用特征来扩展类,如下所示:https://en.wikipedia.org/wiki/Trait_(computer_programming)

所以,来自一个纯粹的"这一点,所有这些实际上是什么的规范定义是什么?有没有更好的方法来定义它们?

1 个答案:

答案 0 :(得分:10)

<强>装饰

我认为Decorator在设计模式方面。设计模式以多种语言识别,特别是面向对象的语言。然后,作为模式的装饰器是一个包装器,它添加了正在装饰的函数或类中不存在的功能。

我能想到的最简单的例子是装饰器功能。功能

int foo(int x)

可以由另一个接受第二个参数的函数修饰,用它做其他事情,然后依次调用foo(),传递原始参数x。

int bar(int x, int y) {
    return y*y + foo(x);
}

虽然设计模式通常在类级别应用,但这里的原理是相同的,我认为它很好地说明了装饰器的含义。每种特定语言是否符合这一点是另一回事。一种语言可能还有其他东西,它称之为装饰者&#39; - 但对我来说,这个概念最符合装饰一些简单的附加功能的想法,而不需要改变原始代码甚至使用继承。

另一个常见的例子是Java中的I / O类。有基本的

OutputStream s

然后你可以使用更专业的类来装饰它,具体取决于所处理的数据类型,或者你想要读取数据的格式:

OutputStream s1 = new FileOutputStream("somefile.txt");

OutputStream s2 = new ByteOutputStream("rawdata.hex");

<强>属性

我倾向于将C#的属性理解为正确的理解,因为它与装饰者不同。属性分配的语义值可以因用户而异,甚至可以在使用相同属性的API之间。例如,我可能有两个功能:

[Logging] private void a() { ... }
[Security] private void b() { ... }

我可以为其分配一个日志记录属性和一个安全属性,这些属性的含义可能与检查这些属性的客户端API不同。可以使用log4j来实现日志记录,可以使用另一个API。这里的定义更加流畅,并且可以由我的代码的不同方或用户进行解释。当然可以使用属性作为装饰器,但属性可以用于更多。

仅仅为了消除歧义,word属性也用于表示类的成员变量。在这里,我们讨论的是更大,更抽象的概念,即为现有对象或类分配预定义的语义值。 Java称这些注释为。

在我看来,作为一个属性的一个限定词,就我们所说的而言,它并不是间接地直接修改行为。例如,将[Logging]属性指定给某些内容并不会以任何方式更改其代码。它就像附上其他人正在寻找的名牌一样。当另一个程序或应用程序看到名称标签时,它会推断出某些事情,并可能相应地改变其行为。但是(至少在Java中)注释或属性不直接修改任何东西 - 再次,只是一个名称标签。这在C#或其他支持属性的语言中可能略有不同,在这种情况下,我会将它们视为更高级的属性或其他完全属性。

<强>方面

面向方面编程(AOP)意义上的一个方面是一种自修改或自我更新的代码构造。它将一段代码定义为更具延展性(一个切入点),并允许特定部分在一个或多个可能的更新,补丁或同一代码段的不同版本之间进行交换。

你可以使用方面做一些与装饰器和属性相同的东西吗?当然。但是你为什么要给自己头疼呢? AOP就像是OOP的下一步,只有在必要时才应该使用它。什么时候需要?当一个特定的应用程序有很多&#34;交叉问题&#34;像安全或日志记录 - 例如,银行应用程序。这些问题交叉;它们跨越传统的界限,形成了很好的定义的类和包。当你记录时,除非你记录所有内容,否则它不会有很多好处;因此,这种关注是贯穿各领域的。因此,当您更新一个类的日志记录机制时,很难同时修改所有其他类和API,但它也是必要的。否则,您的日志记录现在不一致且容易混淆,并且更难以用于故障排除或监视。

为了使这些类型的更新不那么令人头疼,引入了面向方面的语言,如AspectJ。我没有遇到过&#34;方面&#34;这意味着除此之外的任何东西,但可能有一些如前所述的装饰器。一种特定的语言可能会把某些东西称为一个方面,但它可能看起来更像是我们已经讨论过的其他事情。

<强>性状

Trait是界面的同义词,或者至少是它在我所研究的语言中的表现方式。

接口是一种OOP概念,它在不实现行为的情况下声明行为。创建这些预期的行为可以使这些行为变得通用,并且可以在不关心细节的情况下进行一般性调用。它留给了子类来实现它们。

经典的OOP示例是Animal,有两个子类,Cat和Dog。

public interface/trait Animal {
    public void speak();
}
public class Cat implements Animal {
    public void speak() {
        output("Meow.");
    }
}
public class Dog implements Animal {
    public void speak() {
         output("Bark!");
    }
}

这也是多态性的一个很好的例子 - 其中一个倾向于使非计算机人员畏缩的词。这只意味着猫和狗有个人行为,如果我宣布一个动物对象,我不在乎你给我什么样的。你可以给我一只猫或一只狗。因为两者都是动物,在任何一种情况下,我所要做的就是调用我的Animal对象的speak()函数,我可以放心,在任何一种情况下都会出现正确的结果。每个子类都知道它需要做什么。在C ++中,这里的水域更加泥泞,但一般概念是相同的(读入关键字&#39;虚拟&#39;如果你想开始那个兔子洞)。

<强>层的总结

我希望能够解决一些困惑。正如你所说,似乎许多不同的语言对于这些语言都有许多不同的含义,这无疑会导致混乱。我相信如果你进一步研究它,你会发现这些是标准的含义。我已经用多种语言(VB,C ++,C#,Java,Paschal,PHP,Perl)编程了18年以上,这些是我认为最适合作为一种标准的定义。

我当然欢迎进一步讨论我所说的话。