【问题标题】:Doubt about instantiating child class of an abstract class关于实例化抽象类的子类的疑问
【发布时间】:2011-07-23 14:46:20
【问题描述】:

我正在使用 LinqToSQL 和多层进行 ASP.Net MVC 项目。用户可以上传文件,基本上是 Excel 和 Access 文件,我的服务层将完成所有的验证和其他工作。

我正在考虑实现一个名为“UploadManager”的抽象类和 2 个子类:“UploadExcel”和“UploadAccess”。一些方法对两个类都是通用的,例如“SaveFile”和“DeleteFile”。但是,其他一些方法将仅限于特定的子类,例如仅属于“UploadExcel”类的“ValidateWorksheet”。

我正在设计这样的东西:

    public abstract class UploadManager
    {
        protected void SaveFile(string fileName)
        {
             //Implement
        }

        protected void DeleteFile(string fileName)
        {
             //Implement
        }
    }

   public class UploadExcel : UploadManager
   {
      private bool ValidateWorksheet()
      {
         //Implement
      }
   }

   public class UploadAccess : UploadManager
   {
      private bool ValidateSomethingAboutAccess()
      {
         //Implement
      }
   }

我也在考虑使用接口。但是,我的主要疑问是我怎么知道我必须实例化哪个子类?如果上传的文件是 Excel 文件,则为“new UploadExcel()”,如果是 Access 文件,则为“new UploadAccess()”。

有没有办法做到这一点?有没有更好的办法?我有点迷失了这个......

提前致谢!!

【问题讨论】:

    标签: c# asp.net-mvc-2 inheritance interface abstract-class


    【解决方案1】:

    可以做这样的事情,一个伪代码

    第一:

    public abstract class UploadManager
    {
       public void SaveFile(string fileName){ //uploading file }
       public abstract bool CanAccept(string sFileName); //abstract
    
        protected void DeleteFile(string fileName)
        {
           //Implement
        }
    }
    

    第二个具体实现:

     public class UploadExcel : UploadManager
       {
          public override bool CanAccept(string sFileName) {
    
               //if Excel file return true, else false
          }
    
          private bool ValidateWorksheet()
          {
             //Implement
          }
       }
    
       public class UploadAccess : UploadManager
       {
           public override bool CanAccept(string sFileName) {
    
               //if Access file return true, else false
          }
          private bool ValidateSomethingAboutAccess()
          {
             //Implement
          }
       }
    

    在代码的某个地方你有一个集合:

    List<UploadManager> managers = new List<UploadManager>{ new UploadExcel(), new UploadAccess()};
    
    
    
    //at the time decide to send a file (sFileName): 
    UploadManager myUploadManager = managers.Find(manager=>{return manager.CanAccept(sFileName);});
    myUploadManager.SaveFile(sFileName); //call concrete implementaiton for that specific file
    

    代码仅适用于 UploadManager 类型,因此您可以在任何具体实现之上为您想要的任何文件类型上传器创建定义抽象层。

    问候。

    完成。

    【讨论】:

      【解决方案2】:

      基本思想是在基类中将 validate 方法实现为abstract

      然后您只需要在实例化时担心子类,其余的您只需处理基类方法:

      string fileName = ...;  // from your request somehow
      
      UploadManager manager = null;  // note the type of manager, no var
      
      if (System.IO.Path.GetExtension(filename).LowerCase().StartsWith("xls"))    
         manager = new UploadExcel ();  
      else
         ...   
      
      manager.Validate();  // calls the Excel or the Access override
      

      你的课程看起来更像

      public abstract class UploadManager
      {
          // SaveFile, DeleteFile
      
          public abstract bool Validate();
      }
      
      
      public class UploadExcel : UploadManager
      {
            public override bool Validate()
            {
                // ...
                return ValidateWorksheet();
            }
      
            private bool ValidateWorksheet()
            {
               //Implement
            }
      }
      

      【讨论】:

      • 但我怎么知道我必须执行新的 UploadExcel() 还是新的 UploadAccess()?
      • 假设我有一个关于 Excel 的特定方法?它将被限制在它的类...
      • @Andre:会有一些逻辑(if/else)留给你。继承只能处理(可以做成)符合相同形状的事情。
      • 嗯...所以我必须创建一个 if else 来实例化正确的类,对吧?
      • 是的,或者使用工厂辅助类或方法。例如,请参阅库中的 WebRequest.Create()。但是 if/else 仍然会存在...
      【解决方案3】:

      我相信您正在寻找的是Abstract factory design pattern

      【讨论】:

        【解决方案4】:

        根据我对您问题的理解,您可以缓存上传管理器,以便当用户选择上传文件时,您可以获得与文件扩展名相关的管理器。即

        // Cache of upload managers keyed by their associated file extension
        private Dictionary<string, UploadManager> mManagers;
        
            // ... Add managers to cache in constructor ...
        
        public void Upload(string filename)
        {
            string extension = System.IO.Path.GetExtension(filename);
        
            // See if we have a manager for this extension
            UploadManager manager;
            if(mManagers.TryGetValue(extension, out manager))
            {
                // Validate the file
                // Note: This will call an abstract method in the UploadManager base
                //   class that will be defined in the child classes.
                manager.Validate(filename);
            }
        }
        

        【讨论】:

          【解决方案5】:

          你可以定义一个接口

          public interface IUserDataManager
          {
              void SaveFile();
              void DeleteFile();
              void Validate();
          }
          

          然后是抽象类和两个孩子

          public abstract class UserDataManager : IUserDataManager
          {
              private readonly string filename;
          
              protected UserDataManager(string filename)
              {
                  this.filename = filename;
              }
          
              public void SaveFile()
              {
                  Console.WriteLine("File saved as: " + filename);
              }
          
              public void DeleteFile()
              {
                  Console.WriteLine("File deleted: " + filename);
              }
          
              public abstract void Validate();
          }
          
          public class AccessUserDataManager : UserDataManager
          {
              public AccessUserDataManager(string filename) : base(filename) { }
          
              public override void Validate()
              {
                  Console.WriteLine("Access validated");
              }
          }
          
          public class ExcellUserDataManager : UserDataManager
          {
              public ExcellUserDataManager(string filename) : base(filename) { }
          
              public override void Validate()
              {
                  Console.WriteLine("Excel validated");
              }
          }
          

          这就是它的使用方法

          class Program
          {
              static void Main(string[] args)
              {
                  IUserDataManager mgr = new AccessUserDataManager("access.db");
                  mgr.Validate();
                  mgr.SaveFile();
                  mgr.DeleteFile();
          
                  mgr = new ExcellUserDataManager("excel.xlsx");
                  mgr.Validate();
                  mgr.SaveFile();
                  mgr.DeleteFile();
          
                  Console.ReadLine();
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多