为类方法定义临时对象



我有一个名为"HotelUtilities"的公共类,它包含许多方法。实现可在HotelUtilities方法之间共享的TEMPORARY对象的最佳方式是什么?(我不希望在主HotelUtilities类之外访问对象。)对Visitor使用结构、其他类或其他东西是最佳做法吗?例如,看看"Visitor",TEMPORARY对象。。。

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之外使用。

谢谢!

要回答您的直接问题,您可以定义一个在公共方法中使用的空类或接口。拥有一个私有类,该类使用所需的属性/字段扩展空类,并强制转换它们。

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没有,这使得单个责任类更容易理解。它是可测试的,使用mocking框架来创建它使用的接口的mock,并且可以轻松地测试类的业务逻辑,包括边缘情况和错误情况。它封装了一个业务逻辑单元,因此,如果在事件发生后,关于向谁发送电子邮件的要求发生了变化,则由于有一个有用的名称,类很容易找到,并且代码在一个位置,而不是在一个地方获取访问者列表,从另一个地方的模板构建电子邮件正文,并从第三个地方发送电子邮件。

基本上,你的问题感觉像是XY问题。你正在做一些事情,遇到了一个问题,你正在寻找解决方案。如果你退后一步,寻找不同的方法,你可能会找到一个根本不需要变通的解决方案。

相关内容

最新更新