Boolood
Boolood

Reputation: 89

Which design pattern solve the multiple rules checking?

I want to save some files of an article which are posted to an ASP.NET MVC Core action. Then i have them as IFormFile in HttpContext. These files can be image, video, and document. Each of these file have their restrictions to save such as size or extension and each type can have own specific restriction. For example the main image of article should not large that 1500* 900. So I decide to put this design to them:

Class Diagram

And my codes:

public interface IArticleFile
{
    void CheckFileRules(IFormFile formFile);
    void SaveFile(IFormFile formFile, string path);
}

public interface IArticleImage : IArticleFile
{
    void CheckImageRules(IFormFile formFile);
}

public interface IArticleVideo : IArticleFile
{
    void CheckVideoRules(IFormFile formFile);
}

public class ArticleMainImage: IArticleImage
{
    public void CheckFileRules(IFormFile formFile) {/*CHECK STH*/}
    public void CheckImageRules(IFormFile formFile) {/*CHECK STH*/}
    public void SaveFile(IFormFile formFile, string path) { /* Save file */ }
}
public class ArticleSummaryImage : IArticleImage
{
    public void CheckFileRules(IFormFile formFile) {/*CHECK STH*/}
    public void CheckImageRules(IFormFile formFile) {/*CHECK STH*/}
    public void SaveFile(IFormFile formFile, string path) { /* Save file */ }
}

public class ArticleDto
{
    /*some properties*/
    public IFormFile MainImage { get; set; }
    public IFormFile SummaryImage { get; set; }
    public IFormFile ThumbnailImage { get; set; }
    public List<IFormFile> Videos { get; set; }
    public List<IFormFile> Documents { get; set; }

}

public class Article: IArticleService
{
    public void AddArticle(ArticleDto articleDto)
    {
        var articleMainImage = new ArticleMainImage();
        articleMainImage.CheckFileRules(articleDto.MainImage);
        articleMainImage.CheckImageRules(articleDto.MainImage);

        var articleSummaryImage = new ArticleMainImage();
        articleSummaryImage.CheckFileRules(articleDto.MainImage);
        articleSummaryImage.CheckImageRules(articleDto.MainImage);

        //Do these for Thumbnail image, videos, and documents
    }
}

But, I think I should use a design pattern here to make them easy to manipulate later and avoid from repeating some of my codes in Service layer. How can I do this in better way?

Upvotes: 2

Views: 309

Answers (1)

Siamak Ferdos
Siamak Ferdos

Reputation: 3299

You can use Command design pattern by changing some part of your code. Here you can have two types of commands. 1st for your validating and 2nd for file saving. So with registering them as a command, you can call them all in one place. You can use .NET Action class as your command and use it in a CommandHandler class:

So, if you have a command handler class like this:

public class CommandsHandler
{
    private List<Action> Commands { get; set; }

    public void AddCommand(Action saver)
    {
        Commands.Add(saver);
    }

    public void ExecuteAll()
    {
        Commands.ForEach(c => c.Invoke());
    }
}

Then change your article classes to get command handler. Note that each superclass is responsible to register its validation methods to prevent duplicate registration in children:

public abstract class ArticleFile
{
    protected IFormFile FileForm;
    protected string FileFullPath;
    public abstract void CheckFileRules();

    public void SaveFile(){

    protected ArticleFile(CommandsHandler validator, CommandsHandler saver, IFormFile file, string path)
    {
        FileForm = file;
        FileFullPath = path;
        validator.AddCommand(CheckFileRules); 
        saver.AddCommand(SaveFile); 
    }
}

public abstract class ArticleImage : ArticleFile
{
    public abstract void CheckImageRules();

    protected ArticleImage(CommandsHandler validator, CommandsHandler saver, IFormFile file, string path)
        : base(validator, saver, file, path)
    {
        validator.AddCommand(CheckImageRules);
    }
}

public class ArticleVideo : ArticleFile
{
    public override void CheckFileRules() {/*CHECK STH*/ }

    public void CheckVideoRules() {/*CHECK STH*/ }

    public ArticleVideo(CommandsHandler validator, CommandsHandler saver, IFormFile file, string path)
        : base(validator, saver, file, path)
    {
        validator.AddCommand(CheckVideoRules);
    }
}

public class ArticleMainImage : ArticleImage
{
    public ArticleMainImage(CommandsHandler validator, CommandsHandler saver, IFormFile file, string path)
        : base(validator, saver, file, path)
    {
        validator.AddCommand(CheckImageDimensions);
    }
    public override void CheckFileRules() {/*CHECK STH*/}
    public override void CheckImageRules() {/*CHECK STH*/}

    public void CheckImageDimensions() { }


}

Then you can easily create your objects and call validators and savers:

public class Article : IArticleService
{
    public void AddArticle(ArticleDto articleDto)
    {
        var articleValidator = new CommandsHandler();
        var articleFileSaver = new CommandsHandler();
        var articleMainImage = new ArticleMainImage(articleValidator, articleFileSaver, articleDto.MainImage, "");

        var articleVideos = new List<ArticleVideo>();
        articleDto.Videos.ForEach(v =>
            articleVideos.Add(new ArticleVideo(articleValidator, articleFileSaver, v, "")));

        articleValidator.ExecuteAll();
        articleFileSaver.ExecuteAll();
    }
}

Upvotes: 1

Related Questions