gpt4 book ai didi

ruby - 动态生成代码

转载 作者:太空宇宙 更新时间:2023-11-03 15:59:36 25 4
gpt4 key购买 nike

我有一大堆结构相似的方法,每个方法看起来都像这样:

def my_method_1
if params[:user_id]
#code that stays the same across my_method_1, 2, 3, 4, etc.
#code that varies across my_method_1, 2, 3, 4, etc.
elsif params[:tag_id]
#code that stays the same across my_method_1, 2, 3, 4, etc.
#code that varies across my_method_1, 2, 3, 4, etc.
else
#code that stays the same across my_method_1, 2, 3, 4, etc.
#code that varies across my_method_1, 2, 3, 4, etc.
end
end

我有 my_method_2、3、4 等。我想做的是避免为我拥有的每个方法输入所有这些,因为大部分代码都是重复的。我只想输入在方法 1、2、3、4 等中实际不同的代码位。

我在这方面的尝试使用了 eval(),它有效,并且肯定会耗尽我所有的个人方法,但让我感到不舒服。基本上,我有一个接受键值对的辅助方法,键是“上下文”,值是指定为字符串的“语句”:

def helper_method
hash.each do |context, statement|
if params[eval(":#{context}_id")]
#code that stays the same
eval(statement)
return
end
end
eval(hash[:none])
end

现在我的个人方法可以 super 枯燥,只需调用辅助方法并传入代码字符串:

def my_method_1
helper_method(
user: '#code that varies',
tag: '#code that varies',
none: '#code that varies'
)
end

同样,在字符串中输入大块代码让我感到不舒服。任何以另一种方式解决这个问题的帮助将不胜感激!

最佳答案

代码中的重复分支告诉我您的类可以使用一些重构来消除对多个 if 语句的需要。听起来您的类(class)需要委托(delegate)给另一个类(class)以获得特定功能。虽然我不知道你的类看起来像,或者它的意图,但以下是一个示例,你可以将其应用到你的代码中,这样你根本不需要生成动态方法。

具有重复 if 语句的假想 Order

考虑这个具有多个看起来相似的 if 语句的 Order 类:

class Order
attr_accessor :order_type

def discount_amount
if order_type == 1
.2
elsif order_type == 2
.5
else
0
end
end

def discount_end_date
if order_type == 1
DateTime.new(2014, 12, 31)
elsif order_type == 2
DateTime.new(2014, 3, 31)
else
# Always expires 100 years from now
DateTime.new(DateTime.now.year + 100, 1, 1)
end
end
end

我们提供三种折扣:2014 年底到期的 20% 折扣; 50%,将于 2014 年 3 月底到期。最后,0% 的默认折扣始终在 100 年后到期。让我们清理它以删除 if 语句,并将这些计算委托(delegate)给 Discount 类。

重构 Order 类以使用委托(delegate)方法

首先,让我们清理 Order 类,然后我们将实现一个 Discount 类:

class Order
attr_accessor :order_type

def discount
@discount ||=
if order_type == 1
Discount.twenty_percent_off
elsif order_type == 2
Discount.half_off
else
Discount.default_discount
end
end

def discount_amount
discount.amount
end

def discount_end_date
discount.end_date
end
end

干净整洁。 Order 对象需要 Discount 对象才能获得折扣金额和结束日期。 Order 类现在几乎可以无限扩展,因为计算折扣的逻辑已完全卸载到另一个类。 Order#order_type 值决定折扣。现在,让我们定义我们的 Discount 类。

实现折扣

根据我们的(假)业务规则,只有三种折扣:

  1. 20% 折扣,2014 年底到期
  2. 50% 折扣,2014 年 3 月底到期
  3. 0% 折扣(无折扣),从今天起 100 年过期,本质上意味着它永远不会过期

我们不希望人们创建任意折扣,所以让我们将我们的 Discount 实例限制为仅使用私有(private)构造函数定义的实例,然后为每种折扣声明静态方法:

class Discount
private_class_method :new

def self.default_discount
@@default_discount ||= new(0)
end

def self.half_off
@@half_off_discount ||= new(.5, DateTime.new(2014, 3, 31))
end

def self.twenty_percent_off
@@twenty_percent_off ||= new(.2, DateTime.new(2014, 12, 31))
end

def initialize(amount, end_date = nil)
@amount = amount
@end_date = end_date
end

def amount
@amount
end

def end_date
@end_date ||= DateTime.new(DateTime.now.year + 100, 1, 1)
end
end

尝试运行 Discount.new(...) 应该会引发错误。我们只有三个折扣实例可用:

Discount.half_off
Discount.twenty_percent_off
Discount.default_discount

鉴于 Order#order_type 用于确定折扣,我们通过 Order#discount 返回正确的 Discount 实例来模拟这一点在 Order#order_type 上。此外,我们通过定义自己的折扣来防止人们玩弄系统,并且所有折扣的逻辑都在一个类中。

order = Order.new
order.order_type = 1
puts order.discount_amount # -> .2

order = Order.new
order.order_type = 2
puts order.discount_amount # -> .5

您可以使用子类来创建更具体的业务逻辑,例如“随机”折扣:

class Discount
protected_class_method :new

...

def self.random
@random_discount ||= RandomDiscount.new(nil)
end

class RandomDiscount < Discount
def amount
rand / 2
end
end
end

现在 Discount.random.amount 每次输出不同的折扣。可能性变得无穷无尽。

这如何适用于您的问题

重复 if 语句的存在意味着你的类做的太多了。它应该委托(delegate)给另一个专门研究这些代码分支之一的类。您不必在运行时操作 Ruby 中的方法来实现此目的。它太“神奇”了,让新开发者感到困惑。使用我上面概述的方法,您可以获得这些折扣的强类型定义,并且您让每个类都专注于一项任务(不,如果正确使用,“强类型”在 Ruby 中不是一个四字母单词)。您将获得对象之间明确定义的关系、更易于测试的代码,并且可以强有力地执行业务规则。一切都没有“魔法”。

关于ruby - 动态生成代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28327729/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com