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

Table builder pattern

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

Problem

Trying to combine functional style (immutable objects) and flexibility of property setters. For the sake of example, let’s say we have a soil types table with two attributes: Color and Name. I am looking for a way to alternate Names, but not Color. Here is how I solved it:

// retrieving: all objects are immutable
        SoilTypes types = SoilTypes.Default;
        ISoilType clay1 = types.Clay;
        ISoilType clay2 = types[3];

        // derive an alternated immutable copy
        SoilTypes altTypes = types
            .With(tt =>
            {
                // tt.SensitiveFines.Color is still read only
                tt.SensitiveFines.Name = "Very sensitive fines!";
                tt[2].Name = "Purely Organic soil!";
            });

        // retrieving: everything is immutable
        ISoilType sensitiveFines = altTypes.SensitiveFines;


Where this interface is immutable:

public interface ISoilType
{
    Color Color { get; }
    string Name { get; }
}


And this class is mutable:

public class SoilType : ISoilType
{
    public static implicit operator SoilType((Color Color, string Name) tuple) =>
         new SoilType(tuple.Color, tuple.Name);

    internal SoilType(ISoilType source)
        : this(source.Color, source.Name)
    {
    }

    internal SoilType(Color color, string name)
    {
        Color = color;
        Name = name;
    }

    public Color Color { get; }
    public string Name { get; set; }
}


And this non-generic class is immutable:

```
public class SoilTypes : SoilTypes
{
public static SoilTypes Default = new SoilTypes(
(White, "Undefined"),
(Red, "Sensitive Fines"),
(Green, "Organic Soil"),
(Blue, "Clay"),
(Orange, "Silty Clay"));

public SoilTypes(params SoilType[] types)
: base(types)
{
}

public SoilTypes With(Action> update)
{
var copy = this
.Select(t => new SoilType(t))
.ToArray();

update(new

Solution

I'm afraid this is not fully immutable becasue I am able to change the Name with a simple cast:

altTypes.Dump();
((SoilType)altTypes.SensitiveFines).Name = "foo";
altTypes.Dump();


The underlying data type is still SoilType so the interface does not protect the data from being overriden.

Consider a user that writes a function like this one because he doesn't like interfaces :-)

public static void foo(SoilType bar)
{
    bar.Name = "new name";
}


and calls it

foo((SoilType)altTypes.SensitiveFines);
altTypes.Dump();


Name changed. Unfortunatelly I have no idea how to prevent it yet.

Code Snippets

altTypes.Dump();
((SoilType)altTypes.SensitiveFines).Name = "foo";
altTypes.Dump();
public static void foo(SoilType bar)
{
    bar.Name = "new name";
}
foo((SoilType)altTypes.SensitiveFines);
altTypes.Dump();

Context

StackExchange Code Review Q#161521, answer score: 4

Revisions (0)

No revisions yet.