一个程序应该能够用一个子类的实例替换父类的任何实例,而不会产生负面的副作用,即为LSP原则。
违反LSP原则案例
在我们的示例中,我们尝试用子类(AdminUser类)的实例替换其父类。通过执行这个操作,它破坏了程序,我认为这是一个负面的副作用。
require 'date'
class User
def initialize(email:)
@email = email
end
attr_accessor :settings, :email
end
class AdminUser < User
end
user = User.new(email: "user@test.com")
user.settings = {
"level" => "Low Security",
"status" => "Live",
signed_in: Date.today
}
admin = AdminUser.new(email: "admin@test.com")
admin.settings = ["Editor", "VIP", Date.today]
# puts user.settings
# puts admin.settings
@user_database =[user, admin]
def signed_in_today?
@user_database.each do |user|
if user.settings[:signed_in] == Date.today
puts "#{user.email} singed in today"
end
end
end
signed_in_today?
解决方案
使用
ostruct
库文件,并规范化设置@settings
的数值
require 'date'
require 'ostruct'
class User
def initialize(email:)
@email = email
end
def set_settings(level:, status:, signed_in:)
@settings = OpenStruct.new(
level: level,
status: status,
signed_in: signed_in
)
end
def get_settings
@settings
end
attr_accessor :settings, :email
end
class AdminUser < User
end
user = User.new(email: "user@test.com")
user.settings = {
"level" => "Low Security",
"status" => "Live",
signed_in: Date.today
}
admin = AdminUser.new(email: "admin@test.com")
admin.settings = {
level: "Editor" ,
status: "VIP" ,
signed_in: Date .today
}
# puts user.settings
# puts admin.settings
@user_database =[user, admin]
def signed_in_today?
@user_database.each do |user|
if user.settings[:signed_in] == Date.today
puts "#{user.email} singed in today"
end
end
end
signed_in_today?