静态类只包含静态方法的困境
本文关键字:困境 静态方法 包含 静态类 | 更新日期: 2023-09-27 18:11:01
我的任务是映射两个酒店目录;两者都是CSV文件。根据它们的职责,我创建了两个类:1. CatalogManager:处理目录的I/O操作。2. CatalogMapper:处理两个目录的映射任务。
定义如下:
public static class CatalogManager
{
public static List<Hotel> GetHotels(string filePath) { }
public static void SaveHotels (List<Hotel> hotels, string filePath) { }
public static void SaveMappedHotels (List<MappedHotel> hotels, string filePath) { }
public static List<string> GetHotelChains(string filePath) { }
}
public static class CatalogMapper
{
public static List<MappedHotel> MapCatalogs (List<Hotel> masterCatalog, List<Hotel> targetCatalog) { }
public static FetchAddressGeoCodes (Hotel.Address address)
{ // fetch address's geocode using Google Maps API }
public static string GetRelevantHotelChain (string hotelName)
{
List<string> chains = CatalogManager.GetChains();
// find and return the chain corresponding to hotelName.
}
}
一个典型的映射操作可能是这样的:
List<Hotel> masterCatalog = CatalogManager.GetHotels(masterFilePath);
List<Hotel> targetCatalog = CatalogManager.GetHotels(targetFilePath);
List<MappedHotel> mappedHotels = CatalogMapper.MapHotels(masterCatalog, targetCatalog);
CatalogManager.SaveMappedHotels(mappedHotels, mappedCatalogFilePath);
如代码所示,这两个类都是静态的。虽然我发现它们是正确的,并且可以正常工作,但我仍然觉得这种设计在面向对象方面存在一些问题。这两个类都是简单的静态的,这样可以吗?我发现没有必要实例化它们。此外,这个设计还有哪些缺陷?我确信缺陷是存在的。这些问题的解决方案是什么?
另一种合理的方法是使CatalogManager
成为一个用文件名初始化的非静态类。这将允许您使用部分内存中的文件,并在需要时读取或写入。
不要害怕自由函数!
我发现CatalogMapper
映射到Hotel.Address
是可疑的。要正确地分解/封装,
-
CatalogMapper
应该在非酒店特定的Address
上运行, -
或者,如果
Hotel.Address
是某种特殊的w.r.t GeoCodes,那么Hotel.Address
应该能够将自己映射到没有CatalogMapper
的GeoCode。
根据评论的澄清,我想提出以下建议。我不懂c#,所以我把它写成c++。我希望它能翻译
struct Hotel {
const Address & address () const;
// I typedef EVERTYTHING :-)
typedef std :: list <std :: string> StringList;
typedef std :: pair <Hotel, Hotel> Pair;
typedef std :: list <Hotel> Container; // TODO implicit sharing?
typedef std :: list <Pair> Mapping;
// NB will be implemented in terms of std::istream operations below,
// or whatever the C# equivalent is.
// These could arguably live elsewhere.
static Container load (const std :: string &);
static Mapping load_mapping (const std :: string &);
static void save (const std :: string &, const Container &);
static void save_mapping (const std :: string &, const Mapping &);
// No need for a "Manager" class for this.
static StringList load_chain (const string & file_name);
private:
static Hotel load (std :: istream &);
void save (std :: ostream &) const;
};
// Global namespace, OK because of overloading. If there is some corresponding
// generic library function which merges pair-of-list into list-of-pair
// then we should be specialising/overloading that.
Hotel :: Mapping merge (const Hotel :: Container &, const Hotel :: Container &);
struct GeoCode {
GeoCode (const Address &);
};
每当我看到一个名为"Manager"的类时,如果它不是一个创建、拥有和控制对其他对象访问的对象,那么它就是一个警告警报,告诉我们我们处于名词王国。对象可以自我管理。只有当逻辑超出单个类的范围时,才应该为该逻辑创建一个单独的类。