Цель класса - объединить похожие объекты или объекты с похожим поведением. 1
и 2
очень похожи, поэтому для них имеет смысл быть в одном классе. true
и false
однако не похожи. Фактически, их весь смысл в том, что они в точности противоположны друг от друга и имеют противоположное поведение. Следовательно, они не принадлежат к одному и тому же классу.
Можете ли вы привести пример того, какое обычное поведение вы бы реализовали в классе Boolean
? Я не могу думать ни о чем.
Давайте просто посмотрим на поведение, которое имеют TrueClass
и FalseClass
: там есть ровно четыре метода. Больше не надо. И в каждом отдельном случае оба метода делают прямо противоположным . Как и почему вы поместите это в один класс?
Вот как вы реализуете все эти методы:
class TrueClass
def &(other)
other
end
def |(_)
self
end
def ^(other)
!other
end
def to_s
'true'
end
end
А теперь наоборот:
class FalseClass
def &(_)
self
end
def |(other)
other
end
def ^(other)
other
end
def to_s
'false'
end
end
Конечно, в Ruby за кулисами происходит много "магии", которая на самом деле не обрабатывается TrueClass
и FalseClass
, а скорее встроена в интерпретатор. Вещи как if
, &&
, ||
и !
. Тем не менее, в Smalltalk, у которого Ruby много позаимствовал, включая концепцию FalseClass
и TrueClass
, все они также реализованы как методы, и вы можете сделать то же самое в Ruby:
class TrueClass
def if
yield
end
def ifelse(then_branch=->{}, _=nil)
then_branch.()
end
def unless
end
def unlesselse(_=nil, else_branch=->{})
ifelse(else_branch, _)
end
def and
yield
end
def or
self
end
def not
false
end
end
И снова наоборот:
class FalseClass
def if
end
def ifelse(_=nil, else_branch=->{})
else_branch.()
end
def unless
yield
end
def unlesselse(unless_branch=->{}, _=nil)
ifelse(_, unless_branch)
end
def and
self
end
def or
yield
end
def not
true
end
end
Пару лет назад я написал вышесказанное просто для забавы и даже опубликовал его . Помимо того, что синтаксис выглядит иначе, потому что Ruby использует специальные операторы, а я использую только методы, он ведет себя точно так же, как встроенные операторы Ruby. На самом деле я взял тестовый набор на соответствие RubySpec и перенес его на мой синтаксис и он прошел.