对象设计:如何组织/构建“集合类”

时间:2010-05-25 23:35:22

标签: c# collections object-design

我目前正在努力理解我应该如何组织/构建一个我已经创建的类。该课程执行以下操作:

  1. 作为构造函数中的输入,它需要一组日志
  2. 在构造函数中,它通过一系列实现我的业务逻辑的算法来验证和过滤日志
  3. 完成所有过滤和验证后,它会返回有效和已过滤日志的集合(List),这些日志可以在UI中以图形方式呈现给用户。
  4. 以下是一些描述我正在做的事情的简化代码:

    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. 我保持这个类简单的尝试是该类的唯一目的是创建这个验证数据的集合。
    5. 我知道这里可能没有“完美”的解决方案,但我真的想通过这种设计来提高我的技能,我非常感谢这样做的建议。提前致谢。


      修改

      感谢所有的回答者,Dynami Le-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);
      

4 个答案:

答案 0 :(得分:3)

听起来你对日志做了三件事:

  1. 验证它们
  2. 过滤它们 和
  3. 访问它们
  4. 您希望将日志存储在集合中。标准的List集合非常适合,因为它不关心它的内容,为您提供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));
    

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

答案 1 :(得分:1)

一些想法:

  • 正如您正确指出的那样,使用实例类可以提高可测试性。

  • 如果(A)整个系统中只有一个类的实例(B),您需要在应用程序的多个不同位置访问此实例时使用单例无需传递物体。应该避免不必要地使用Singleton模式(或任何其他类型的“全局状态”),所以除非(B)在你的情况下也满足,否则我不会在这里使用单例。

  • 对于简单的解除引用,请考虑使用indexer。这将允许您写:

    FilteredCollection filteredlogs = new FilteredCollection( secialArrayInput );
    //Example of accessing data
    filteredlogs[5].MyLogData;
  • 如果您的类只包含构造函数和访问结果的字段,则使用简单的方法可能比使用更合适。如果您想以奇特的方式进行,可以将其写为SpecialArray<MyLog> {{1}},允许您像这样访问它:
    List<MyLog> filteredlogs = secialArrayInput.Filter();
    //Example of accessing data
    filteredlogs[5].MyLogData;

答案 2 :(得分: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();
        }
    }
}

答案 3 :(得分:0)

如果要为最终过滤的数组继承SpecialArray的接口,则从具有实例成员的SpecialArray instad派生。这将允许:
    filteredCollecction [5] .MyLogData; 等。