How to design around the lack of const in C # / Java?

While trying to simulate my domain, I encountered the following problem. Let us have a Thing:

class Thing
{
    public int X { get; set; }
}

Things have property X. Then there are Packages that combine Things. But the domain requires a restriction on things that may contain packages. Let it be, for example, that the cumulative value of Xes cannot be above some certain limit:

class Pack
{
    private readonly List<Thing> myThings = new List<Thing>();
    private const int MaxValue = 5;

    public void Add(Thing thing)
    {
        if (myThings.Sum(t => t.X) + thing.X > MaxValue)
            throw new Exception("this thing doesn't fit here");
        myThings.Add(thing);
    }

    public int Count
    {
        get { return myThings.Count; }
    }

    public Thing this[int index]
    {
        get { return myThings[index]; }
    }
}

So, I check before adding Thing to Pack for the condition, but it's still so easy to get into trouble:

var pack = new Pack();
pack.Add(new Thing { X = 2 });
pack.Add(new Thing { X = 1 });

var thingOne = new Thing { X = 1 };
var thingTwo = new Thing { X = 3 };

//pack.Add(thingTwo); // exception
pack.Add(thingOne);   // OK

thingOne.X = 5;       // trouble
pack[0].X = 10;       // more trouble

In C ++, the solution would be to create a copy when you insert and return a const link in the index. How to design around this problem in C # (and possibly Java)? I just can't think of a good solution:

  • make Thing immutable - but what if it has to be volatile?
  • /, , Thing; , ? - Pack - .

?

EDIT:

... . . , , Thing , , . ... . " ", "" ( DDD) , , , , ( ).

, ++ const. , , .

+3
7

Thing .

class Thing
{
    public Thing (int x)
    {
       X = x;
    }
    public int X { get; private set; }
}

, if (myThings.Sum(t => t.X) + thing.X > MaxValue) , , .


, , , .
... ++ ? ++, ++ , ?

EDIT2

public interface IThing
{
  int X { get; }
}

public class Thing : IThing
{
  int X { get; set; }
}

class Pack
{
    private readonly List<IThing> myThings = new List<IThing>();
    private const int MaxValue = 5;

    public void Add(IThing thing)
    {
        if (myThings.Sum(t => t.X) + thing.X > MaxValue)
            throw new Exception("this thing doesn't fit here");
        myThings.Add(new InnerThing(thing));
    }

    public int Count
    {
        get { return myThings.Count; }
    }

    public IThing this[int index]
    {
        get { return myThings[index]; }
    }

    private class InnerThing : IThing
    {
      public InnerThing(IThing thing)
      {
        X = thing.X;
      }
      int X { get; private set; }
    }
}
+6

Thing iReadOnlyThing, ReadOnly Thing.

, , , iReadOnlyThing, iReadOnlyThings .

, ,

System.Collections.ObjectModel.ObservableCollection<T>

System.Collections.ObjectModel.ReadOnlyObservableCollection<T>

. ReadOnlyObservableCollection ObservableCollection . , ReadOnlyObservableCollection ObservableCollection.

, , Model-View-ViewModel, WPF, , , NotifyPropertyChanged, , ...

MVVM , ...

+3

- X, , X. , X, - -. , .

:

  • X? , X .
  • SetX(...), -, , Thing Pack Pack.
  • , setter set { } .
  • Pack.Add Thing, , .
  • ...

, , : X, / , X. X , X (, , ...).

+2

. . , , , , . .

, . , , , .

, . , , . , , .

+1

Thing; Pack , X Thing, Pack , ; ?

+1

, # , const C/++, ( ), .

, , - ( ), , const.: (

, , - ,

class Thing
{
    public bool IsReadOnly {get; set;}

    private int _X;
    public int X
    {
        get
        {
            return _X;
        }
        set
        {
            if(IsReadOnly)
            {
                throw new ArgumentException("X");
            }

            _X = value;
        }
    }
}

try/catch IsReadOnly. , , , - .

0

.

, , , .

Of course, the downside is that you must remember to return it to the package!

Alternatively, you can provide methods in the package to change Things, so you can verify that the set value does not violate the domain rules.

0
source

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


All Articles