我有一个名为“ HotelUtilities”的公共类,其中包含许多方法。实现可在HotelUtilities方法之间共享的TEMPORARY对象的最佳方法是什么? (我不希望在HotelUtilities主类之外访问该对象。)最好的方法是为游客使用结构,其他类或其他东西吗?例如,看一下TEMPORARY对象“ Visitor” ...
namespace Utilities
{
public static class HotelUtilities
{
public class TempVisitor
{
internal Guid UserId;
internal string EmailAddress;
internal string FirstName;
internal string LastName;
internal integer CountryCode;
}
public static List<TempVisitor> GetForeignVisitors()
{
Visitor对象只是TEMPORARY,并且只能由HotelUtilities类中的各种方法使用/共享。我不希望在HotelUtilities之外使用它。
谢谢!
答案 0 :(得分:1)
要回答您的直接问题,您可以定义在公共方法中使用的空类或接口。有一个私有类,可以使用您想要的属性/字段来扩展空类,并将其强制转换。
public static class HotelUtilities
{
public interface ITempVisitor
{
}
private class HiddenTempVisitor : ITempVisitor
{
internal Guid UserId;
}
public static List<ITempVisitor> GetTempVisitors()
{
return new List<ITempVisitor>() { new HiddenTempVisitor { UserId = Guid.NewGuid } };
}
public static void UseTempVisitors(List<ITempVisitor> visitors)
{
foreach (HiddenTempVisitor visitor in visitors)
{
Console.WriteLine(visitor.UserId);
}
}
}
但是,对我来说,这似乎确实是一种代码气味。实际上,我认为这很可怕。考虑如果其他人创建了自己的扩展ITempVisitor的类,则UseTempVisitors将因无效的强制转换异常而崩溃。
另一种可能性是将返回类型更改为object
,并且在需要使用它时,该方法接受一个对象并将其强制转换为List。这样,TempVisitor是否为私有并不重要,因为它不会成为任何公共接口的一部分。但这仍然很糟糕,因为当传入List以外的数据类型时,编译器不会给出错误。
由于您尝试做的事情与OO设计不太吻合,这可能意味着您可以重新设计代码,使其工作更加自然。在非静态类中,您可以将TempVisitor类设为私有,并将TempVisitors列表保留在私有字段中。为了使代码更易于理解,您可能希望将使用TempVisitor的方法提取到名称更有意义的新类中,但是有些人认为实用程序/帮助程序类是反模式,因此这样做可能会很好无论如何。
public class EventGuestEmailer
{
private class GuestInfo
{
public Guid GuestId;
public string EmailAddress;
}
private List<GuestInfo> _guests;
private IDataAccess _dataStore;
private IEmailSender _emailer;
public EventGuestEmailer(IDataAccess dataStore, IEmailSender emailer)
{
_dataStore = dataStore;
_emailer = emailer;
}
public void GetGuestsAtEvent(int eventId)
{
if (_guests != null) throw new InvalidOperationException($"Cannot call {nameof(GetGuestsAtEvent)} more than once");
_guests = new List<GuestInfo>();
foreach (var result in _dataStore.GetEventAttendees(eventId))
{
if (result.IsGuest)
{
_guests.Add(new GuestInfo { GuestId = restult.GuestId, EmailAddress = result.EmailAddress });
}
}
}
public SendEmailToGuests(ITemplate emailTemplate)
{
if (_guests == null) throw new Exception($"{nameof(GetGuestsAtEvent)} must be called before {nameof(SendEmailToGuests)}");
foreach (var guest in _guests)
{
var emailBody = template.Apply(guest.GuestId);
_emailer.Send(emailBody, guest.EmailAddress);
}
}
}
这有几个优点。类名描述了它的作用,而HotelUtilities
没有描述,这使单一职责类更易于理解。它是可测试的,使用模拟框架创建其使用的接口的模拟,并且您可以轻松测试类的业务逻辑,包括边缘情况和错误情况。它封装了业务逻辑单元,因此,如果在事件发生后对向谁发送电子邮件的需求发生变化,则由于使用了一个有用的名称,因此很容易找到该类,并且代码位于一个位置,而不是将访问者列表放在一个位置,从另一个模板构建电子邮件正文,然后从第三位发送电子邮件。
基本上,您的问题就像是XY problem的情况。您正在做某事,遇到一个问题,您正在寻找解决方法。如果退后一步,寻找其他方法,可能会找到根本不需要解决方法的解决方案。