7-1.임시 필드 Temporary Field

[ 2017-08.16 작성 ]

  1. 클래스는 일반적으로 모든 인스턴스 변수를 사용하기를 기대하기 때문에 임시 변수가 사용되는 것을 보기가 어려울 수 있습니다.
  2. 특정 상황에 따라 값이 변하게 되는 임시 변수는 코드를 이해하기 어렵게 만듭니다.

참고 사이트
http://blog.ploeh.dk/2015/09/18/temporary-field-code-smell/

[ sample source ]

public class Estimator
{
    private readonly TimeSpan defaultEstimate;
    private IReadOnlyCollection<TimeSpan> durations; 
.....
.....
  public TimeSpan CalculateEstimate(IReadOnlyCollection<TimeSpan> durations) 
  {
   .....
    this.durations = durations;
    this.CalculateAverage();
    this.CalculateStandardDeviation();

      var margin = TimeSpan.FromTicks(this.standardDeviation.Ticks * 3);
      return this.average + margin;
   }
   
    private void CalculateAverage(){   //  임시 필드에 셋팅된 값(durations) 처리
    .....
    }
    
    private void CalculateStandardDeviation(){ //  임시 필드에 셋팅된 값(durations) 처리
    .....
    }
....

위의 durations 임시변수와 평균계산, 표준편자 계산 메서드를 Class로 추출하여 사용하는 예제를 보게 됩니다.
아래의 코드와 같습니다.

[ 1. ] 해결책

public class Estimator   //  class
{
// private IReadOnlyCollection<TimeSpan> durations;  <- 삭제
......
......
 var stats = new DurationStatistics(durations);  // 평균, 표준편차 계산
 
 var margin = TimeSpan.FromTicks(this.standardDeviation.Ticks * 3);
 return this.average + margin;
......
......
 private class DurationStatistics  // public class안의 private class
    {
        private readonly IReadOnlyCollection<TimeSpan> durations;
        private readonly Lazy<TimeSpan> average;
        private readonly Lazy<TimeSpan> standardDeviation;
        
        public DurationStatistics(IReadOnlyCollection<TimeSpan> durations)
        {
          if (durations == null)
            throw new ArgumentNullException(nameof(durations));
          if (durations.Count == 0)
            throw new ArgumentException("Empty collection not allowed.",nameof(durations));

          this.durations = durations;
          this.average = new Lazy<TimeSpan>(this.CalculateAverage);
          this.standardDeviation = new Lazy<TimeSpan>(this.CalculateStandardDeviation);
        }
           
        public TimeSpan Average{.....}
        public TimeSpan StandardDeviation{.....}
        private TimeSpan CalculateAverage(){.....}      
        private TimeSpan CalculateStandardDeviation(){.....}      
.....
.....

Estimator 클래스 안에 private 접근자 DurationStatistics 클래스는 중첩 된 클래스입니다.
하지만 임시 변수 durations에 값이 설정되고 공유하고 있는 코드를 제거할 수 있고 만약
공용 클래스로 만들어 재사용 가능한 개념을 도입한다면 전체 코드베이스가 향상될 수 있습니다.

[ 2. ] 해결책

public class Estimator
{
// private IReadOnlyCollection<TimeSpan> durations;  <- 삭제
......
 var average = CalculateAverage(durations);
 var standardDeviation = CalculateStandardDeviation(durations, average);

var margin = TimeSpan.FromTicks(standardDeviation.Ticks * 3);
return average + margin;
.....
.....
  private static TimeSpan CalculateAverage(IReadOnlyCollection<TimeSpan> durations)
    {
.....
 private static TimeSpan CalculateStandardDeviation(IReadOnlyCollection<TimeSpan> durations, TimeSpan average)
    {
.....

필요한 인수를 전달하는 방법도 좋은 해결책!