Ruby中编写类与模块的作风指南,Ruby中的会集编写

作者: 韦德国际1946手机版  发布:2019-06-02

在 class 定义里使用一样的协会。

Ruby中编写类与模块的风骨指南,ruby编写风格指南

在 class 定义里采纳一样的结构。

    

class Person
   # extend and include go first
   extend SomeModule
   include AnotherModule

   # constants are next
   SOME_CONSTANT = 20

   # afterwards we have attribute macros
   attr_reader :name

   # followed by other macros (if any)
   validates :name

   # public class methods are next in line
   def self.some_method
   end

   # followed by public instance methods
   def some_method
   end

   # protected and private methods are grouped near the end
   protected

   def some_protected_method
   end

   private

   def some_private_method
   end
  end

    倾向利用 module,而不是唯有类方式的 class。种类应该只在创制实例是在理的时候利用。

   

 # bad
  class SomeClass
   def self.some_method
    # body omitted
   end

   def self.some_other_method
   end
  end

  # good
  module SomeClass
   module_function

   def some_method
    # body omitted
   end

   def some_other_method
   end
  end

    当您愿意将模块的实例方法成为 class 方法时,偏爱接纳 module_function 胜过 extend self。

 

  # bad
  module Utilities
   extend self

   def parse_something(string)
    # do stuff here
   end

   def other_utility_method(number, string)
    # do some more stuff
   end
  end

  # good
  module Utilities
   module_function

   def parse_something(string)
    # do stuff here
   end

   def other_utility_method(number, string)
    # do some more stuff
   end
  end

    When designing class hierarchies make sure that they conform to the
    Liskov Substitution Principle.

    在布置类档期的顺序的时候保险他们适合 Liskov Substitution Principle 原则。(译者注: LSP原则大致意思为: 要是1个函数中援引了 父类的实例, 则一定能够使用其子类的实例代替, 并且函数的基本作用不改变. (就算效果允许被扩大))

        Liskov替换原则:子类型必须能够替换它们的基类型 <br/>
        1. 假诺每2个类型为T壹的指标o一,都有品种为T2的目的o二,使得以T壹概念的富有程序P在具有的对象o一都退换为o二时,程序P的作为尚未成形,那么类型T二是项目T一的子类型。 <br/>
        二. 换言之,二个软件实体假诺应用的是3个基类的话,那么势必适用于其子类,而且它根本不能够察觉出基类对象和子类对象的界别。唯有衍生类替换基类的同期软件实体的功效尚未发生变化,基类能力当真被复用。 <br/>
        三. 里氏代换原则由Barbar Liskov(芭芭拉.里氏)建议,是持续复用的水源。 <br/>
