【问题标题】:Dilemma of static class containg only static methods静态类的困境只包含静态方法
【发布时间】:2011-12-04 10:17:08
【问题描述】:

所以我的任务是映射两个酒店目录;两者都是 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);

正如代码所示,这两个类都是静态的。尽管我发现它们是正确的并且可以正常工作,但我仍然觉得这种设计在 OOP 方面存在问题。 这两个类都只是静态的,这很好吗?我发现不需要实例化它们。 此外,这个设计还有哪些其他缺陷?我确信存在缺陷。解决方案是什么?

【问题讨论】:

  • 想告诉我们您使用的是哪种语言?请适当地标记问题。
  • 听起来Kingdom Of Nouns里有些不安
  • @KerrekSB 这只是我想讨论的类设计;所以语言对我来说似乎并不重要。我还是添加了 C# 标签。
  • @HauntedGhost:有些语言(真正的语言?)没有“静态”类的概念,所以我认为这很重要。我想说你本质上只是在描述一些美化的命名空间。
  • 发布的代码很好,它是完成工作的面向任务的过程代码。你选择了优秀的名字,很容易理解发生的事情。您实际上确实有实例对象,Hotel 和 MappedHotel。没有什么需要修复的。

标签: c# oop class-design static-class


【解决方案1】:

Fear not the free function!

我觉得 CatalogMapper 映射 Hotel.Address 很可疑。要正确分解/封装,要么

  • CatalogMapper 应该在非酒店特定的Address 上运行,

  • 或者,如果Hotel.Address 在地理编码方面有某种特殊性,那么Hotel.Address 应该能够在没有CatalogMapper 的情况下将自己映射到地理编码。


根据 cmets 的澄清,我想提出以下建议。我不懂 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”的类时,如果它不是一个创建、拥有和控制对其他对象的访问的对象,那么它就是我们处于名词王国的警告警报。对象可以自己管理。如果该逻辑超出了单个类的范围,则您应该只为该逻辑创建一个单独的类。

【讨论】:

  • 我同意。我将 GeoCode 方法放在那里是因为该任务仅与映射相关。不过,它似乎不合适。我会将它重新安置在一些更相关/新的地方。
【解决方案2】:

另一种合理的方法是使CatalogManager 成为使用文件名初始化的非静态类。这将允许您从内存中部分使用文件并在需要时读取或写入。

【讨论】:

    猜你喜欢
    • 2012-09-04
    • 2011-01-17
    • 1970-01-01
    • 2011-02-13
    • 2011-07-11
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多