2010-05-25 208 views
2

我目前正在努力了解如何组织/构建我已经创建的类。类执行以下操作:对象设计:如何组织/构建“集合类”

  1. 作为其在构造函​​数输入,它通过一系列的算法需要记录的集合
  2. 在它验证构造函数和过滤日志实现我的业务逻辑
  3. 后所有过滤和验证都已完成,它会返回有效和过滤日志的集合(List),这些日志可以在用户界面中以图形方式呈现给用户。

下面是一些简单的代码描述我在做什么:

class FilteredCollection 
{ 
    public FilteredCollection(SpecialArray<MyLog> myLog) 
    { 
    // validate inputs 
    // filter and validate logs in collection 
    // in end, FilteredLogs is ready for access 
    } 
    Public List<MyLog> FilteredLogs{ get; private set;} 

} 

然而,为了访问这个集合,我一定要做到以下几点:

var filteredCollection = new FilteredCollection(specialArrayInput); 
//Example of accessing data 
filteredCollection.FilteredLogs[5].MyLogData; 

其他关键输入件:

  1. 我预见这些过滤集合中只有一个存在在应用程序(因此我应该使它成为一个静态类?或许单身?)
  2. 可测性和灵活性,在创建对象是很重要的(或许因此,我应该记住这一个类实例化可测性?)
  3. 我宁愿简化日志的间接引用,如果在所有可能的,因为实际的变量名称非常长,需要60-80个字符才能得到实际的数据。
  4. 我在保持这个类简单的尝试是该类的唯一目的是创建这个验证数据的集合。

我知道在这里可能没有“完美”的解决方案,但我真的想通过这种设计来提高我的技能,我非常感谢能够这样做的建议。提前致谢。


编辑:

感谢所有的应答者,既Dynami乐Savard和Heinzi确定我最终使用的办法 - 扩展方法。我结束了创建一个MyLogsFilter静态类

namespace MyNamespace.BusinessLogic.Filtering 
{ 
    public static class MyLogsFilter 
    { 
     public static IList<MyLog> Filter(this SpecialArray<MyLog> array) 
     { 
      // filter and validate logs in collection 
      // in end, return filtered logs, as an enumerable 
     } 
    } 
} 

,我可以做

IList<MyLog> filteredLogs = specialArrayInput.Filter(); 
ReadOnlyCollection<MyLog> readOnlyFilteredLogs = new ReadOnlyCollection<MyLog>(filteredLogs); 
+0

注意,来电者将能够创建后操作列表。最好不要公开FilteredLog,以确保其不变性。 – CurtainDog 2010-05-25 23:54:41

回答

1

我看到它的方式,你正在寻找一种方法,返回过滤日志的集合,而不是包装业务逻辑的集合类。像这样:

class SpecialArray<T> 
{ 
    [...] 

    public IEnumerable<T> Filter() 
    { 
     // validate inputs 
     // filter and validate logs in collection 
     // in end, return filtered logs, as an enumerable 
    } 

    [...] 
} 

但是,它看起来像什么,你真的希望实际上是对业务逻辑负责从SpecialArray类过滤日志,也许是因为你觉得自己逻辑的分离倒是很多事情要做不是真的担心SpecialArray,或者因为Filter不适用于所有通用案例SpecialArray

在这种情况下,我的建议是将分离你的业务逻辑在其他namespace,或许是一个以应用使用和/或需要其他组件表示业务逻辑,并提供您的功能扩展方法,较具体来说:

namespace MyNamespace.Collections 
{ 
    public class SpecialArray<T> 
    { 
     // Shenanigans 
    } 
} 

namespace MyNamespace.BusinessLogic.Filtering 
{ 
    public static class SpecialArrayExtensions 
    { 
     public static IEnumerable<T> Filter<T>(this SpecialArray<T> array) 
     { 
      // validate inputs 
      // filter and validate logs in collection 
      // in end, return filtered logs, as an enumerable 
     } 
    } 
} 

而当你需要使用的业务逻辑,它应该是这样的:

using MyNamespace.Collections; // to use SpecialArray 
using MyNamespace.BusinessLogic.Filtering; // to use custom log filtering business logic 
namespace MyNamespace 
{ 
    public static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main2() 
     { 
      SpecialArray<Logs> logs; 
      var filteredLogs = logs.Filter(); 
     } 
    } 
} 
+0

