你将如何实现一个"性状"设计模式在C#中? [英] How would you implement a "trait" design-pattern in C#?

查看:99
本文介绍了你将如何实现一个"性状"设计模式在C#中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这个功能不会在C#中存在,但PHP最近增加了一个功能叫做性状我认为是一个有点傻起初,直到我开始思考它。

I know the feature doesn't exist in C#, but PHP recently added a feature called Traits which I thought was a bit silly at first until I started thinking about it.

说我有叫一个基类客户端客户端有一个名为名称的一个属性。

Say I have a base class called Client. Client has a single property called Name.

现在我开发将由许多不同的客户可以使用可重复使用的应用程序。所有客户的认同,客户端应该有一个名称,因此它在基类之中。

Now I'm developing a re-usable application that will be used by many different customers. All customers agree that a client should have a name, hence it being in the base-class.

现在客户A走过来说,他还需要跟踪客户的重量。客户B不需要的重量,但他想要跟踪高度。 。客户C要同时跟踪体重,身高

Now Customer A comes along and says he also need to track the client's Weight. Customer B doesn't need the Weight, but he wants to track Height. Customer C wants to track both Weight and Height.

使用特点,我们可以使两者的重量和高度功能特点:

With traits, we could make the both the Weight and the Height features traits:

class ClientA extends Client use TClientWeight
class ClientB extends Client use TClientHeight
class ClientC extends Client use TClientWeight, TClientHeight

现在我能满足我所有的客户的需求,而不会增加任何额外的绒毛类。如果我的客户回来后,​​说:哦,我真的很喜欢这个功能,我可以拥有它吗?,我刚更新的类定义,包括额外的特征。

Now I can meet all my customers' needs without adding any extra fluff to the class. If my customer comes back later and says "Oh, I really like that feature, can I have it too?", I just update the class definition to include the extra trait.

你将如何做到这一点在C#?

How would you accomplish this in C#?

,因为我想要的属性和任何相关的具体方法定义的接口并不在这里工作,我不想重新实现他们的类的每个版本。

Interfaces don't work here because I want concrete definitions for the properties and any associated methods, and I don't want to re-implement them for each version of the class.

(通过顾客,我的意思是谁已聘请我作为一个开发者的文字的人,而通过客户端我指的编程类,我的每一个客户都有客户,他们希望记录信息)

(By "customer", I mean a literal person who has employed me as a developer, whereas by "client" I'm referring a programming class; each of my customers has clients that they want to record information about)

推荐答案

可以。获得使用标志接口和扩展方法的语法

You can get the syntax by using marker interfaces and extension methods.

先决条件:接口需要定义它后来被扩展方法的合同。基本上,接口定义了能够实现一特质的合同;理想情况下,你添加接口的类应该已经具备了本接口的所有成员,这样的没有的额外的实施是必需的。

Prerequisite: the interfaces need to define the contract which is later used by the extension method. Basically the interface defines the contract for being able to "implement" a trait; ideally the class where you add the interface should already have all members of the interface present so that no additional implementation is required.

public class Client {
  public double Weight { get; }

  public double Height { get; }
}

public interface TClientWeight {
  double Weight { get; }
}

public interface TClientHeight {
  double Height { get; }
}

public class ClientA: Client, TClientWeight { }

public class ClientB: Client, TClientHeight { }

public class ClientC: Client, TClientWeight, TClientHeight { }

public static class TClientWeightMethods {
  public static bool IsHeavierThan(this TClientWeight client, double weight) {
    return client.Weight > weight;
  }
  // add more methods as you see fit
}

public static class TClientHeightMethods {
  public static bool IsTallerThan(this TClientHeight client, double height) {
    return client.Height > height;
  }
  // add more methods as you see fit
}

使用这样的:

var ca = new ClientA();
ca.IsHeavierThan(10); // OK
ca.IsTallerThan(10); // compiler error



编辑:提出的问题是如何额外的数据可能被存储。

The question was raised how additional data could be stored. This can also be addressed by doing some extra coding:

public interface IDynamicObject {
  bool TryGetAttribute(string key, out object value);
  void SetAttribute(string key, object value);
  // void RemoveAttribute(string key)
}

public class DynamicObject: IDynamicObject {
  private readonly Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.Ordinal);

  bool IDynamicObject.TryGetAttribute(string key, out object value) {
    return data.TryGet(key, out value);
  }

  void IDynamicObject.SetAttribute(string key, object value) {
    data[key] = value;
  }
}



然后,将性状的方法可以添加和检索数据

And then, the trait methods can add and retrieve data if the "trait interface" inherits from IDynamicObject:

public class Client: DynamicObject { /* implementation see above */ }

public interface TClientWeight, IDynamicObject {
  double Weight { get; }
}

public class ClientA: Client, TClientWeight { }

public static class TClientWeightMethods {
  public static bool HasWeightChanged(this TClientWeight client) {
    object oldWeight;
    bool result = client.TryGetAttribute("oldWeight", out oldWeight) && client.Weight.Equals(oldWeight);
    client.SetAttribute("oldWeight", client.Weight);
    return result;
  }
  // add more methods as you see fit
}

请注意:通过实施 IDynamicMetaObjectProvider 以及对象甚至会允许暴露通过DLR的动态数据,用动态使用时,使得进入透明的附加属性关键字。

Note: by implementing IDynamicMetaObjectProvider as well the object would even allow to expose the dynamic data through the DLR, making the access to the additional properties transparent when used with the dynamic keyword.

这篇关于你将如何实现一个&QUOT;性状&QUOT;设计模式在C#中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