I just want to use Null Object Design Pattern, but I found I can inherit from NilClass.
I can write a method "nil?" and return false but what if user write code below
if null_object
puts "shouldn't be here"
end
For clarify what I try to do is:
record = DB.find(1)
# if it can not find record 1, the bellow code should not raise exception
record.one_attr
# and what's more
if record
puts "sho开发者_如何学Gouldn't be here"
end
# I don't want to override all NilClass
An approach that may work for you is to overide the method #nil? in your Null object. This means that in your code to test for null you have to use obj.nil? and not just check for obj existence. This is probably reasonable, since you can distinguish between nil and null. Below is an example:
class NullClass
def nil?
true
end
def null_behavior
puts "Hello from null land"
end
end
Inheritance will work:
class NewClass < NullClass
end
Use like so:
normal = Class.new
null = NewClass.new
x = [normal, null]
x.each do |obj|
if obj.nil?
puts "obj is nil"
obj.null_behavior
end
end
Output:
obj is nil
Hello from null land
Just remember to use #.nil? for any checks that require Null and Nil to be false-ish.
Below this line was my WRONG initial answer
CustomNil = Class.new(NilClass)
class CustomNil
def self.new
###!!! This returns regular nil, not anything special.
end
end
[tests deleted for brevity]
Use at your own risk. I haven't researched what side effects this may cause or whether it will do what you want. But it seems it does have some nil like behavior
Instead of inheriting from NilClass
I do the following
class NullObject < BasicObject
include ::Singleton
def method_missing(method, *args, &block)
if nil.respond_to? method
nil.send method, *args, &block
else
self
end
end
end
This gives you any custom method that have been monkey patched onto NilClass
(such as ActiveSupport's blank?
and nil?
). You can also of course add custom null object behaviors, or change method_missing
to handle other calls differently (this one returns the NullObject for chaining, but you could return nil
for example).
I don't think Ruby actually allows you to inherit from NilClass and create an object based on it:
class CustomNilClass < NilClass
end
custom_nil_object = CustomNilClass.new
# => NoMethodError: undefined method `new' for CustomNilClass:Class
精彩评论