使用扩展方法实用程序的真棒解释!你正确地意识到对我来说,“Filter”不适用于所有的SpecialArray的泛型情况。到目前为止,我已经创建了一个扩展方法,它带有一个签名'Public static IList Filter(this SpecialArray myLog)',它似乎正常工作。我会遇到的唯一问题是 - 是否适合返回像过滤日志的“只读”列表?或者说是过度杀伤,我应该相信未来的程序员一旦创建就不会更改列表? – CrimsonX 2010-05-26 14:21:44

+0

我想我回答了我自己的问题 - 我可以强制列表只读,如果我希望这样做: 'IList filteredLogs = specialArrayInput.Filter(); ReadOnlyCollection readOnlyFilteredLogs = new ReadOnlyCollection (filteredLogs);' – CrimsonX 2010-05-26 14:44:18

1

的几点思考在代码中创建一个只读的这个集合:

  • 正如你正确地指向使用实例化类可以提高可测试性。

  • 如果(A)有类只有一个实例在你的整个系统 (B)你需要,而不必通过对象来访问你的应用程序的多个不同的地方这种情况下
  • 单身,应使用周围。应该避免不必要地使用Singleton模式(或任何其他类型的“全局状态”),因此除非(B)在您的情况下得到满足,否则我不会在此使用单例模式。

  • 对于简单取消引用,请考虑使用indexer。这将允许你写:

 
    FilteredCollection filteredlogs = new FilteredCollection(secialArrayInput); 
    //Example of accessing data 
    filteredlogs[5].MyLogData; 
  • 如果你的类只包含一个构造函数和字段的访问结果,使用简单方法可能比使用类比较合适。如果你想这样做的花哨手法,你可以把它写成一个extension methodSpecialArray<MyLog>,让您可以访问它像这样:
 
    List<MyLog> filteredlogs = secialArrayInput.Filter(); 
    //Example of accessing data 
    filteredlogs[5].MyLogData; 
+0

谢谢你指出单身模式的好处/不利因素。这是一个很好的选项列表。我希望做的不仅仅是创建对象的简单解引用,所以我认为扩展方法就是要走的路。我会遇到的唯一问题是 - 是否适合返回像过滤日志的“只读”列表?或者说是过度杀伤,我应该相信未来的程序员一旦创建就不会更改列表? – CrimsonX 2010-05-26 14:13:43

3

这听起来像你做三件事到您的日志:

  1. 验证它们
  2. 过滤它们 和
  3. 访问他们

您想将日志存储在集合中。标准列表集合非常合适,因为它不关心它里面的内容,给你LINQ并允许你用一个只读封装锁定集合

我建议你将问题分成上述三个步骤。

考虑

interface ILog 
{ 
    MarkAsValid(bool isValid); 
    ... whatever data you need to access... 
} 

把你的验证逻辑在一个单独的接口类

interface ILogValidator 
{ 
    Validate(ILog); 
} 

而且你的筛选逻辑在另一个

interface ILogFilter 
{ 
    Accept(ILog); 
} 

然后用LINQ,是这样的:

List<MyLog> myLogs = GetInitialListOfLogsFromSomeExternalSystem(); 
myLogs.ForEach(x => MyLogValidator(x)); 
List<MyLog> myFilteredLogs = myLogs.Where(x => MyLogFilter(x)); 

问题的分离使测试和可维护性变得更好。并远离单身人士。由于包括可测试性在内的许多原因,它们不受欢迎。

+0

感谢您使用接口建议替代设计!集合的整体过滤实际上取决于各个日志对象之间的顺序和相互关系,所以像myLogs.ForEach(x => MyLogValidator(x));'这样的操作对我来说不起作用。但是,你确实提醒我这个代码只是*做了过滤练习,所以我将在未来正确划分过滤/验证。 – CrimsonX 2010-05-26 14:28:42

+0

作为一个后续问题 - 你提到'标准列表集合是一个很好的选择,因为它不关心它的内容,给你LINQ并允许你用一个只读封装器来锁定集合。我知道我可以做一些事情,比如'Public List FilteredLogs {get; private set;}'当它在一个类中时,但是当方法调用返回一个集合时,有没有其他方法来锁定一个集合? (我认为没有) – CrimsonX 2010-05-26 14:30:21

+0

我想我回答了我自己的问题 - 我可以强制列表只读,如果我希望这样做:'IList filteredLogs = specialArrayInput.Filter(); ReadOnlyCollection readOnlyFilteredLogs = new ReadOnlyCollection (filteredLogs);' – CrimsonX 2010-05-26 14:44:49

0

如果您想为您最终过滤的数组继承特殊数组的接口,那么从具有实例成员的特殊数组实例派生。这将允许:
filteredCollecction [5] .MyLogData; 等..