use*_*993 6 c# oop design-patterns
public class HourlyForecastData
{
public DateTime DateTime { get; private set; }
public decimal TemperatureCelcius { get; private set; }
public decimal DewPoint { get; private set; }
public string Condition { get; private set; }
public int ConditionCode { get; private set; }
public int WindSpeed { get; private set; }
public string WindDirection { get; private set; }
public decimal WindDegrees { get; private set; }
public int UltravioletIndex { get; private set; }
public decimal Humidity { get; private set; }
public decimal WindChill { get; private set; }
public int HeatIndex { get; private set; }
public decimal FeelsLike { get; private set; }
public decimal Snow { get; private set; }
public HourlyForecastData(DateTime dateTime, decimal temperatureCelcius, ...)
{
DateTime = dateTime;
TemperatureCelcius = temperatureCelcius;
//...set all the other properties via constructor
}
}
Run Code Online (Sandbox Code Playgroud)
我正在努力学习更好的软件设计和OOP.我正在创建一个可以访问回复XML的气象服务的库.服务提供了许多不同的字段,因此我为每个XML字段创建了属性.但是,通过构造函数设置该数量的属性会感觉有点混乱.我可以省略构造函数并拥有公共setter但我正在尝试创建一个不可变类.
我已经环顾了不同的设计模式,似乎有一些"Builder"和"Factory"模式.但是,我很难理解如何将其应用到我的代码中.或者我应该使用完全不同的东西来填充这些对象中的属性?
在这种情况下,组合可能是一个很好的选择.特别是因为有些参数属于特定类别.
例如:
public int WindSpeed;
public string WindDirection;
public decimal WindDegrees;
Run Code Online (Sandbox Code Playgroud)
为它们创建一个新对象,然后访问不同的值:
weatherData.Wind.Speed;
Run Code Online (Sandbox Code Playgroud)
并将新的wind对象传递给构造函数:
var wind = new Wind(xmlData.WindSpeed, xmlData.WindDirection, xmldata.WindDegrees);
var weatherReport = new WeatherReport(wind, /* .... */);
Run Code Online (Sandbox Code Playgroud)
我还会介绍几个枚举.因为到目前为止,例如,用户weatherReport必须知道字符串WindDirection可以具有哪些值.如果将字符串转换为枚举,则使用不同的值会更容易.
最后要注意的是,我通常只使用构造函数,如果实际上必须为类指定一些有效状态的值.例如,在您的情况下,最小有效状态是日期和温度?然后将它们放在构造函数中.
Re 有更好的 OOP 方法吗?
类上的大量属性通常表明需要拆分类( SOLID 的单一职责原则)。
例如,HourlyForecastData模型风(速度和方向)、降水(雪、露水和雨)和温度(最小、最大...)这些问题可以分为不同的类,然后将HourlyForecastData是三。
回复:构建器模式
构建器模式可用于减轻构建大型(通常不可变)类或图期间的负担,但显然需要额外的(可变)构建器类来构建目标类表示(即)HourlyForecastData并最终创建它(即,通过将所有参数传递给构造函数来构造它)。因此,如果这就是您所要求的“更好”,那么这并不是更少的努力,但这肯定可以更容易阅读,例如:
HourlyForecastData todaysForecast = new HourlyForecastDataBuilder()
.WithBaseline(ObjectMother.WinterSnow) // Provide an archetype
.WithPrecipitation(snow: 5, rain:1) // Dew defaults to 0
.Build();
Run Code Online (Sandbox Code Playgroud)
如果一个地区的天气模式经常稳定并且只需要进行小的调整,则基线原型/对象母体将很有用。IMO 构建器模式在测试中最有用。我看不出 Xml 序列化用法有明显的适合性。
另请参见命名参数和可选参数
回复:不变性
从技术上讲,私有 setter 仍然允许可变性,尽管仅限于类本身。C#6 及更高版本支持仅 getter 自动属性,这是实现不可变属性的最简单形式
public class HourlyForecastData
{
public DateTime DateTime { get; }
...
public HourlyForecastData(DateTime dateTime, ...)
{
// Get only auto properties can only be set at construction time
DateTime = dateTime;
...
Run Code Online (Sandbox Code Playgroud)
不相关,但Scala 提供了比 C# 更简洁的语法,通过在(主)构造函数中声明一次来定义类上的不可变公共属性:
class HourlyForecastData(val temperature: Int, val station: String, ...) {
}
Run Code Online (Sandbox Code Playgroud)
无需任何其他属性或支持字段,同时表达和强制不变性。然而,调用者仍然有责任提供所有参数(无论是直接提供,还是通过构建器等)。
Re: Xml 如果你提供API,我建议使用WebAPI。我建议不要将 Xml 序列化问题构建到 DTO 类中,而是依赖Content Negotiation。这将允许调用者确定是否应以 Xml 或 JSON 格式返回数据。
*但请注意,Xml 反序列化技术通常使用反射来填充 DTO 属性,这可能要求可序列化属性具有设置器(即使是私有的)。