对象设计:如何组织/结构“收集类”
-
04-10-2019 - |
题
我目前正在努力了解如何组织/构建我已经创建的课程。班级进行以下操作:
- 作为在构造函数中的输入,它需要集合日志
- 在构造函数中,它通过实现我的业务逻辑的一系列算法来验证并过滤日志
- 在完成所有过滤和验证后,它将返回有效和过滤日志的集合(列表),该日志可以在UI中以图形方式显示给用户。
这是一些简化的代码,描述我正在做什么:
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;
其他关键输入:
- 我预见到应用程序中存在的这些过滤集合中只有一个(因此,我应该将其作为静态类吗?或者也许是单身人士?)
- 创建对象的可测试性和灵活性很重要(因此,也许我应该将其保留为实例性的可检验性?)
- 如果可能的话,我宁愿简化日志的放置,因为实际变量名称很长,并且需要60-80个字符才能获取实际数据。
- 我使该课程简单的尝试是,类的唯一目的是创建此验证数据集合。
我知道这里可能没有“完美”的解决方案,但是我确实试图通过这种设计来提高自己的技能,我非常感谢您的建议。提前致谢。
编辑:
多亏了所有答案,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);
解决方案
我的看法是,您正在查看一种返回过滤日志集合的方法,而不是包装您的业务逻辑的集合类。像这样:
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();
}
}
}
其他提示
听起来您对日志做三件事:
- 验证他们
- 过滤它们和
- 访问他们
您想将日志存储在集合中。标准列表集合非常适合
我建议您将您的关注点分为上面的三个步骤。
考虑
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));
关注点的分离使测试和可维护性更好。并远离单身人士。由于许多原因,包括可检验性,它们不受欢迎。
一些想法:
正如您正确指出的那样,使用实例类可改善可测试性。
如果(a)整个系统中只有一个实例,则应使用单例 和 (b)您需要在应用程序的多个不同位置访问此实例,而不必传递对象。应避免不必要使用单身模式(或任何其他类型的“全球状态”),因此,除非(b)在您的情况下也得到满足,否则我在这里不使用单身人士。
要进行简单的删除,请考虑使用 索引器. 。这将使您写作:
FilteredCollection filteredlogs = new FilteredCollection( secialArrayInput ); //Example of accessing data filteredlogs[5].MyLogData;
- 如果您的班级仅由构造函数和一个字段组成以访问结果,则使用简单 方法 可能比使用 班级. 。如果您想以奇特的方式做,可以将其写成 扩展方法 为了
SpecialArray<MyLog>
, ,允许您这样访问它:
List<MyLog> filteredlogs = secialArrayInput.Filter(); //Example of accessing data filteredlogs[5].MyLogData;
如果您想为最终过滤阵列继承SpecialArray的界面,请从具有实例成员的SpecialArray Instad派生。这将允许:
过滤collectection [5] .mylogdata; ETC..