類別

2018-02-24 16:11 更新
  • 在類別定義里使用一致的結(jié)構(gòu)。

    class Person
      # 首先是 extend 與 include
      extend SomeModule
      include AnotherModule
    
      # 接著是常量
      SOME_CONSTANT = 20
    
      # 接下來是屬性宏
      attr_reader :name
    
      # 跟著是其它的宏(如果有的話)
      validates :name
    
      # 公開的類別方法接在下一行
      def self.some_method
      end
    
      # 初始化方法在類方法和實(shí)例方法之間
      def initialize
      end
    
      # 跟著是公開的實(shí)例方法
      def some_method
      end
    
      # 受保護(hù)及私有的方法,一起放在接近結(jié)尾的地方
      protected
    
      def some_protected_method
      end
    
      private
    
      def some_private_method
      end
    end
  • 如果某個(gè)類需要多行代碼,則不要嵌套在其它類中。應(yīng)將其獨(dú)立寫在文件中,存放以包含它的類的的名字命名的文件夾中。

    # 差
    
    # foo.rb
    class Foo
      class Bar
        # 30個(gè)方法
      end
    
      class Car
        # 20個(gè)方法
      end
    
      # 30個(gè)方法
    end
    
    # 好
    
    # foo.rb
    class Foo
      # 30個(gè)方法
    end
    
    # foo/bar.rb
    class Foo
      class Bar
        # 30個(gè)方法
      end
    end
    
    # foo/car.rb
    class Foo
      class Car
        # 20個(gè)方法
      end
    end
  • 傾向使用模塊,而不是只有類別方法的類。類別應(yīng)該只在產(chǎn)生實(shí)例是合理的時(shí)候使用。

    # 差
    class SomeClass
      def self.some_method
        # 省略函數(shù)體
      end
    
      def self.some_other_method
      end
    end
    
    # 好
    module SomeClass
      module_function
    
      def some_method
        # 省略函數(shù)體
      end
    
      def some_other_method
      end
    end
  • 當(dāng)你想將模塊的實(shí)例方法變成類別方法時(shí),偏愛使用?module_function?勝過?extend self

    # 差
    module Utilities
      extend self
    
      def parse_something(string)
        # 做一些事
      end
    
      def other_utility_method(number, string)
        # 做另一些事
      end
    end
    
    # 好
    module Utilities
      module_function
    
      def parse_something(string)
        # 做一些事
      end
    
      def other_utility_method(number, string)
        # 做另一些事
      end
    end
  • 當(dāng)設(shè)計(jì)類型層級時(shí),確認(rèn)它們符合?Liskov 替換原則。

  • 盡可能讓你的類型越?SOLID?越好。
  • 永遠(yuǎn)替類型提供一個(gè)適當(dāng)?shù)?to_s?方法給來表示領(lǐng)域模型。

    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?系列函數(shù)來定義瑣碎的訪問器或 mutators。

    # 差
    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
    
    # 好
    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。

    # 差 - ruby 1.9 中就不推薦了
    attr :something, true
    attr :one, :two, :three # behaves as attr_reader
    
    # 好
    attr_accessor :something
    attr_reader :one, :two, :three
  • 考慮使用?Struct.new,它替你定義了那些瑣碎的訪問器(accessors),構(gòu)造器(constructor)以及比較操作符(comparison operators)。

    # 好
    class Person
      attr_reader :first_name, :last_name
    
      def initialize(first_name, last_name)
        @first_name = first_name
        @last_name = last_name
      end
    end
    
    # 更好
    Person = Struct.new(:first_name, :last_name) do
    end
  • 不要擴(kuò)展?Struct.new。它已經(jīng)是個(gè)類了。對它擴(kuò)展不但引入了無意義的類的層次也會在該文件多次被require時(shí)出現(xiàn)奇怪的錯(cuò)誤。

  • 考慮加入工廠方法以提供附加的有意義的方式來生成一個(gè)特定的類實(shí)例。

    class Person
      def self.create(options_hash)
        # body omitted
      end
    end
  • 傾向使用鴨子類型?而不是繼承。

    ## 差
    class Animal
      # 抽象方法
      def speak
      end
    end
    
    # 繼承超類
    class Duck < Animal
      def speak
        puts 'Quack! Quack'
      end
    end
    
    # 繼承超類
    class Dog < Animal
      def speak
        puts 'Bau! Bau!'
      end
    end
    
    ## 好
    class Duck
      def speak
        puts 'Quack! Quack'
      end
    end
    
    class Dog
      def speak
        puts 'Bau! Bau!'
      end
    end
  • 由于類變量在繼承中產(chǎn)生的“討厭的”行為,避免使用類變量(@@)。

    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"

    如同你所看到的,在類型層級中的所有類其實(shí)都共享單獨(dú)一個(gè)類變量。通常情況下應(yīng)該傾向使用實(shí)例變量而不是類變量。

  • 依據(jù)方法的目的用途指定適當(dāng)?shù)目梢妼蛹墸?code>private,protected)。別把所有方法都設(shè)為?public(方法的缺省值)。我們現(xiàn)在是在寫“Ruby”,不是“Python”。

  • 將?public,protectedprivate?和被應(yīng)用的方法定義保持一致的縮排。在上下各留一行來強(qiáng)調(diào)這個(gè)可見性應(yīng)用于之后的所有方法。

    class SomeClass
      def public_method
        # ...
      end
    
      private
    
      def private_method
        # ...
      end
    
      def another_private_method
        # ...
      end
    end
  • 使用?def self.method?來定義方法。在代碼重構(gòu)時(shí)如果修改類名也無需重復(fù)多次修改了。

    class TestClass
      # 差
      def TestClass.some_method
        # 省略方法體
      end
    
      # 好
      def self.some_other_method
        # 省略方法體
      end
    
      # 當(dāng)你需要定義很多個(gè)類時(shí),另一種便捷的方式
      class << self
        def first_method
          # 省略方法體
        end
    
        def second_method_etc
          # 省略方法體
        end
      end
    end
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號