Хотите написать класс Tag - PullRequest
0 голосов
/ 13 апреля 2010

Я хочу написать класс Tag (тег - это строка без пробелов). Моя первая мысль - наследовать от String:

class Tag < String
  def initialize(str)
    raise ArgumentError if str =~ /\s/
    super
  end
end

Это выглядит правильно? Есть ли другие методы, которые я должен переопределить?

Ответы [ 3 ]

2 голосов
/ 13 апреля 2010

Вы не должны наследовать от String, как по причинам хорошего объектно-ориентированного дизайна, так и чистого прагматизма.

Если вы наследуете от String, вы нарушаете принцип подстановки Лискова, который гласит, что экземпляры подклассов должны заменять экземпляры их суперкласса. Это не тот случай: я могу вставить пробел в середине String, но не могу вставить пробел в середине Tag, поэтому Tag не является заменой для String и, следовательно, не должно быть подклассом.

И с чисто практической точки зрения: вы наследуете около 100 открытых методов экземпляра от String. Вы действительно хотите провести аудит (и, возможно, переопределить) каждого из них , чтобы убедиться, что они не нарушают Tag контракт?

Я бы предпочел сделать что-то вроде этого:

require 'facets/multiton'

class Tag
  include Multiton

  attr_reader :name
  attr_accessor :description

  private

  def initialize name, description=nil
    raise ArgumentError, 'Tag name cannot contain whitespace' if str =~ /\s/

    self.name = name.to_s.dup.freeze
    self.description = description unless description.nil?
  end

  attr_writer :name

  def self.multiton_id name, description=nil
    return name.to_s.downcase
  end
end
2 голосов
/ 13 апреля 2010

В порядке другие буквы?

вы можете убедиться, что строка соответствует вашим критериям вместо не , соответствующей ей.

Примеры:

1. /^\w+$/      ensures at least one word character (ThisIsAValidTag_123)
2. /^[a-z]+$/   ensures at least one lowercase a to z only
3. /^[a-z]+$/i  ensures at least one a to z upper *or* lowercase.

Использование в классе:

class Tag < String
  def initialize(str)
    raise ArgumentError unless str =~ /^[a-z]+$/
    super
  end
end

Все, что сказано, звучит очень похоже на Ruby symbols.

1 голос
/ 13 апреля 2010

Будет довольно сложно сделать его герметичным. В настоящее время:

puts Tag.new("with_space").tr!("_"," ") # ==> prints "with space"

В основном вам необходимо специализировать все изменяющие методы (например, #tr!), вызывая super и добавляя проверку в конце, а также все методы, возвращающие измененную копию self (например, #tr).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...