Ruby類繼承、抽象類別、類拓展混入、代理類執行個體_ruby專題

來源:互聯網
上載者:User

總結一下工作中遇到的類擴充:

1、類繼承:

當多個類公用很多方法的時候可以將公用方法部分抽取出來,需要的類做相關繼承。

例子:

複製代碼 代碼如下:

class A < ActiveRecord::Base
    def a
        p "it was a "
    end
end

class B<A
end

class C<A
end

B.new.a #=>"it was a "
C.new.a #=>"it was a "

2、抽象類別

當多個類要繼承一個類時,用第一種方法,會遇到一個問題。
(引用一個別人的註解來描述抽象類別的運用吧https://ihower.tw/rails4/activerecord-others.html)

單一表格繼承STI(Single-table inheritance)

如何將物件導向中的繼承概念,對應到關聯式資料庫的設計,是個大哉問。Rails內建了其中最簡單的一個解法,只用一個資料表儲存繼承體系中的物件,搭配一個type欄位用來指名這筆資料的類別名稱。

要開啟STI功能,依照慣例只要有一個欄位叫做type,型態字串即可。假設以下的posts資料表有欄位叫做type,那麼這三個Models實際上就會共用posts一個資料表,當然,還有這兩個子類別也都繼承到父類別的validates_presence_of :subject:

複製代碼 代碼如下:

class Post < ActiveRecord::Base 
    validates_presence_of :subject 
end 
 
class GuestPost < Post 
end 
 
class MemberPost < Post 
end 

讓我們進入rails console實驗看看,Rails會根據你使用的類別,自動去設定type欄位:

複製代碼 代碼如下:

post = GuestPost.create( :subject => "guest")
post.type # "GuestPost"
post.id # 1
post = MemberPost.create( :subject => "member" )
post.id # 2
post.type # "MemberPost"
GuestPost.last # 1

很遺憾,也因為這個慣例的關係,你不能將type這麼名字挪做它用。
STI最大的問題在於欄位的浪費,如果繼承體系中交集的欄位不多,那麼使用STI就會非常的浪費空間。如果有較多的不共用的欄位,筆者會建議不要使用這個功能,讓個別的類別有自己的資料表。要關閉STI,請父類別加上self.abstract_class = true

複製代碼 代碼如下:

class Post < ActiveRecord::Base 
    self.abstract_class = true 
end 
 
class GuestPost < Post 
end 
 
class MemberPost < Post 
end 

這裡的GuestPost和MemberPost就需要有自己的Migrations建立guest_posts和member_posts資料表。

你還可以在某個類中,引入多個依賴

複製代碼 代碼如下:

class Dependency<Post 
    require_dependency 'guestpost' 
    require_dependency 'memberpost' 
end 

3、類拓展混入

ruby的類是單繼承的,要實現多繼承的功能需要用mixin(參合模式)的方式,即類拓展混入來實現。例子:

複製代碼 代碼如下:

module Extract 
  def self.included(base) 
     base.extend(ClassMethods) 
  end 
  module ClassMethods 
     def a 
        p "it was a " 
     end 
  end 
end   
 
class A<ActiveRecord::Base 
  include Extract 
end 
 
A.new.a  #=>"it was a" 

4、代理類

當某個功能是比較複雜的,當然寫再lib中,作為一個面向函數的方法去處理很簡單,也可以用代理類的方式實現物件導向的調用。

例子:

複製代碼 代碼如下:

class A<ActiveRecord::Base
 def generate_schedule
    generator =  Generator::ExcelGenerator.new(self)
    generator.generate_schedule
  end
end

module Generator
  class ExcelGenerator

    attr_reader :excel,:workbook,:a,:worksheet
    attr_accessor :styles

    def initialize(a)
      @excel ||= Axlsx::Package.new
      @workbook ||= @excel.workbook
      @worksheet = @workbook.add_worksheet(:name => '測試產生一個excel檔案')
      @a ||= a
      @styles ||= Hash.new
    end
   
    def generate_schedule
        #excel內容的具體定義
    end

  end
end

A.new.generate_schedule 就可以通過代理類ExcelGenerator實現一個A的類執行個體方法generate_schedule

當然也可以通過include 一個model的方式實現添加類執行個體方法,有時候也可以混合使用。另外使用代理類的好處在於多個類都需要相同方法的時候可以定義共同的部分,舉一個發郵件的例子:

複製代碼 代碼如下:

class A<ActiveRecord::Base
    include SendEmail
end

class B<ActiveRecord::Base
    include SendEmail
end

實現引入模組:

複製代碼 代碼如下:

module SendEmail
    #include this module to class::A and B
    #use like that--  A.first.send_email
    def send_email
      Email.call_email(self)
    end
end

實現代理類:

複製代碼 代碼如下:

class Email < ActionMailer::Base
  default :from => "test@email.com"

  def self.call_email(obj)
     define_method "#{obj.state}" do |obj|
       @obj = obj
       mail(:to => @obj.email, :subject => "XX標題" )
     end
     send("#{obj.state}").deliver
     #根據不同對象obj.state得到不同狀態下,定義不同方法,然後send派發調用相關對象狀態的模板。
  end
    
end

RUBY很靈活當然還有很多其他的方法實現更多的方式,以後再慢慢總結。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.