Metode tanpa argumen adalah jahat di OOP, dan berikut cara mengobatinya

Halo!



Idenya adalah menggunakan properti yang disimpan dalam cache malas di mana pun dalam objek yang tidak dapat diubah, tempat kami biasanya menggunakan metode berat prosesor tanpa argumen. Dan artikelnya - bagaimana mendesainnya dan mengapa.





Mengakses properti malas suatu objek secara visual



Penolakan

:

1) - , — ,

2) (, SRP)

3) ,



TL; DR di bagian paling bawah.



Mengapa jahat?



. , 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



: , .



Dan pendekatan terkenal yang ada, ternyata, tidak memungkinkan untuk dilakukan dengan indah, jadi Anda harus menulis sendiri.




All Articles