Les méthodes sans argument sont mauvaises en POO, et voici comment la traiter

salut!



L'idée est d'utiliser des propriétés mises en cache différées partout dans les objets immuables, où nous utiliserions normalement des méthodes lourdes de processeur sans arguments. Et l'article - comment le concevoir et pourquoi.





Accéder visuellement à une propriété paresseuse d'un objet



Avertissement

:

1) - , — ,

2) (, SRP)

3) ,



TL; DR tout en bas.



Pourquoi le mal?



. , Integer, :



public sealed record Integer(int Value);


Value int. , :



public sealed record Integer(int Value)
{
    public Integer Triple() => new Integer(Value * 3);
}


, , . ,



public int SomeMethod(Integer number)
{
    var tripled = number.Triple();
    if (tripled.Value > 5)
        return tripled.Value;
    else
        return 1;
}


,



public int SomeMethod(Integer number)
    => number.Tripled > 5 ? number.Tripled.Value : 1;


, , , . , , Tripled .



?



  1. . , , .
  2. . , , ( — ).
  3. . immutable object, , Equals GetHashCode , - , .


, , . , :



public sealed record Number(int Value)
{
    public int Number Tripled => tripled.GetValue(@this => new Number(@this.Value * 3), @this);
    private FieldCache<Number> tripled;
}


, , Cacheable. source- , - . — , .



:



1 ( ?):



public sealed record Number(int Value)
{
    public int Number Tripled => new Number(@this.Value * 3);
}


( )



2 ( Lazy<T>):



public sealed record Number : IEquatable<Number>
{
    public int Value { get; init; }  //   ,   
    public int Number Tripled => tripled.Value;
    private Lazy<Number> tripled;
    public Number(int value)
    {
        Value = value;
        tripled = new(() => value * 3);  //        ,      this-   
    }

    //   Equals,    ,    ,    Lazy<T>  
    public bool Equals(Number number) => Value == number.Value;
    //     GetHashCode
    public override int GetHashCode() => Value.GetHashCode();
}


, . , ? , .



, with, , (-). Lazy, .



3 ( ConditionalWeakTable):



public sealed record Number
{
    public Number Tripled => tripled.GetValue(this, @this => new Integer(@this.Value * 3));
    private static ConditionalWeakTable<Number, Number> tripled = new();
}


. ValueType ConditionalWeakTable -. , - ( , , 6 , , ).



4 ( ):



public sealed record Number
{
    public int Value { get; init; }

    public Number Tripled { get; }
    public Number(int value)
    {
        Value = value;
        Tripled = new Number { Value = value * 3 };
    }
}


stackoverflow, , "" — , .





  1. , , . ?
  2. Equals GetHashCode true 0 . , , . , Equals GetHashCode , .
  3. . , , .
  4. , GetValue, , ConditionalWeakTable. -, Lazy<T>.
  5. with, initialized holder, — .


!



, :



public struct FieldCache<T> : IEquatable<FieldCache<T>>
{
    private T value;
    private object holder; //       ,    generic 
    //    , ,   Equals     
    public bool Equals(FieldCache<T> _) => true;
    public override int GetHashCode() => 0;
}


GetValue :



public struct FieldCache<T> : IEquatable<FieldCache<T>>
{
        public T GetValue<TThis>(Func<TThis, T> factory, TThis @this) where TThis : class // record -   .   ,    
        {
            //        (,   - null)
            if (!ReferenceEquals(@this, holder))
                lock (@this)
                {
                    if (!ReferenceEquals(@this, holder))
                    {
                        //    ,    FieldCache   ,  -         . , ,     ,      
                        value = factory(@this);
                        holder = @this;
                    }
                }
            return value;
        }
}


, :



public sealed record Number(int Value)
{
    public int Number Tripled => tripled.GetValue(@this => new Number(@this.Value * 3), @this);
    private FieldCache<Number> tripled;
}


, .





, , FieldCacheLazy<T>.



Method Mean
BenchFunction 4,599.1638 ns
Lazy 0.6717 ns
FieldCache 3.6674 ns
ConditionalWeakTable 25.0521 ns


BenchFunction — - , , . . , FieldCache<T> , Lazy<T>.



, , , .



TL;DR



: , .



Et les approches existantes bien connues, très probablement, ne permettent pas que cela soit fait à merveille, vous devez donc écrire les vôtres.




All Articles