无参数方法在OOP中是邪恶的,这是如何对待它的方法

你好!



这个想法是在不可变对象中的任何地方都使用惰性缓存的属性,在这种情况下,我们通常会使用没有参数的处理器密集型方法。以及文章-如何设计它以及为什么。





可视地访问对象的惰性属性



免责声明

:

1) - , — ,

2) (, SRP)

3) ,



TL; DR位于最底部。



为什么邪恶?



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



: , .



而且,众所周知,现有的方法不允许做得精美,因此您必须编写自己的方法。




All Articles