寻找关于如何改进我的代码和领域的技巧,我可以更好地遵循面向对象的原则。这个班结构可以吗?代码的总体情况如何?
问题:有两个IBAN标准: IBAN-10和IBAN-13.IBAN-10是由9个数字加上一个支票数字组成的.IBAN-13是由12位数字加上一个支票数字组成的。空格和连字符可能包含在代码中,但并不重要。
IBAN-10的校验是通过将每一位数乘以其位置,将这些积加在一起并取结果的模数11来计算的。如果结果是10,则替换X。
IBAN-13的校验数字是通过将每一个数字交替乘以1或3,将这些乘积相加,取结果的模10并从10中减去这个值来计算的。然后用这个结果取10的模,从而将这个数降为一位数。
如果是有效的IBAN-10/IBAN-13,则返回true。
class IBAN
def initialize(number)
puts "number: #{number}"
@number = number
@number.gsub!(/[^0-9]/i, '')
return @number
end
def number
@number
end
# # check IBAN length and if valid proceed to process IBAN type
def check_number_format
iban_length = self.number.length
unless iban_length == 10 || iban_length == 13
puts "Not a valid IBAN - incorrect length"
return false
else
self.validate_iban_type
end
end
def validate_iban_type
case self.number.length
when 10
@iban_ten = IBANTEN.new(self.number)
@iban_ten.process_ten_digit_iban
when 13
@iban_thirteen = IBANTHIRTEEN.new(self.number)
@iban_thirteen.process_thirteen_digit_iban
else
return false
end
end
end
class IBANTEN
def initialize(iban_number)
@iban_number = iban_number
end
def iban_number
@iban_number
end
def process_ten_digit_iban
number_split = self.iban_number.split('')
final_digit = number_split[-1]
running_total = 0
number_split[0, (number_split.length - 1)].each_with_index do |num, index|
# multiply each digit by its position
sum = num.to_i * (index.to_i + 1)
running_total += sum.to_i
end
# get the modulus of the running total if it exuals 10 replace it with X otherwise return the result
digit_sum_total = running_total % 11
calculated_result = digit_sum_total == 10 ? "X" : digit_sum_total
if calculated_result == final_digit.to_i
puts "Valid IBAN-10 Number"
return true
else
puts "Invalid IBAN-10 Number"
return false
end
end
end
class IBANTHIRTEEN
def initialize(iban_number)
@iban_number = iban_number
end
def iban_number
@iban_number
end
def process_thirteen_digit_iban
number_split = self.iban_number.split('')
final_digit = number_split[-1]
running_total = 0
number_split[0, (number_split.length - 1)].each_with_index do |num, index|
# if the remainder equals zero multiply by 1 otherwise multiplu by 3
sum = (index % 2 == 0 ) ? num.to_i * 1 : num.to_i * 3
running_total += sum.to_i
end
# modulo 10 of the result and subtracting this value from 10, and then taking the modulo 10 of the result again to produce a single digit
calculated_result = ( (10 - (running_total % 10) ) % 10)
if calculated_result == final_digit.to_i
puts "Valid IBAN-13 Number"
return true
else
puts "Invalid IBAN-13 Number"
return false
end
end
end
@iban_v13_valid = IBAN.new("978 0 471 48648 0")
@iban_v13_valid.check_number_format
@iban_v13_invalid = IBAN.new("9780470059021")
@iban_v13_valid.check_number_format
@iban_v10_valid = IBAN.new("0 471 60695 2")
@iban_v10_valid.check_number_format
@iban_v10_invalid = IBAN.new("0-470-84525-6")
@iban_v10_invalid.check_number_format
@iban_invalid_length = IBAN.new("0-470-84525-618423")
@iban_invalid_length.check_number_format发布于 2018-03-23 16:24:56
假设你喜欢使用3个不同的类;
gsub!和gsub之间的区别。attr_而不是编写方法。#process_ten_digit_iban和#process_thirteen_digit_iban,因为它们非常相似。puts valid/invalid以保持代码的干爽。class IBAN
REQUIRED_LENGTH = [10, 13].freeze
attr_reader :number
def initialize(number)
@number = number.gsub(/[^0-9]/i, '')
end
def validate_iban_type
return if check_number_format?
case number.length
when 10
IBANTEN.new(number).process_ten_digit_iban
when 13
IBANTHIRTEEN.new(number).process_thirteen_digit_iban
else
false
end
end
# check IBAN length and if valid proceed to process IBAN type
def check_number_format?
iban_length = number.length
raise 'Incorrect length' unless REQUIRED_LENGTH.include?(iban_length)
end
end
class IBANTEN
attr_reader :iban_number
def initialize(iban_number)
@iban_number = iban_number
end
def process_ten_digit_iban
numbers_array = iban_number.split('')
total = 0
numbers_array[0, (numbers_array.length - 1)].each_with_index do |num, index|
# multiply each digit by its position
sum = num.to_i * (index.to_i + 1)
total += sum
end
# get the modulus of the running total if it exuals 10 replace it with X
# otherwise return the result
digit_sum_total = total % 11
result = digit_sum_total == 10 ? 'X' : digit_sum_total
if result == numbers_array[-1].to_i
puts 'Valid IBAN-10 Number'
true
else
puts 'Invalid IBAN-10 Number'
false
end
end
end
class IBANTHIRTEEN
attr_reader :iban_number
def initialize(iban_number)
@iban_number = iban_number
end
def process_thirteen_digit_iban
numbers_array = iban_number.split('')
total = 0
numbers_array[0, (numbers_array.length - 1)].each_with_index do |num, index|
# if the remainder equals zero multiply by 1 otherwise multiply by 3
sum = index.even? ? num.to_i * 1 : num.to_i * 3
total += sum
end
# modulo 10 of the result and subtracting this value from 10, and then
# taking the modulo 10 of the result again to produce a single digit
result = ((10 - (total % 10)) % 10)
if result == numbers_array[-1].to_i
puts 'Valid IBAN-13 Number'
true
else
puts 'Invalid IBAN-13 Number'
false
end
end
end
iban_v13_valid = IBAN.new('978 0 471 48648 0')
iban_v13_valid.validate_iban_type
iban_v13_invalid = IBAN.new('9780470059021')
iban_v13_invalid.validate_iban_type
iban_v10_valid = IBAN.new('0 471 60695 2')
iban_v10_valid.validate_iban_type
iban_v10_invalid = IBAN.new('0-470-84525-6')
iban_v10_invalid.validate_iban_type
iban_invalid_length = IBAN.new('0-470-84525-618423')
iban_invalid_length.validate_iban_type发布于 2018-04-01 14:07:46
我希望为这三种情况实现一个具有不同实现的结构:
您可以提供这样的内容,其中IBAN#new被重写以检测提供的整数数量,并初始化正确的对象来处理它。
这里真正的诀窍是提供Invalid模块,它响应您期望Thirteen和Ten对象响应的所有东西,在类似于Nil对象模式的实现中--在本例中是无效对象。
我忽略了#valid? etc类的实现,但将指向Lisbn gem,在这个gem中,我们实现了一个非常快速的算法https://github.com/ragalie/lisbn/blob/master/lib/lisbn/lisbn.rb#L111。基于可枚举方法的基准测试通常看起来相当优雅,该算法比在某些ISBN gems中实现的相同逻辑快40倍。
下面是代码大纲:
module IBAN
def self.new(string)
numeric = string.gsub(/[^0-9]/,"")
case numeric.size
when 13
then Thirteen.new(string)
when 10
then Ten.new(string)
else
Invalid
end
end
class Thirteen
def initialize(number)
@number = number
end
def checksum
# TODO
end
def valid?
# TODO
end
attr_reader :number
end
class Ten
def initialize(number)
@number = number
end
def checksum
# TODO
end
def valid?
# TODO
end
attr_reader :number
end
module Invalid
def self.valid?
false
end
def self.checksum
nil
end
end
endps。您可能更喜欢将Invalid实现为单例而不是模块。
...
else
Invalid.instance
end
...
class Invalid
include Singleton
def valid?
false
end
def checksum
nil
end
end
endhttps://codereview.stackexchange.com/questions/190139
复制相似问题