Вы могли бы шпаргалка из FalseClass и установить те же методы оператора на NoThing
.Но я бы не решился сделать это по ряду причин.
В отличие от некоторых других языков, Ruby очень ясно, что существует очень ограниченный набор ложных вещей, false
и nil
.Неразбериха с этим, вероятно, приведет к путанице и ошибкам в будущем, вероятно, это не стоит того удобства, которое вы ищете.
Кроме того, Null Object Pattern - это возвращение объекта с тем же интерфейсом.как объект, который что-то делает, но ничего не делает.Его появление false
победило бы это.Желание написать @thing ||= Thing.new
противоречит желанию обнулить объект.Вы всегда хотите установить @thing
, даже если Thing.new
вернет NoThing
, вот для чего нужны нулевые объекты.Код, использующий класс, не заботится, использует ли он Thing
или NoThing
.
Вместо этого, для тех случаев, когда вы хотите различить Thing
и NoThing
, я бы предложил иметьмаленький метод, например #nothing?
.Затем установите Thing#nothing?
для возврата false
и NoThing#nothing?
для возврата true
.Это позволяет вам различать их, спрашивая, а не пробивая инкапсуляцию по жестким кодовым именам классов.
class NoThing
def status
:cancelled
end
def expires_on
0.days.from_now
end
def gateway
""
end
def nothing?
true
end
end
class Thing
attr_accessor :status, :expires_on, :gateway
def initialize(args={})
@status = args[:status]
@expires_on = args[:expires_on]
@gateway = args[:gateway]
end
def nothing?
false
end
end
Кроме того, Thing.new
плохо возвращать что-либо, кроме Thing
.Это добавляет дополнительную сложность к тому, что должно быть простым конструктором.Он даже не должен возвращать nil
, вместо этого должно выдаваться исключение.
Вместо этого используйте Factory Pattern , чтобы Thing
и NoThing
были чистыми и простыми.Поместите произведение, чтобы решить, следует ли вернуть Thing
или NoThing
в ThingBuilder
или ThingFactory
.Затем вы вызываете ThingFactory.new_thing
, чтобы получить Thing
или NoThing
.
class ThingFactory
def self.new_thing(arg)
# Just something arbitrary for example
if arg > 5
return Thing.new(
status: :allgood,
expires_on: Time.now + 12345,
gateway: :somewhere
)
else
return NoThing.new
end
end
end
puts ThingFactory.new_thing(4).nothing? # true
puts ThingFactory.new_thing(6).nothing? # false
Затем, если вам это действительно нужно, на фабрике также может быть отдельный метод класса, которыйвозвращает nil
вместо NoThing
с учетом @thing ||= ThingFactory.new_thing_or_nil
.Но вам это не нужно, потому что это то, для чего предназначен шаблон нулевого объекта.Если вам это действительно нужно, используйте #nothing?
и троичный оператор.
thing = ThingFactory.new_thing(args)
@thing = thing.nothing? ? some_default : thing