Ruby中编写类与模块的作风指南,Ruby中的会集编写指南。        4. 多个一而再是或不是适合里氏代换原则,能够判明该持续是还是不是合理(是还是不是隐身不平时)。

    努力令你的类尽只怕的健壮 [SOLID](

    总是为你协和的类提供 to_s 方法, 用来显示那几个类(实例)对象涵盖的对象.

   

 class Person
   attr_reader :first_name, :last_name

   def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
   end

   def to_s
    "#@first_name #@last_name"
   end
  end

    使用 attr 功效成员来定义各种实例变量的访问器或许修改器方法。

  

 # bad
  class Person
   def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
   end

   def first_name
    @first_name
   end

   def last_name
    @last_name
   end
  end

  # good
  class Person
   attr_reader :first_name, :last_name

   def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
   end
  end

    制止采纳 attr。使用 attr_reader 和 attr_accessor 作为代替。

  # bad - creates a single attribute accessor (deprecated in 1.9)
  attr :something, true
  attr :one, :two, :three # behaves as attr_reader

  # good
  attr_accessor :something
  attr_reader :one, :two, :three

    思虑接纳 Struct.new, 它能够定义一些零碎的 accessors,
    constructor(构造函数) 和 comparison(相比较) 操作。

  # good
  class Person
   attr_reader :first_name, :last_name

   def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
   end
  end

  # better
  class Person < Struct.new(:first_name, :last_name)
  end

    惦记使用 Struct.new,它替你定义了这个琐碎的存取器(accessors),构造器(constructor)以及比较操作符(comparison operators)。

  # good
  class Person
   attr_accessor :first_name, :last_name

   def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
   end
  end

  # better
  Person = Struct.new(:first_name, :last_name) do
  end

    不要去 extend 1个 Struct.new - 它曾经是二个新的 class。扩大它会产生七个盈余的 class 层级
    并且可能会时有产生玄妙的荒唐要是文件被加载数拾贰次。

    思量加多工厂方法来提供灵活的方法来创制特定类实例。

    

class Person
   def self.create(potions_hash)
    # body omitted
   end
  end

    鸭子类型(duck-typing)优于承接。

  

 # bad
  class Animal
   # abstract method
   def speak
   end
  end

  # extend superclass
  class Duck < Animal
   def speak
    puts 'Quack! Quack'
   end
  end

  # extend superclass
  class Dog < Animal
   def speak
    puts 'Bau! Bau!'
   end
  end

  # good
  class Duck
   def speak
    puts 'Quack! Quack'
   end
  end

  class Dog
   def speak
    puts 'Bau! Bau!'
   end
  end

    Avoid the usage of class (@@) variables due to their "nasty" behavior
    in inheritance.

    幸免选择类变量(@@)因为她俩讨厌的接续习于旧贯(在子类中也得以修改父类的类变量)。

   

 class Parent
   @@class_var = 'parent'

   def self.print_class_var
    puts @@class_var
   end
  end

  class Child < Parent
   @@class_var = 'child'
  end

  Parent.print_class_var # => will print "child"

    正如上例看到的, 全数的子类共享类变量, 并且能够平素修改类变量,此时选拔类实例变量是更加好的主意.

    根据章程的用途为他们分合作适的可知度( private, protected ),不要让抱有的艺术都是 public (那是暗中认可设定)。那是 Ruby 不是 Python。

    public, protected, 和 private 等可知性关键字应该和其(钦赐)的点子具备同样的缩进。并且差别的可见性关键字之间留2个空格。

   

 class SomeClass
   def public_method
    # ...
   end

   private

   def private_method
    # ...
   end

   def another_private_method
    # ...
   end
  end

    使用 def self.method 来定义单例方法. 今世码重构时, 那将使得代码尤其便于因为类名是不另行的.

  class TestClass
   # bad
   def TestClass.some_method
    # body omitted
   end

   # good
   def self.some_other_method
    # body omitted
   end

   # Also possible and convenient when you
   # have to define many singleton methods.
   class << self
    def first_method
     # body omitted
    end

    def second_method_etc
     # body omitted
    end
   end
  end

  class SingletonTest
   def size
    25
   end
  end

  test1 = SingletonTest.new
  test2 = SingletonTest.new
  def test2.size
   10
  end
  test1.size # => 25
  test2.size # => 10

    本例中,test一 與 test2 屬於同一類別,但 test二 具备双重定義的 size 方法,因而兩者的行為會不一樣。只給予單一物件的主意稱為单例方法 (singleton method)。

在 class 定义里使用一样的构造。 class Person # extend and include go first extend SomeModule include A...

Ruby中的集结编写指南,Ruby会集编写指南

同情数组及哈希的字面表示法(除非你必要传递参数到它们的构造函数中)。

  # bad
  arr = Array.new
  hash = Hash.new

  # good
  arr = []
  hash = {}

    当你要求成分为单词(未有空格和特殊符号)的数组的时候总是利用 %w 的艺术来定义字符串数组。应用那条规则仅仅在八个或多少个数组。

  # bad
  STATES = ['draft', 'open', 'closed']

  # good
  STATES = %w(draft open closed)

    当您要求三个符号的数组(并且无需保持 Ruby 1.九 包容性)时,使用 %i。仅当数组唯有七个及以上因素时才使用这几个规则。

  # bad
  STATES = [:draft, :open, :closed]

  # good
  STATES = %i(draft open closed)

    防止在 Array 恐怕 Hash 的最终1项前面出现逗号,非常是当那些条约不在壹行。

  # bad - easier to move/add/remove items, but still not preferred
  VALUES = [
        1001,
        2020,
        3333,
       ]

  # bad
  VALUES = [1001, 2020, 3333, ]

  # good
  VALUES = [1001, 2020, 3333]

    制止在数组中开创巨大的距离。

  arr = []
  arr[100] = 1 # now you have an array with lots of nils

    当访问八个数组的率先个可能最终1个成分,倾向使用 first 或 last 而不是 [0] 或 [-1]。

    尽管要保管元素唯一, 则使用 Set 代替 Array .Set 更切合于无顺序的, 并且成分唯1的聚合, 群集具备类似于数组一致性操作以及哈希的神速查找.

    尽大概使用标记取代字符串作为哈希键.

  # bad
  hash = { 'one' => 1, 'two' => 2, 'three' => 3 }

  # good
  hash = { one: 1, two: 2, three: 3 }

    制止采纳易变对象作为哈希键。

    优先选择 壹.九 的新哈希语法当您的哈希键是符号。

  # bad
  hash = { :one => 1, :two => 2, :three => 3 }

  # good
  hash = { one: 1, two: 2, three: 3 }

    在同1的 hash 字面量中不用混合 Ruby 壹.玖 hash 语法和箭头情势的 hash。当您
    获得的 keys 不是标识的时候转变为箭头格局的语法。

  # bad
  { a: 1, 'b' => 2 }

  # good
  { :a => 1, 'b' => 2 }

    用 Hash#key? 不用 Hash#has_key? 以及用 Hash#value?, 不用 Hash#has_value? 马茨 提到过 长的情势在牵挂被弃用。

  # bad
  hash.has_key?(:test)
  hash.has_value?(value)

  # good
  hash.key?(:test)
  hash.value?(value)

    在拍卖相应存在的哈希键时,使用 fetch。

  heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' }
  # bad - if we make a mistake we might not spot it right away
  heroes[:batman] # => "Bruce Wayne"
  heroes[:supermann] # => nil

  # good - fetch raises a KeyError making the problem obvious
  heroes.fetch(:supermann)

    在采纳 fetch 时,使用第二个参数设置暗许值而不是行使自定义的逻辑。

  batman = { name: 'Bruce Wayne', is_evil: false }

  # bad - if we just use || operator with falsy value we won't get the expected result
  batman[:is_evil] || true # => true

  # good - fetch work correctly with falsy values
  batman.fetch(:is_evil, true) # => false

    尽量用 fetch 加区块而不是向来设定暗许值。

  batman = { name: 'Bruce Wayne' }

  # bad - if we use the default value, we eager evaluate it
  # so it can slow the program down if done multiple times
  batman.fetch(:powers, get_batman_powers) # get_batman_powers is an expensive call

  # good - blocks are lazy evaluated, so only triggered in case of KeyError exception
  batman.fetch(:powers) { get_batman_powers }

    当你须求从3个 hash 延续的取回一多种的值的时候利用 Hash#values_at。

  # bad
  email = data['email']
  nickname = data['nickname']

  # good
  email, username = data.values_at('email', 'nickname')

    记住, 在 Ruby壹.九 中, 哈希的变现不再是冬辰的. (译者注: Ruby一.9将会记住成分插入的类别)

    当遍历3个汇合的同时, 不要改变那些集结。

倾向数组及哈希的字面表示法(除非您须要传递参数到它们的构造函数中)。 # bad arr = Array.new hash...

同情数组及哈希的字面表示法(除非您需求传递参数到它们的构造函数中)。

    

  # bad
  arr = Array.new
  hash = Hash.new

  # good
  arr = []
  hash = {}
class Person
   # extend and include go first
   extend SomeModule
   include AnotherModule

   # constants are next
   SOME_CONSTANT = 20

   # afterwards we have attribute macros
   attr_reader :name

   # followed by other macros (if any)
   validates :name

   # public class methods are next in line
   def self.some_method
   end

   # followed by public instance methods
   def some_method
   end

   # protected and private methods are grouped near the end
   protected

   def some_protected_method
   end

   private

   def some_private_method
   end
  end

    当您供给成分为单词(未有空格和特殊符号)的数组的时候总是选取 %w 的诀要来定义字符串数组。应用那条规则仅仅在多个或多个数组。

    倾向使用 module,而不是只有类措施的 class。连串应该只在创造实例是客观的时候使用。

  # bad
  STATES = ['draft', 'open', 'closed']

  # good
  STATES = %w(draft open closed)

   

    当您需求3个标记的数组(并且不须要保持 Ruby 一.九 包容性)时,使用 %i。仅当数组只有八个及以上因素时才使用这么些规则。

 # bad
  class SomeClass
   def self.some_method
    # body omitted
   end

   def self.some_other_method
   end
  end

  # good
  module SomeClass
   module_function

   def some_method
    # body omitted
   end

   def some_other_method
   end
  end
  # bad
  STATES = [:draft, :open, :closed]

  # good
  STATES = %i(draft open closed)

    当您期望将模块的实例方法成为 class 方法时,偏爱选择 module_function 胜过 extend self。

    防止在 Array 大概 Hash 的末梢1项前边出现逗号,极其是当这个条目不在一行。

 

  # bad - easier to move/add/remove items, but still not preferred
  VALUES = [
        1001,
        2020,
        3333,
       ]

  # bad
  VALUES = [1001, 2020, 3333, ]

  # good
  VALUES = [1001, 2020, 3333]
  # bad
  module Utilities
   extend self

   def parse_something(string)
    # do stuff here
   end

   def other_utility_method(number, string)
    # do some more stuff
   end
  end

  # good
  module Utilities
   module_function

   def parse_something(string)
    # do stuff here
   end

   def other_utility_method(number, string)
    # do some more stuff
   end
  end

    防止在数组中开创巨大的间距。

    When designing class hierarchies make sure that they conform to the
    Liskov Substitution Principle.

  arr = []
  arr[100] = 1 # now you have an array with lots of nils

    在希图类档次的时候保险他们适合 Liskov Substitution Principle 原则。(译者注: LSP原则差不离意思为: 假设3个函数中援引了 父类的实例, 则一定能够动用其子类的实例代替, 并且函数的基本成效不改变. (就算效果允许被增添))

    当访问1个数组的首先个大概最终一个要素,倾向使用 first 或 last 而不是 [0] 或 [-1]。

        Liskov替换原则:子类型必须能够替换它们的基类型 <br/>
        一. 举个例子每三个项目为T一的指标o一,都有品种为T2的靶子o2,使得以T一定义的具有程序P在享有的对象o1都转移为o贰时,程序P的一坐一起尚未生成,那么类型T2是项目T一的子类型。 <br/>
        二. 换言之,三个软件实体即使接纳的是2个基类的话,那么早晚适用于其子类,而且它根本不能够察觉出基类对象和子类对象的差别。惟有衍生类替换基类的同不经常候软件实体的功效未有产生变化,基类技艺真的被复用。 <br/>
        叁. 里氏代换原则由Barbar Liskov(芭芭拉.里氏)建议,是连续复用的根本。 <br/>
        四. 一个连任是还是不是符合里氏代换原则,能够看清该持续是或不是创建(是还是不是隐身有瑕疵)。

    若是要保障元素唯1, 则使用 Set 代替 Array .Set 更合乎于无顺序的, 并且成分唯一的集合, 集合具有类似于数组1致性操作以及哈希的高速查找.

本文由韦德国际1946发布于韦德国际1946手机版,转载请注明出处:Ruby中编写类与模块的作风指南,Ruby中的会集编写

关键词: