Ruby类继承、抽象类、类拓展混入、代理类实例_ruby专题

总结一下工作中遇到的类扩展:

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很灵活当然还有很多其他的方法实现更多的方式,以后再慢慢总结。

时间: 2024-09-20 18:04:15

Ruby类继承、抽象类、类拓展混入、代理类实例_ruby专题的相关文章

Ruby设计模式编程中使用Builder建造者模式的实例_ruby专题

先来复习一下设计模式的基本概念:定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要重新定一个建造者就可以了.实用范围1.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 2.当构造过程必须允许被构造的对象有不同表示时.角色在这样的设计模式中,有以下几个角色: 1.builder:为创建一个产品对象的各个部件指定抽象接口. 2.ConcreteBuilder:实现Builder

使用Ruby on Rails快速开发web应用的教程实例_ruby专题

 Ruby on Rails 正在令整个 Web 开发领域受到震憾.让我们首先了解底层的技术:     Ruby 是一门免费的.简单的.直观的.可扩展的.可移植的.解释的脚本语言,用于快速而简单的面向对象编程.类似于 Perl,它支持 处理文本文件和执行系统管理任务的很多特性.     Rails 是用 Ruby 编写的一款完整的.开放源代码的 Web 框架,目的是使用更简单而且更少的代码编写实际使用的应用程序. 作为一个完整的框架,这意味着 Rails 中的所有的层都是为协同工作而构造的,所以

Ruby连接使用windows下sql server数据库代码实例_ruby专题

require 'win32ole' class SqlServer # This class manages database connection and queries attr_accessor :connection, :data, :fields def initialize @connection = nil @data = nil end def open # Open ADO connection to the SQL Server database connection_st

Ruby使用设计模式中的代理模式与装饰模式的代码实例_ruby专题

代理模式 需求: 小明让小李替他追小丽(送洋娃娃,送花,送巧克力) 没有代理的代码: # -*- encoding: utf-8 -*- #追求者类 class Pursuit attr_accessor :mm def initialize(mm) @mm = mm end def give_dolls puts "#{mm.name} 送你洋娃娃" end def give_flowers puts "#{mm.name} 送你鲜花" end def give_

介绍Ruby中的模块与混合类型的相关知识_ruby专题

模块是组合在一起的方法,类和常量.模块两个主要好处:     模块提供了一个命名空间,并避免名称冲突.     模块实现混合工厂. 模块定义了一个命名空间,一个沙箱中方法和常量可以自由使用,而不必担心踩到其他的方法和常数. 语法: module Identifier statement1 statement2 ........... end 就像被命名为类常量模块中的常量,首字母大写.定义的方法看起来很相似,模块定义方法就像类的方法. 调用一个模块方法和类方法一样,通过模块的名称它名字前,引用一

Ruby优化继承类实例_ruby专题

在Rails的原则里有简化Controller,丰富Model的说法.下面将用一个示例展示一个简单的继承优化.特别是你的method里有一个写变化的self变量的时候. 假设我们有如下的Model 复制代码 代码如下: class SubjectMatterExpert < User   include HashCodeCreatorModule   def make_activation_code     self.deleted_at = nil     self.activation_co

实例讲解Ruby使用设计模式中的装饰器模式的方法_ruby专题

概述       若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一  个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类-这建立在额外的代码上.       通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是静态的,用户不能控制增加行为的方式和时机.如果  你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只

深入剖析Ruby设计模式编程中对命令模式的相关使用_ruby专题

命令模式是对象行为型使用率比较高的设计模式,别名:Action(动作),Transaction(事务) 意图: 将一个请求封装为一个对象,从而使你可对不同的请求进行参数化:对请求排队或记录请求日志,以及支持可取消的操作 这里所谓的"不同的请求"也既意味着请求可能发生的变化,是一个可能扩展的功能点. 动机: 方便扩展 结构: 协作说明:    参与角色:     Command 声明一个接口以用来实现某个操作.     ConcreteCommand 将动作与Reciver对外绑定,通过

Ruby中使用SWIG编写ruby扩展模块实例_ruby专题

在使用ruby/rails的过程中,确实发现有时性能不尽人意,如生成一个拥有600项的item的3层树形结构目录要花去20ms,为提高性能在学习用c/c++写ruby模块的过程中,认识了swig,rubyInline等一系列帮助编写c/c++来提升ruby性能的辅助工具. rubyInline用于内嵌c/c++程序,简单快捷,swig则帮助我们更容易地用c/c++写出独立的ruby模块. swig的入门使用方法 目标:用swig/c++编写一个ruby模块Test,并提供add方法作加法运算.