HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpModerate

Bread formula object

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
breadformulaobject

Problem

I designed this object for a "bread formula". They use a concept known as baker's percentages, but you don't need to understand the math to help with the object design.

I designed it as an object (of type Formula) that contains objects (of type Ingredient).

Both classes have nullable properties. C# demarcates nullable types using a ? after the type, like so:

public decimal? Weight { get; set; }


The reason I declare them as nullable types is because I don't know their values (when I create an instance of them) until I calculate them later, as which point I update the null value with a calculated value.

The calculations are just basic methods, like CalculateSum() or CalculateWeight().

Is there a better way to design this object? It works, but I feel like it's the wrong way to do things. I feel like I'm trying to force-fit inline/declarative style programming into an OOP design, but I don't know how else to do it, being so new to OOP.

My thinking is that this object has this property. I won't know its value when I create an instance of it, so I must declare it as nullable. Once I calculate its value using a method that's also internal to the class, I assign/set its value. Then it will no longer be null.

The calculation methods are basic calculations:

public type Method(input,input,...){calc; return calc;}.


```
class Ingredient
{
public string Name { get; set; }
public decimal Percentage { get; set; }
public bool IsFlour { get; set; }
public decimal? Weight { get; set; }

public Ingredient(string _Name, decimal _Percent, bool _IsFlour, decimal? _Weight)
{
this.Name = _Name;
this.Percentage = _Percent;
this.IsFlour = _IsFlour;
this.Weight = _Weight;
}
}

class Formula
{
public decimal Weight_Total_Dough { get; set; }
public ArrayList Ingredients { get; set; }
public int NumberOfIngredients { g

Solution

Everyone has had good ideas, but since you're asking about OOP, I'd suggest refactoring it altogether.

void Main()
{
    var formula = new Formula(new[] {
        new Ingredient("Flour, AP", 100m, true),
        new Ingredient("Water, Warm", 70.15m, false),
        new Ingredient("Salt", 3.04m, false),
        new Ingredient("Yeast", .24m, false),
        new Ingredient("Pate fermentee", 2.53m, false)
    });
    var weights = formula.GetWeights(10000m);
}

class Ingredient
{
    public string Name { get; private set; }
    public decimal Percentage { get; private set; }
    public bool IsFlour { get; private set; }

    public Ingredient(string _Name, decimal _Percent, bool _IsFlour)
    {
        this.Name = _Name;
        this.Percentage = _Percent;
        this.IsFlour = _IsFlour;
    }
}

class Formula
{
    private IEnumerable Ingredients { get; set; }
    public decimal SumPercentages { get; private set; }

    public Formula(IEnumerable _Ingredients)
    {
        this.Ingredients = _Ingredients;
        this.SumPercentages = _Ingredients.Sum(x => x.Percentage);
    }

    public Dictionary GetWeights(decimal weightTotalDough)
    {
        return Ingredients.ToDictionary(k => k, v => (v.Percentage / this.SumPercentages) * weightTotalDough);
    }
}


By doing it this way, you separate the formula (which is basically just Ingredient/Percentage pairs) from each application of it. You can use the same Formula object to calculate the weights for 10000g of dough or 50000g of dough - simply call GetWeights() with a different value.

Notice how many fewer properties you need on each class, and the question of "late setting" of some of them is entirely irrelevant. Effectively, weight is not an intrinsic property of an ingredient, because it varies based on the total weight, so Weight shouldn't be a property of Ingredient.

Code Snippets

void Main()
{
    var formula = new Formula(new[] {
        new Ingredient("Flour, AP", 100m, true),
        new Ingredient("Water, Warm", 70.15m, false),
        new Ingredient("Salt", 3.04m, false),
        new Ingredient("Yeast", .24m, false),
        new Ingredient("Pate fermentee", 2.53m, false)
    });
    var weights = formula.GetWeights(10000m);
}

class Ingredient
{
    public string Name { get; private set; }
    public decimal Percentage { get; private set; }
    public bool IsFlour { get; private set; }

    public Ingredient(string _Name, decimal _Percent, bool _IsFlour)
    {
        this.Name = _Name;
        this.Percentage = _Percent;
        this.IsFlour = _IsFlour;
    }
}

class Formula
{
    private IEnumerable<Ingredient> Ingredients { get; set; }
    public decimal SumPercentages { get; private set; }

    public Formula(IEnumerable<Ingredient> _Ingredients)
    {
        this.Ingredients = _Ingredients;
        this.SumPercentages = _Ingredients.Sum(x => x.Percentage);
    }

    public Dictionary<Ingredient, decimal> GetWeights(decimal weightTotalDough)
    {
        return Ingredients.ToDictionary(k => k, v => (v.Percentage / this.SumPercentages) * weightTotalDough);
    }
}

Context

StackExchange Code Review Q#20328, answer score: 18

Revisions (0)

No revisions yet.