четверг, 29 июня 2017 г.

Рефакторинг говнокода на Observer

Изначальная реализация паттерна проектирования "Наблюдатель" (Observer) для погоды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
 
namespace lb2
{
 class Program
 {
 public static void Main()
 {
 WeatherData weatherData = new WeatherData();
 CarrentConditionDisplay carrentDisplay = new CarrentConditionDisplay(weatherData);
 //...
 weatherData.setMeasurements(80, 65, 30.4);
 weatherData.setMeasurements(82, 70, 29.2);
 weatherData.setMeasurements(78, 90, 29.2);
 
 Console.Read();
 }
 
 }
 public interface Subject
 {
 public void registerObserver(Observer 0);
 public void removeObserver(Observer 0);
 public void notifyObservers();
 }
 public interface Observer
 {
 public void update(float temp, float hum, float press);
 }
 public interface DisplayElement
 {
 public void display();
 }
 
 public class WeatherData : Subject
 {
// private string SubjectState { get; set; }
 private ArrayList observers;
 
 private float temp;
 private float hum;
 private float pressure;
 
 public WeatherData()
 {
 observers = new ArrayList ();
 }
 public void registerObserver(Observer 0)
 {
 observers.Add(0);
 }
 public  void removeObserver(Observer 0)
 {
 int i = observers.indexOF(0);
 if (i>=0) observers.remove(i);
 }
 public void notifyObservers()
 {
 foreach (Observer obs in Observers)
 Obs.opdate(temp, hum, pressure);
 }
 public  void measurementsChanges()
 {
 notifyObservers();
 }
 public  void SetMeasurements(float temp, float hum, float press);
 {
 this.temp = temp;
 this.hum = hum; 
 this.pressure = press;
 measurementsChanges();
 }
//реализовать другие методы класса
 
public class CarrentConditionDisplay:Observer, DisplayElement
 {
 private float temper;
 private float humid;
 private Subject weatherData;
 
 public CarrentConditionDisplay(Subject wData)
 {
 this.weatherData = wData;
 wData.registerObserver(this);
 }
 
 public void update(float temp, float hum, float press)
 {
 this.temper = temp;
 this.humid = hum;
 Display();
 }
 public void Display()
 {
 System.Console.WriteLine("Текущие условия" + temper + "С и " + humid + "% влажности");
 }
 }
}

Очень много синтаксических ошибок. В интерфейсах нельзя использовать модификаторы (public, private и т.п.), на то он и интерфейс. На вход в методы передается ноль, надо переименовать. Классы не закрываются (нет символа '}' ). Значения float не завершаются буквой "f" в конце числа - писать 80f.

Нарушены соглашения:
- локальные переменные объявляются как var;
- приватные переменные начинаются либо со знака подчеркивания _ (далее слово начинается с маленькой буквы), либо с "m_", либо с "p_" (буквы m и p маленькие, после подчеркивания - начинается с большой);
- интерфесы именуются с большой буквы "I";
- код плохо отформатирован.

Методы и свойства всегда начинаются с большой буквы (Pascal-нотация).

https://msdn.microsoft.com/ru-ru/library/ff926074.aspx

Рефакторинг. Этап 1


    class Program
    {
        static void Main(string[] args)
        {
            var weatherData = new WeatherData();
            CarrentConditionDisplay carrentDisplay = new CurrentConditionDisplay(weatherData);
 
            weatherData.SetMeasurements(80f, 65f, 30f);
            weatherData.SetMeasurements(82f, 70f, 29f);
            weatherData.SetMeasurements(78f, 90f, 29f);
 
            Console.Read();
        }
    }
 
    
    public interface ISubject
    {
        void RegisterObserver(IObserver observer);
        void RemoveObserver(IObserver observer);
        void NotifyObservers();
    }
 
    public interface IObserver
    {
        void Update(float temp, float hum, float press);
    }
 
     public interface IDisplayElement
     {
        void Display();
     }
 
     public class WeatherData : ISubject
     {
 
        private readonly IList<IObserver> _observers = new List<IObserver>>();
 
        private float _temp;
        private float _hum;
        private float _pressure;
 
 
        public void RegisterObserver(IObserver observer)
        {
            _observers.Add(observer);
        }
        
        public void RemoveObserver(IObserver observer)
        {
             int i = _observers.IndexOf(observer);
             if (i>=0) _observers.Remove(observer);
        }
        
        public void NotifyObservers()
        {
            foreach (var observer in _observers)
                observer.Update(_temp, _hum, _pressure);
        }
 
        public void MeasurementsChanges()
        {
            NotifyObservers();
        }
 
        public void SetMeasurements(float temp, float hum, float press)
        {
             _temp = temp;
             _hum = hum; 
             _pressure = press;
             MeasurementsChanges();
        }
//реализовать другие методы класса
 
 
     }
 
    public class CurrentConditionDisplay : IObserver, IDisplayElement
    {
        private float _temper;
        private float _humid;
        private ISubject _weatherData;
 
        public CarrentConditionDisplay(ISubject wData)
        {
            _weatherData = wData;
            wData.RegisterObserver(this);
        }
 
        public void Update(float temp, float hum, float press)
        {
            _temper = temp;
            _humid = hum;
            Display();
        }
        
        public void Display()
        {
            System.Console.WriteLine("Текущие условия: " + _temper + "С и " + _humid + "% влажности");
        }
     }

На самом деле Observer уже реализован в C# в виде событий. Ниже показано, как должен выглядеть код на C# в данном случае.

Рефакторинг. Этап 2

    class Program
    {
        static void Main(string[] args)
        {
 
            var weatherData = new WeatherData();
            weatherData.MeasurementsChanged += Display; //Подписались
            weatherData.SetMeasurements(80f, 65f, 30f);
            weatherData.SetMeasurements(82f, 70f, 29f);
            weatherData.SetMeasurements(78f, 90f, 29f);
 
            weatherData.MeasurementsChanged -= Display; //Отписались
            Console.Read();
        }
 
        public static void Display(object sender, WeatherEventArgs e)
        {
            System.Console.WriteLine("Текущие условия: " + e.Temp + "С и " + e.Hum+ "% влажности");
        }
    }
 
    
    public class WeatherEventArgs : EventArgs 
    {
        public float Temp {get; set;}
        public float Hum {get; set;}
        public float Pressure {get;set;}
    }
 
     public class WeatherData
     {
 
 
        private float _temp;
        private float _hum;
        private float _pressure;
 
 
        public event EventHandler<WeatherEventArgs> MeasurementsChanged;
 
        protected virtual void OnMeasurementsChanges(WeatherEventArgs e)
        {
            var handler = MeasurementsChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
 
        public void SetMeasurements(float temp, float hum, float press)
        {
             _temp = temp;
             _hum = hum; 
             _pressure = press;
             OnMeasurementsChanges(
                 new WeatherEventArgs { Temp = _temp, Hum = _hum, Pressure = _pressure } );
        }
 
     }

Элегантнее и короче, верно?

0 коммент.:

Отправить комментарий