Code Enhancements for Implementing Business Logic

I previously asked this question about SO. This is due to this. We have a code base like this:

IRecipie FindRecipiesYouCanMake(IEnumerable<Ingredientes> stuff, Cook cook) { if(stuff.Any(s=>s.Eggs && s.Flour) && cook.DinerCook) { if(s=>s.Sugar) return new Pancake("Yum"); if(s=>s.Salt) return new Omlette("Yay"); } /*..... ...... ..... loads of ifs and buts and else*/ } 

I want to get rid of this mess and take an extra data structure and OO route. Even the sample code I provided is not as terrible as it is. I reviewed the spec template and found it applicable. Any ideas for improving the code.

EDIT: now that I understand this, I might even like to implement the method of this signature:

 List<IRecipe> WhatAllCanBeCooked(IEnumerable<Ingredients> stuff, Cook cook); 
+4
source share
4 answers

I would delegate this logic to separate IRecipie classes:

 if (Pancake.CanBeMadeBy(stuff, cook)) { return new Pancake("Yum"); } .... public class Pancake: IRecipe { ... public static bool CanBeMadeBy(IEnumerable<Ingredientes> stuff, Cook cook) { return stuff.Any(s=>s.Eggs && s.Flour && s.Sugar) && cook.DinerCook; } } 

Edit in response to comment

To find all the recipes that can be prepared, simply follow these steps:

 List<IRecipe> results = new List<IRecipe>(); if (Pancake.CanBeMadeBy(stuff, cook)) { results.Add(new Pancake("Yum"); } .... 

Edit 2 In addition, if you keep a list of all possible recipes somewhere, you can turn CanBeMadeBy into an instance method instead of a static one and do this:

 List<IRecipe> allRecipes = // all possible recipes ... return allRecipes.Where(r => r.CanBeMadeBy(stuff, cook)); 
+3
source

Some ideas:

  • use decision tables

  • Use a strategy template . This will help you encapsulate a group of actions or parameters that belong together in different concrete classes. After you decide which strategy to use, you no longer need "ifs" to send between strategies.

EDIT: some additional ideas:

  • run the little one: most often just refactoring for smaller, well-named, reusable functions will help you reduce if-else-if-else-soup. Sometimes a simple, well-named logical variable does the trick. Both are examples of refactoring, which you will find in Fowler's book "Refactoring" .

  • I think itโ€™s โ€œbigโ€: if you really have a lot of complex business rules, creating a โ€œdomain-specific languageโ€ is an option that can sometimes be the right way to reduce complexity. You will find a lot of material on this topic just by looking into it. Referring to David Wheeler. All problems in computer science can be solved by a different level of indirection.

+1
source

ORIGIINAL POST - Martin Fowler solved this problem for you ... it was called a specification template.
http://en.wikipedia.org/wiki/Specification_pattern

UPDATED POST -

Consider using a composite specification template if:

  • You need to select a subset of objects based on some criteria,
  • You need to verify that only suitable objects are used for a specific role, or
  • You need to describe what an object can do without explaining the details of how the object does it.

The true power of a template lies in its ability to combine different specifications with composites with AND, OR, and NOT relationships. Combining various specifications together can be done at design time or runtime.

Eric Evan's book on Domain Driven Design has a great example of this template (delivery manifest)

This is the link to the Wiki:

http://en.wikipedia.org/wiki/Specification_pattern

At the bottom of the wiki link is this link in PDF format:

http://martinfowler.com/apsupp/spec.pdf

+1
source

I think that this block of code is essentially trying to achieve, it is linking the recipes to the ingredients in this recipe. One approach would be to include the list of ingredients in the recipe class itself, and then compare this with the list of ingredients conveyed this way:

 public interface IRecipe { IEnumerable<Ingredient> Ingredients { get; } } public class Omlette : IRecipe { public IEnumerable<Ingredient> Ingredients { get { return new Ingredient[]{new Ingredient("Salt"), new Ingredient("Egg")}; } } } // etc. for your other classes. IRecipie FindRecipiesYouCanMake(IEnumerable<Ingredientes> stuff, Cook cook) { var query = Recipes.Where(r => !r.Ingredients.Except(stuff).Any()); return query.First(); } 

This assumes that you have a collection somewhere of your recipes. It should be simple enough to set up a static list of these or pull them out of the database.

The Linq query in question is looking for any recipes in which all the ingredients conveyed in the materials are on the list of ingredients (or, as he noted, there are no ingredients in the ingredients that are not in the substance). It can also reduce the need to have subclasses for recipes that seem a bit odd (although for everyone I know there are additional reasons you will need)

0
source

Source: https://habr.com/ru/post/1299686/


All Articles