Doubt about instantiating child class of an abstract class
I'm on a ASP.Net MVC project with LinqToSQL and multilayer. Users cand upload files, basically Excel and Access file and my service layer will do all of its validatio开发者_如何学JAVAn and other stuff.
I was thinking about implement an abstract class named "UploadManager" and 2 child classes: "UploadExcel" and "UploadAccess". Some methods will be common to both classes, such as "SaveFile" and "DeleteFile". But, some other methods will be restricted to an especific child class, such as "ValidateWorksheet" that will belong to "UploadExcel" class only.
I was designing something like this:
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
}
}
I was thinking about using Interfaces too. But, my main doubt is how can I know which child class I have to instantiate? If uploaded file is an Excel file, it will be "new UploadExcel()
" and if it is an Access file, it will be "new UploadAccess()
".
Is there a way to accomplish this? Is there a better way? I'm some kinda lost with this...
Thanks in advance!!
Could do something like this, a pseudocode:
First:
public abstract class UploadManager
{
public void SaveFile(string fileName){ //uploading file }
public abstract bool CanAccept(string sFileName); //abstract
protected void DeleteFile(string fileName)
{
//Implement
}
}
Second concrete implementation:
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
}
}
Somewhere in the code you have a collection:
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
The code works only with UploadManager type, so you create definit abstraction layer over any concrete implementation for any file type uploader you want.
Regards.
Done.
The basic idea would be to inplement the validate method as abstract
in the base class.
You then only have to worry about the child class when instantiating, for the rest you only deal with the base class methods:
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
And your classes would look more like
public abstract class UploadManager
{
// SaveFile, DeleteFile
public abstract bool Validate();
}
public class UploadExcel : UploadManager
{
public override bool Validate()
{
// ...
return ValidateWorksheet();
}
private bool ValidateWorksheet()
{
//Implement
}
}
I believe what you're looking for is the Abstract factory design pattern
Based on my understanding of your question, you could have a cache of upload managers so that when the user selects to upload the file, you can get the manager relevant to the file extension. i.e.
// 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);
}
}
You can define an interface
public interface IUserDataManager
{
void SaveFile();
void DeleteFile();
void Validate();
}
Then abstract class and two children
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");
}
}
And this is how to use it
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();
}
}
精彩评论