Статьи

Свойства и методы в Ruby из .NET POV

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

Поля, свойства и методы в C #

Поля — это переменные, относящиеся либо к объекту (поля экземпляра), либо к классу (статические поля). Лучше всего, чтобы разработчики не выставляли поля публично, так как это раскрывает слишком много внутренних элементов класса. Поле экземпляра объявлено так:

public class Customer
{
  private int _age;
}

Обратите внимание, что подчеркивание перед «age» — это просто общее соглашение, которому следуют несколько разработчиков на C #. Чтобы выставить такое поле, создается «свойство», которое определяется как пара методов получения и метода установки:

 public class Customer
{
  private int _age;

  public int Age 
  {
    get { return _age; }
    set { _age = value; }
  }
}

Свойство определяется только методом get в том случае, если оно предназначено только для «доступа», но не для «назначения». В случаях, когда геттеры и сеттеры просто получают или устанавливают значение поля, можно использовать функцию C #, которая называется auto properties :

 public class Customer
{
  public int Age { get; set; } 
}

Когда свойство определяется таким образом, компилятор C # создает код, похожий на тот, который я показывал ранее (он создает вспомогательное поле и реализацию геттеров / сеттеров).

Теперь, как это выглядит в Ruby …?

В следующем посте кратко рассматриваются переменные экземпляра и класса: NET to Ruby: методы и переменные . Чтобы объявить переменную экземпляра, мы определяем ее в инициализаторе класса (его конструкторе ), которому предшествует @:

 class Customer

  def initialize
    @age = 18
  end
end

На этом этапе @age очень похож на приватное поле в C #, так как к нему можно получить доступ в любом месте класса, где оно определено, но не за его пределами. Чтобы получить к нему доступ или назначить его извне, мы должны определить методы доступа к нему:

 class Customer

  def initialize
    @age = 18
  end

  def age
    @age
  end

  def age=(value)
    @age = value
  end
end

В отличие от C #, где мы определили свойство Age, содержащее методы set и get, здесь мы создали метод age, который возвращает значение переменной экземпляра @age, а также метод age = , который принимает значение и присваивает его переменная экземпляра.

Подобно автоматическим свойствам C #, Ruby также предлагает конструкцию, позволяющую легко создавать методы доступа. Код выше можно переписать так:

 class Customer

  def initialize
    @age = 18
  end

  attr_accessor :age
end

attr_accessor не является ключевым словом в Ruby; это нечто, называемое «макросом класса», который представляет собой метод метапрограммирования для добавления динамического поведения в класс. В этом случае добавляются средства чтения и записи. Мы также можем только добавить средства чтения или записи с помощью attr_reader или attr_writer, соответственно.

Accessors, которые делают немного больше …

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

 public class Customer
{
  private string _firstName;
  private string _lastName;

  public string FullName 
  {
    get { return string.Format("{0} {1}", _firstName, _lastName); }
  }
}

В приведенном выше примере свойство FullName имеет метод получения, который объединяет поля _firstName и _lastName. Такая практика распространена и в Ruby:

 class Customer

  def initialize
    @first_name = "Claudio"
    @last_name = "Lassala"
  end

  def full_name
    "#{@first_name} #{@last_name}"
  end
end

Имейте в виду, что круглые скобки являются необязательными в Ruby, поэтому такой метод, как full_name выше, может быть вызван так:

 cust = Customer.new
puts cust.first_name

Очистка кода с помощью метапрограммирования

Довольно часто мы добавляем логические свойства в класс, чтобы мы могли спросить объект об определенных вещах. Возьмите этот пример:

 public class User
{
  private string _profile;

  public User(string profile)
  {
    _profile = profile;
  }

  public bool IsDoctor
  {
    get { return _profile == "doctor"; }
  }

  public bool IsPatient
  {
    get { return _profile == "patient"; }
  } 
}

Теперь предположим, что существует больше типов профилей, чем просто «доктор» и «пациент», поэтому в этом случае класс User будет иметь одно свойство для каждого типа профиля. Подобный класс может быть создан в Ruby примерно так:

 class User

  def initialize(profile)
    @profile = profile
  end

  def doctor?
    @profile == 'doctor'
  end

  def patient?
    @profile == 'patient'
  end
end

Что с суффиксом «?» Для доктора? а пациент? методы? Часто, когда метод в Ruby предназначен для возврата логического значения, этот метод называется методом предиката , и обычной практикой является использование его с суффиксом «?». Поэтому вместо того, чтобы писать код, например «if user.is_doctor», мы пишем «if user.doctor?».

Действительно ли у класса User есть несколько методов, таких как доктор? а пациент? (по одному для каждого типа профиля), класс можно переписать, чтобы использовать метапрограммирование. Вот пример того, как это может выглядеть:

 class User

  def initialize(profile)
    @profile = profile
  end

  def method_missing(method_name, *args, &block)
    method_name = method_name.to_s
    if method_name.ends_with?("?")
      return @profile == method_name.chop
    end

    super if self.responds_to?(method_name)
  end
end

Заметили, что оба доктора? а пациент? методы исчезли, и был добавлен метод method_missing . Теперь происходит то, что всякий раз, когда какой-либо код запрашивает объект пользователя, например, «if user.doctor?», Такой метод отсутствует в классе, и вызывается метод method_missing . В приведенном выше примере method_missing проверяет, заканчивается ли метод, вызываемый для объекта («имя_метода») символом «?», И, если это так, сравнивает @profile с ним. Если поддерживаются новые профили, нет необходимости добавлять свойства в класс User, поскольку он готов к его обработке.

Резюме

Важно понимать тот факт, что в Ruby на самом деле нет «свойств» (есть методы), и их можно создавать автоматически (используя макросы класса attr_accessor, attr_reader, attr_writer) или вручную (просто определяя методы ), поскольку эти вещи используются довольно часто в каждом приложении.

Я надеюсь, что теперь вы лучше понимаете, как C # и Ruby сравниваются, когда дело доходит до свойств. Оставьте комментарий, если у вас есть какие-либо вопросы или понимание.