Инициализация объекта DRY'er в Ruby

VB.Net - 530 символов (без пробелов), 634 (без пробелов)

Module ChristmasSong
    Sub Main()
        Dim i&, f$ : Dim d$() = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"}, g$() = {"a partridge in a pear tree.", "two turtle doves, and ", "three french hens, ", "four calling birds, ", "five gold rings, ", "six geese a-laying, ", "seven swans a-swimming, ", "eigth maids a-milking, ", "nine ladies dancing, ", "ten lords a-leaping, ", "eleven pipers piping, ", "twelve drummers drumming, "}
        For i = 0 To 11 : f = g(i) & f : Console.WriteLine("On the {0} day of Christmas, my true love gave to me {1}", d(i), f) : Next
    End Sub
End Module
14
задан Trevor O 11 June 2009 в 18:34
поделиться

4 ответа

 class Volume

  FIELDS = %w( name size type owner iscsi_target iscsi_portal date_create date_modified)
  SYSTEM = 0
  DATA = 1
  attr_accessor *FIELDS

  def initialize( args= { :type => SYSTEM } )
    args.each_pair do | key, value |
      self.send("#{key}=", value) if self.respond_to?("#{key}=")
    end
  end

  def inspect
    FIELDS.inject({}) do | hash, field |
      hash.merge( field.to_sym => self.send(field) )
    end.inspect
  end

 end
9
ответ дан 1 December 2019 в 12:27
поделиться

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

class Volume
  ATTRIBUTES = [
    :name, :size, :type, :owner, :date_created, :date_modified,
    :iscsi_target, :iscsi_portal
  ].freeze

  ATTRIBUTES.each do |attr|
    attr_accessor attr
  end

  SYSTEM = 0
  DATA = 1

  DEFAULTS = {
    :type => SYSTEM
  }.freeze

  def initialize(args = nil)
    # EDIT
    # args = args ? DEFAULTS : DEFAULTS.merge(args) # Original
    args = args ? DEFAULTS.merge(args) : DEFAULTS

    ATTRIBUTES.each do |attr|
      if (args.key?(attr))
        instance_variable_set("@#{attr}", args[attr])
      end
    end
  end

  def inspect
    ATTRIBUTES.inject({ }) do |h, attr|
      h[attr] = instance_variable_get("@#{attr}")
      h
    end
  end

  def to_json
    self.inspect.to_json
  end
end

После этого манипулировать переменными экземпляра становится довольно просто.

12
ответ дан 1 December 2019 в 12:27
поделиться

Я согласен с ответом Рекса М , но я бы пошел еще дальше. Если вы используете шаблон MVC (или что-то подобное), представление делегирует нажатие кнопки контроллеру. Конечно, методы контроллеров могут быть вызваны из любого места в вашем классе - скажем, из вашего обратного вызова таймера.

Итак, вернемся к вашему исходному коду:

using System.Windows.Forms;

class MyForm : Form
{
    private Timer myTimer;
    private Button myButton;

    private MyController myController;

    public MyForm()
    {
        // ...
        // Initialize the components, etc.
        // ...

        myTimer.Tick += new EventHandler( myTimer_Tick );
        myButton.Click += new EventHandler( myButton_Click );

        myTimer.Start();
    }

    private void myTimer_Tick( object sender, EventArgs eventArgs )
    {
        myTimer.Stop();
        myController.SomeMethod()
    }

    private void myButton_Click( object sender, EventArgs eventArgs )
    {
        // All the stuff done here will likely be moved 
        // into MyController.SomeMethod()
        myController.SomeMethod();
    }
}

Одним из преимуществ использования MVC является отделение контроллера от представления. Контроллер теперь можно легко использовать для нескольких типов представлений, а выход из графического интерфейса пользователя проще поддерживать, поскольку он содержит очень мало логики приложения.

РЕДАКТИРОВАТЬ: добавлено в ответ на комментарии OP

Основные принципы проектирования в разговоре о разработке программного обеспечения о сцеплении и сплоченности. Важно отметить, что мы стремимся минимизировать взаимосвязь между компонентами при максимальной согласованности, так как это приводит к созданию более модульной и удобной в обслуживании системы. Такие шаблоны, как MVC, и принципалы, такие как Open / Closed Principal, основываются на этих основах, предоставляя разработчику более ощутимые шаблоны реализации.

Итак, любой, кто пишет код, как показано в исходной публикации, не понимает основ разработки программного обеспечения и должен значительно развить свои навыки. OP следует похвалить за определение этого «запаха кода» и попытку понять, почему он не совсем правильный.

Некоторые соответствующие ссылки:

1
ответ дан 1 December 2019 в 12:27
поделиться

Вот немного другой вариант ответа Тадмана:

class Volume
  ATTRIBUTES = [
    :name, :size, :type, :owner, :date_created, :date_modified,
    :iscsi_target, :iscsi_portal
  ].freeze

  ATTRIBUTES.each do |attr|
    attr_accessor attr
  end

  SYSTEM = 0
  DATA = 1

  DEFAULTS = {
    :type => SYSTEM
  }.freeze

  def initialize(&block)
    ATTRIBUTES.each do |attr|
      self.__send__ "#{attr}=", DEFAULTS[attr]
    end
    yield(self)
  end

  def inspect
    ATTRIBUTES.inject({}) { |h,attr| h[attr] = self.__send__ attr; h }
  end
  def to_json
    self.inspect.to_json
  end
end

Это позволяет сделать это:

vol = Volume.new do |v|
  v.name = 'myVolume'
end

Мне это нравится, потому что это дает преимущество сразу же выдавать ошибки, если кто-то сделал опечатка в атрибуте.

Кроме того, в отличие от его ответа, он инициализирует значения по умолчанию, если они не указаны.

или если вы в конечном итоге делаете это много и действительно нуждаетесь в DRY:

module Attributable
  @@ATTRIBUTES = []
  @@DEFAULTS = {}

  def initialize(&block)
    @@ATTRIBUTES.each do |attr|
      self.class.__send__ :attr_accessor, attr
      self.__send__ "#{attr}=", @@DEFAULTS[attr]
    end
    yield(self)
  end
end

class Volume
  include Attributable
  @@ATTRIBUTES = [ :name, :size, :type, :owner ]
  @@DEFAULTS = { :type => 0 }
end

не могли понять, как это сделать с константами, поэтому я сделал это с переменными класса.

1
ответ дан 1 December 2019 в 12:27
поделиться