你将如何实现“特质” C#中的设计模式? [英] How would you implement a "trait" design-pattern in C#?

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

问题描述

我知道这个功能在C#中不存在,但PHP最近添加了一个名为特征,我以为是有点傻了,直到我开始考虑它。



说我有一个基类叫$ code >客户端。 客户端有一个名为 Name 的属性。



现在我正在开发可以被许多不同客户使用的可重用的应用程序。所有客户都同意客户应该有一个名字,因此它是在基地。



现在客户A来了,他还需要跟踪客户的重量。客户B不需要重量,但他想跟踪高度。客户C想跟踪重量和高度。



使用特质,我们可以使重量和高度功能都具有特征:

  class ClientA扩展客户端使用TClientWeight 
类ClientB扩展客户端使用TClientHeight
类ClientC扩展客户端使用TClientWeight,TClientHeight

现在,我可以满足所有客户的需求,而不会向课程添加任何额外的绒毛。如果我的客户稍后回来说哦,我真的很喜欢这个功能,我也可以这样做吗?,我只是更新类的定义,以包含额外的特质。



如何在C#中完成这个?



接口在这里不起作用,因为我需要具体的属性和任何关联方法的定义,我不想对于每个版本的课程,重新实施它们。



(客户),我的意思是一个以我为开发人员的字面人,而客户 我指的是一个编程类;我的每个客户都有客户想要记录信息)

解决方案

通过使用标记接口和扩展方法获取语法。



先决条件:接口需要定义随后由扩展方法使用的合同。基本上接口定义了能够实施特征的合同;理想情况下,添加界面的类应该已经具有接口的所有成员,以便需要额外的实现。

  public class Client {
public double Weight {get; }

public double Height {get; }
}

public interface TClientWeight {
double Weight {get; }
}

public interface TClientHeight {
double Height {get; }
$ b 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>重量;
}
//添加更多的方法,你认为合适
}

public static class TClientHeightMethods {
public static bool IsTallerThan(this TClientHeight client,double height){
return client.Height>高度;
}
//添加更多的方法,你认为合适
}

使用如下:

  var ca = new ClientA(); 
ca.IsHeavierThan(10); // OK
ca.IsTallerThan(10); //编译器错误

编辑:存储。这也可以通过做一些额外的编码来解决:

  public interface IDynamicObject {
bool TryGetAttribute(string key,out对象值);
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;
}
}

然后,trait方法可以添加和检索数据如果trait interface继承自 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){
对象oldWeight;
bool result = client.TryGetAttribute(oldWeight,out oldWeight)& amp;& client.Weight.Equals(oldWeight);
client.SetAttribute(oldWeight,client.Weight);
返回结果;
}
//添加更多的方法,你认为合适
}

注意:执行 IDynamicMetaObjectProvider 以及该对象甚至允许通过DLR公开动态数据,当与动态关键字一起使用时,可以访问附加属性。 p>

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.

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.

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
}

Use like this:

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

Edit: 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
}

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.

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

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