如何“很好地”实现以下模式:(有一点arrrgh为什么我不能只使用公共变量)
我有一大堆数据,一组类可以生成,另一组类可以使用。有多种方法可以生成和使用这些数据。数据集具有固定的层次结构,其中包含多个级别的值字段。我有数字,枚举,字符串。
所以,在我的应用程序的原型版本中,我以一种完全公开的方式将一堆类一起编写:
public class AllData
{
public IdentifyData identifyData;
public FirmwareData firmwareData;
public VersionData versionData;
public TestData testData;
public ServiceData serviceData;
public ErrorLog errorLog;
public AllData()
{
identifyData = new IdentifyData();
versionData = new VersionData();
firmwareData = new FirmwareData();
testData = new TestData();
serviceData = new ServiceData();
errorLog = new ErrorLog();
}
}
(...)
public class FirmwareData
{
public DataStatus status;
public int build;
public int variant;
public FirmwareData()
{
status = new DataStatus();
}
}
(Etc.)
现在我正在做软件的真实版本,并希望做正确的事情,所以我开始为所有东西提供财产。但是,我觉得代码受此影响很大。它变得庞大而丑陋,在我的情况下,好处并不明显。
我考虑使用结构,但我真的不想一直按值传递所有这些数据。此外,我还需要做一些范围和理智的检查。
有关如何以一种很好的方式实现此数据模型的任何线索? (要注意我在OOP和C#方面不是很有经验)
如果可能的话,我希望在将数据移交给消费者类时将数据变为只读,怎么可能这样做呢?
谢谢和最好的问候
拉斯
答案 0 :(得分:1)
无论你做什么都不要使用struct
。 特别是,如果它们是可变的!
只需使用属性 - 它们通常比字段更受欢迎(特别是如果您打算使用前端系统使用,例如TypeDescriptor
来获取组件信息 - Asp.Net MVC会这样做)。
我的起始规则是,如果它是公开的或受保护的(在大多数情况下),我将使用一个属性。如果它受保护或私有 且不可变 ,那么我将考虑使用只读字段。虽然这条规则总是有例外,但这只是我自己的出发点。我将很少使用公共字段,除了在辅助类中进行单元测试。
只读问题是另一回事,实际上只有在做使用属性时才能解决。
我会使用只读接口:
public interface IMyData
{
int Value { get; }
}
然后,如果您需要它们,您的类可以读/写:
public class MyData : IMyData
{
public int Value { get; set; }
}
实现了接口 - 使用和理解MyData
(即您的生产者)的代码可以写入它,但只需要读取的代码只使用该接口。使用这样的抽象还有一个额外的好处,即允许您的消费者代码以任何形式使用您的数据。例如。您可以将接口实现添加到EF生成的实体类型(如果这是您选择的ORM。
但请注意,您不能始终强制执行只读 - 特别是如果您打算使用泛型字典等类型。
对于在构造之后必须始终是不可变的对象,然后使用构造函数并隐藏setter。所以再次在MyData
课上:
public int Value { get; private set; }
public MyData(int value){
Value = value;
}
当然,您也可以使用readonly字段(但这两种方法都不会实际阻止真正想要修改对象的人能够这样做,因为这两种方法都可以通过反射来破坏。)
答案 1 :(得分:0)
设计模式在这里没有用,这关系到你想要如何组织你的课程及其关系。
首先将所有字段声明为private
并在类方法中公开数据的“做事”,或者在某些情况下返回它们,但要尽量避免客户端可以直接访问字段和也许改变它们。
http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
这只是一个起点。
答案 2 :(得分:0)
如果您的数据布局一直都是固定的,并且不需要任何数组,那么外露字段结构可能是最合适的。应用于类时,字段应封装在属性中的概念很好,但在应用于结构时通常很糟糕。从根本上说,struct是一个用胶带绑定在一起的字段集合。如果struct1
和struct2
是相同的结构类型,则语句struct1 = struct2
将通过使用struct1
中相应值的值覆盖其所有字段来改变struct2
。结构类型类型的定义中的任何内容都不可能改变它。鉴于结构的所有字段总是通过批量分配公开暴露于变异,所以最好有一个结构,它将自己宣传为与管道胶带粘在一起的一堆变量,而不是假装成其他东西。 / p>
使用暴露场结构的最大问题具有讽刺意味的是它们最大的资产:使用其他数据类型时,使用暴露场结构(尤其是嵌套结构)的许多便捷方法都没有方便的等价物。如果有一个嵌套结构类型的数组,并希望更新内部元素,可以执行以下操作:
TriangleList[index].Vertex1.X += 4;
并更新元素的一部分。如果用List<TriangleStruct>
替换数组,则代码必须变为:
var temp = TriangleList[index]; temp.Vertex1.X += 4; TriangleList[index] = temp;
仍然不太糟糕。但是,假设需要更改类型以支持任意多边形。一个人不能再用暴露字段结构来表示类型(如果它包含一个数组,复制结构不会复制数组而只是一个引用;更改结构的一个副本中的坐标会因此改变它们,可能导致讨厌的错误)。任何操作结构的代码都必须完全重写,这些代码是基于它可用的,就像暴露的字段结构一样。
在决定是否使用公开字段结构或其他一些数据类型时,请考虑能够使用方便的访问形式的程度,以及结构可能发生变化的可能性。如果事物的使用方式意味着它的语义不能在不重写所有使用它的代码的情况下改变,并且以结构形式访问它会更方便,然后使用暴露的字段结构。没有理由让你的代码更加繁琐,以适应YAGNI(你不需要它)时永远不会发生的未来变化。