我有很多实例方法,它们都共享相同的实例变量。由于这个类变得很大,我将这些方法分成了大约50个模块。然后剩下的类包括所有这50个模块。
我最终得到了一个令人难以置信的丑陋代码,其中充满了像"module_name_method_name"这样的实例方法,以避免方法名称的冲突。问题是,每个模块可能具有相似(相似,不相同)的功能(进而具有相似的方法名称)。
我当前的代码如下:
模块:
module Toyota
def toyota_method1;@foo...;end
def toyota_method2;@foo...;end
....
end
module Ford
def ford_method1;@foo...;end
def ford_method2;@foo...;end
....
end
大约50个这样的模块
class Cars
include Toyota
include Ford
include ...
def foo
@foo = "bar"
@bar = "foo"
...
toyota_method1
ford_method2
toyota_method2
...
end
end
如何更好地设计代码?最重要的是,所有实例方法都需要共享相同的实例变量。。或者至少以某种方式访问相同的数据!
编辑:我自己刚刚想到这个:
class Toyota
attr_accessor :foo
def method1
puts @foo
end
end
class Ford
attr_accessor :foo
def method1
puts @foo
end
end
class Cars
def foo
@foo = "bar"
toyota = Toyota.new
toyota.foo = @foo
toyota.method1
ford = Ford.new
ford.foo = @foo
ford.method1
end
end
cars = Cars.new
cars.foo
事实上,它解决了丑陋的方法名称问题,但现在我正在处理新的问题:变量@foo可能很大,它将自己复制50次(或更多)到内存中(因为我有50个这样的类)。
还有其他解决方案吗?
它不仅重复了50次或更多,而且每个实例都重复,因为它是一个实例变量。根据我对代码的了解,如果我错了,你必须纠正我的错误,最好在类级别上使用继承和变量共享。如果你的汽车类真的需要了解各种车型的所有不同方法,这可能不起作用,但我认为你从一开始就做错了。让我们来看看继承:
class Car
attr_accessor :foo
# lets you initialize attributes via a hash
#
def initialize attrs={}
super()
attrs.each do |att, value|
self.send(:"#{att}=", value)
end
end
end
从Car
:继承Toyota
class Toyota < Car
def method1
# do what you want to do in this method
end
end
与Ford
:相同
class Ford < Car
def method1
# do what you want to do in this method
end
end
像这样,您不必将名称空间放在方法前面:
Ford.new(:foo => 'fordfoo').foo #=> will put out «fordfoo»
Toyota.new(:foo => 'toyotafoo').foo #=> will put out «toyotafoo»
跨类共享
现在,如果foo
在所有汽车中共享,那么如果它是静态的,您可以使它成为汽车类上的一个常数:
class Car
FOO = 'bar'
def put_foo
puts FOO
end
end
像这样,Car
、Toyota
或Ford
的所有实例都可以访问静态常量FOO
,该常量在内存中只存在一次:
Toyota.new.put_foo #=> 'bar'
如果foo
必须是可赋值的,并且对于整个继承树只存在一次,则使用类变量:
class Car
class << self
def foo= data
@@foo = data
end
end
def foo= data
self.class.foo = data
end
def foo
@@foo
end
end
现在@@foo
对于继承树只存在一次,所以如果您这样做:
car = Car.new
toyota = Toyota.new
toyota.foo = 'toyota'
car.foo #=> 'toyota'
如果你不注意,这可能会导致严重的问题,但如果所有类的foo
都必须相同,那就另当别论了。使用类变量时,线程安全性也有一些问题需要解决(使用Mutex
)。
如果Car
、Toyota
和Ford
都有不同的foo
,但每个类的实例都需要共享同一个foo(因此总共有3个foo),则使用类实例变量:
class Car
class << self
def foo= data
@foo = data
end
def foo
@foo
end
end
def foo= data
self.class.foo = data
end
def foo
self.class.foo
end
end
像这样你会得到:
car = Car.new
car.foo = 'bla'
toyota = Toyota.new
toyota.foo #=> is nil
toyota.foo = 'bar'
car.foo #=> still 'bla'
toyota.foo #=> is 'bar'
这些是在实例之间共享相同数据的方法。