Ruby類繼承、抽象類、類拓展混入、代理類實例
總結(jié)一下工作中遇到的類擴(kuò)展:
1、類繼承:
當(dāng)多個類公用很多方法的時候可以將公用方法部分抽取出來,需要的類做相關(guān)繼承。
例子:
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、抽象類
當(dāng)多個類要繼承一個類時,用第一種方法,會遇到一個問題。
(引用一個別人的注解來描述抽象類的運用吧https://ihower.tw/rails4/activerecord-others.html)
單一表格繼承STI(Single-table inheritance)
如何將物件導(dǎo)向中的繼承概念,對應(yīng)到關(guān)聯(lián)式資料庫的設(shè)計,是個大哉問。Rails內(nèi)建了其中最簡單的一個解法,只用一個資料表儲存繼承體系中的物件,搭配一個type欄位用來指名這筆資料的類別名稱。
要開啟STI功能,依照慣例只要有一個欄位叫做type,型態(tài)字串即可。假設(shè)以下的posts資料表有欄位叫做type,那麼這三個Models實際上就會共用posts一個資料表,當(dāng)然,還有這兩個子類別也都繼承到父類別的validates_presence_of :subject:
class Post < ActiveRecord::Base
validates_presence_of :subject
end
class GuestPost < Post
end
class MemberPost < Post
end
讓我們進(jìn)入rails console實驗看看,Rails會根據(jù)你使用的類別,自動去設(shè)定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
很遺憾,也因為這個慣例的關(guān)係,你不能將type這麼名字挪做它用。
STI最大的問題在於欄位的浪費,如果繼承體系中交集的欄位不多,那麼使用STI就會非常的浪費空間。如果有較多的不共用的欄位,筆者會建議不要使用這個功能,讓個別的類別有自己的資料表。要關(guān)閉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的類是單繼承的,要實現(xiàn)多繼承的功能需要用mixin(參合模式)的方式,即類拓展混入來實現(xiàn)。例子:
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、代理類
當(dāng)某個功能是比較復(fù)雜的,當(dāng)然寫再lib中,作為一個面向函數(shù)的方法去處理很簡單,也可以用代理類的方式實現(xiàn)面向?qū)ο蟮恼{(diào)用。
例子:
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內(nèi)容的具體定義
end
end
end
A.new.generate_schedule 就可以通過代理類ExcelGenerator實現(xiàn)一個A的類實例方法generate_schedule
當(dāng)然也可以通過include 一個model的方式實現(xiàn)添加類實例方法,有時候也可以混合使用。另外使用代理類的好處在于多個類都需要相同方法的時候可以定義共同的部分,舉一個發(fā)郵件的例子:
class A<ActiveRecord::Base
include SendEmail
end
class B<ActiveRecord::Base
include SendEmail
end
實現(xiàn)引入模塊:
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
實現(xiàn)代理類:
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標(biāo)題" )
end
send("#{obj.state}").deliver
#根據(jù)不同對象obj.state得到不同狀態(tài)下,定義不同方法,然后send派發(fā)調(diào)用相關(guān)對象狀態(tài)的模板。
end
end
RUBY很靈活當(dāng)然還有很多其他的方法實現(xiàn)更多的方式,以后再慢慢總結(jié)。
相關(guān)文章
對Ruby on Rails進(jìn)行高效的單元測試的教程
這篇文章主要介紹了在Ruby on Rails中進(jìn)行高效的單元測試的教程,使用到了Ruby的RSpec和Factory Girl框架,需要的朋友可以參考下2015-04-04利用RJB在Ruby on Rails中使用Java代碼的教程
這篇文章主要介紹了利用RJB在Ruby on Rails中使用Java代碼的教程,本文來自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下2015-04-04Ruby使用C++擴(kuò)展實例(含C++擴(kuò)展代碼示例)
這篇文章主要介紹了Ruby使用C++擴(kuò)展實例,含C++擴(kuò)展實現(xiàn)代碼,本文可作為Ruby中使用C++擴(kuò)展的入門教程,需要的朋友可以參考下2014-09-09