【问题标题】:Class design: file conversion logic and class design类设计:文件转换逻辑和类设计
【发布时间】:2009-09-18 11:47:40
【问题描述】:

这是非常基本的,但有点笼统的问题,所以我想听听人们的想法。我有一种情况,我需要获取一个现有的 MSI 文件并通过一些标准修改对其进行更新,然后生成一个新的 MSI 文件(旧文件的复制与更改)。

我开始使用一些公共方法和原始 MSI 的基本输入路径来编写这篇文章。问题是,要使其正常工作,调用者必须遵循严格的调用路径:

var custom = CustomPackage(sourcemsipath);
custom.Duplicate(targetmsipath);
custom.Upgrade();
custom.Save();
custom.WriteSmsXmlFile(targetxmlpath);

将所有转换逻辑作为构造函数的一部分而不是将它们作为公共方法提供会更好吗? (为了避免让调用者知道“正确的顺序”是什么):

var custom = CustomPackage(sourcemsipath, targetmsipath); // saves converted msi
custom.WriteSmsXmlFile(targetxmlpath); // saves optional xml for sms

然后,构造函数将直接复制 MSI 文件,对其进行升级并将其保存到目标位置。 “WriteSmsXmlFile 仍然是一个公共方法,因为它并不总是必需的。

我个人不喜欢让构造函数真正“做事”——我更喜欢能够调用公共方法,但假设调用者应该知道正确的调用顺序似乎是错误的?

另一种方法是先复制文件,然后将复制的文件传递给构造函数 - 但最好让类自己执行此操作。

也许我把它全部倒退了,需要两个类:SourcePackageTargetPackage,并将 SourcePackage 传递给 TargetPackage 的构造函数?

【问题讨论】:

    标签: class constructor


    【解决方案1】:

    我会按照您的第一个想法:将所有转换逻辑放在一个地方。没有理由向用户公开该序列。

    顺便说一句,我同意你关于不将动作放入构造函数的观点。我可能不会在构造函数中执行此操作,而是在单独的转换器方法中执行此操作,但这是个人喜好。

    【讨论】:

      【解决方案2】:

      可能只有我一个人,但想到一个构造函数做所有这些事情让我不寒而栗。但是为什么不提供一个 static 方法,它可以完成所有这些:

      public class CustomPackage 
      {
      
          private CustomPackage(String sourcePath) 
          {
               ...
          }
      
          public static CustomPackage Create(String sourcePath, String targetPath) 
          {
               var custom = CustomPackage(sourcePath);
               custom.Duplicate(targetPath);
               custom.Upgrade();
               custom.Save();
               return custom;
          }
      }
      

      此方法的实际优点是,除非转换过程实际成功(可选部分安全),否则您不必提供CustomPackage 的实例。

      编辑在 C# 中,这个工厂方法甚至可以根据Factory Pattern 被用作(通过使用委托)作为“真正的”工厂:

      public interface ICustomizedPackage 
      {
          ...
      }
      
      public class CustomPackage: ICustomizedPackage 
      {
          ...
      }
      
      public class Consumer 
      {
          public delegate ICustomizedPackage Factory(String,String);
      
          private Factory factory;
      
          public Consumer(Factory factory) 
          {
              this.factory = factory;
          }
      
          private ICustomizedPackage CreatePackage() 
          {
              return factory.Invoke(..., ...);
          }
      
          ...
      }
      

      及以后:

      new Consumer(CustomPackage.Create);
      

      【讨论】:

      • 这是一种有趣的、普遍适用的方法——有点像“工厂之光”?
      • 所以你可以这么说。特别是,您可以(至少在 C# 中)将其与委托一起使用,以便传递 Create 方法。
      • 谢谢 Dirk,我将您的回复设置为已接受。但是,当我点击赞成票时,它实际上减少了投票??当我尝试再次单击时,它说投票太旧而无法更改。我之前一定已经对这个回复投了赞成票,再次点击一定已经恢复了。奇怪的。无论如何,感谢您的彻底回答。
      【解决方案3】:

      您认为构造函数不应该做更多的工作而不是简单地初始化对象是正确的。

      在我看来,您需要的是一个 Convert(targetmsipath) 函数,它封装了对 DuplicateUpgradeSave 的调用,从而使调用者无需知道正确的操作顺序,而在同时将逻辑排除在构造函数之外。

      您还可以重载它以包含targetxmlpath 参数,当提供该参数时,它也会调用WriteSmsXmlFile 函数。这样,所有相关的操作都是从调用方的同一个函数调用的,并且操作的顺序总是正确的。

      【讨论】:

      • +1:另一个公共函数按正确的顺序做事没有错。
      • 问题是构造函数中指定的源路径不应该保存,但正如这里所说,我可以只要求为公共方法指定一个输出路径。
      【解决方案4】:

      在这种情况下,我通常使用以下设计:

      var task = new Task(src, dst); // required params goes to constructor
      task.Progress = ProgressHandler; // optional params setup
      task.Run();
      

      【讨论】:

        【解决方案5】:

        我认为有面向服务的方式和面向对象的方式。

        面向服务的方式是创建一系列过滤器,传递不可变的数据传输对象(实体)。

        var service1 = new Msi1Service();
        var msi1 = service1.ReadFromFile(sourceMsiPath);
        var service2 = new MsiCustomService();
        var msi2 = service2.Convert(msi1);
        service2.WriteToFile(msi2, targetMsiPath);
        service2.WriteSmsXmlFile(msi2, targetXmlPath);
        

        面向对象的方式可以使用decorator pattern

        var decoratedMsi = new CustomMsiDecorator(new MsiFile(sourceMsiPath));
        decoratedMsi.WriteToFile(targetMsiPath);
        decoratedMsi.WriteSmsXmlFile(targetXmlPath);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-02
          • 1970-01-01
          • 2013-02-18
          相关资源
          最近更新 更多