代码整洁之道——程序员的职业素养
很难想象我在读这本书的时候是除夕的晚上,早晨在公司的书架上无疑翻到这本书,读了几个章节就被深深的吸引住了, 吸引我的并不是我很迫切的需要提高自己的职业素养,而是发现作者描述的场景和自己碰到的情况何其的相似,在某些 情况下甚至是直击内心的。在家人都休息的时候,我在深夜一点钟看完了这本书,而且我觉得有必要做一下笔记,...
原文链接:back-to-basics-polymorphism-and-ruby
多态是面向对象编程最基本的特征之一,但是它到底是什么意思?就其核心而言,对于 Ruby,可以发送相同的消息 给不同的对象,然后得到不同的结果。让我们来看看 Ruby 实现多态的几种方式。
实现多态的其中一种方式就是继承。我们用模版方法创建一个简单的文件解析器。
首先我们创建一个带有 parse 方法的 GenericParser 类,这个模版类的唯一的方法做的事情的就是抛出一个异常:
class GenericParser
def parse
raise NotImplementedError, 'You must implement the parse method'
end
end
然后我们声明一个继承 GenericParser 类的 JsonParser 类:
class JsonParser < GenericParser
def parse
puts 'An instance of the JsonParser class received the parse message'
end
end
再创建一个继承 GenericParser 类的 XmlParser 类:
class XmlParser < GenericParser
def parse
puts 'An instance of the XmlParser class received the parse message'
end
end
然后运行一个脚本,看看发生了什么:
puts 'Using the XmlParser'
parser = XmlParser.new
parser.parse
puts 'Using the JsonParser'
parser = JsonParser.new
parser.parse
输出结果:
Using the XmlParser
An instance of the XmlParser class received the parse message
Using the JsonParser
An instance of the JsonParser class received the parse message
我们注意到代码行为的不同依赖于子类接收的 parse 方法。 XML 和 JSON 解析器修改了 GenericParser 的行为。
对于静态类型语言,运行时多态(runtime polymorphism)更难以实现。幸运的是,Ruby 可以使用鸭子类型。
我们再次以 XML 和 JSON 解析器为例,去掉继承:
class XmlParser
def parse
puts 'An instance of the XmlParser class received the parse message'
end
end
class JsonParser
def parse
puts 'An instance of the JsonParser class received the parse message'
end
end
现在我们创建一个通用解析器,它可以发送 parse 消息,并且接收一个参数。
class GenericParser
def parse(parser)
parser.parse
end
end
现在我们有一个非常棒的鸭子类型的例子。注意,parse 方法接收一个叫 parser 的变量。此工作所需的唯一事情就是让解析器对象响应解析消息, 幸运的是我们两解析器都可以那样做!
parser = GenericParser.new
puts 'Using the XmlParser'
parser.parse(XmlParser.new)
puts 'Using the JsonParser'
parser.parse(JsonParser.new)
输出结果:
Using the XmlParser
An instance of the XmlParser class received the parse message
Using the JsonParser
An instance of the JsonParser class received the parse message
我们注意到方法行为的不同依赖于对象接收的消息。这就是多态!
我们也可以通过设计模式的使用来实现多态。让我们看一个装饰模式的例子:
class Parser
def parse
puts 'The Parser class received the parse method'
end
end
我们需要修改 XmlParser 类,让它包含一个带有解析器参数的构造方法。
class XmlParser
def initialize(parser)
@parser = parser
end
def parse
@parser.parse
puts 'An instance of the XmlParser class received the parse message'
end
end
对 JsonParser 做相同的修改:
class JsonParser
def initialize(parser)
@parser = parser
end
def parse
puts 'An instance of the JsonParser class received the parse message'
@parser.parse
end
end
我们将使用装饰者去创建普通的 XML 和 JSON 解析器,但是在最后一个例子中,我们做的会有一点不同: 都使用装饰者实现运行时多态:
puts 'Using the XmlParser'
parser = Parser.new
XmlParser.new(parser).parse
puts 'Using the JsonParser'
JsonParser.new(parser).parse
puts 'Using both Parsers!'
JsonParser.new(XmlParser.new(parser)).parse
输出结果:
Using the XmlParser
The Parser class received the parse method
An instance of the XmlParser class received the parse message
Using the JsonParser
An instance of the JsonParser class received the parse message
The Parser class received the parse method
Using both Parsers!
An instance of the JsonParser class received the parse message
The Parser class received the parse method
An instance of the XmlParser class received the parse message
多态的其中一个优点是可以简化代码。看看下面的类:
class Parser
def parse(type)
puts 'The Parser class received the parse method'
if type == :xml
puts 'An instance of the XmlParser class received the parse message'
elsif type == :json
puts 'An instance of the JsonParser class received the parse message'
end
end
end
由于鸭子类型的优势,我们可以通过移除条件分支逻辑来简化代码。现在我们把特定的解析逻辑放在它们各自的 类当中:
class Parser
def parse(parser)
puts 'The Parser class received the parse method'
parser.parse
end
end
class XmlParser
def parse
puts 'An instance of the XmlParser class received the parse message'
end
end
class JsonParser
def parse
puts 'An instance of the JsonParser class received the parse message'
end
end
这个例子表明:我们可以利用多态简化代码,同时也符合单一责任原则(Single Responsibility Principle)
在最初的版本中,Parser 类决定使用哪一个解析器,通过实例化去初始化解析器,然后发送解析消息给对象。之后的例子中, 在最初的版本中,Parser 类只需要调用 parse 方法触发解析过程。
多态是面向对象编程的基础之一,但是也容易让人感到疑惑。花时间去理解它可以帮助你写出更有扩展性和维护性的代码。
很难想象我在读这本书的时候是除夕的晚上,早晨在公司的书架上无疑翻到这本书,读了几个章节就被深深的吸引住了, 吸引我的并不是我很迫切的需要提高自己的职业素养,而是发现作者描述的场景和自己碰到的情况何其的相似,在某些 情况下甚至是直击内心的。在家人都休息的时候,我在深夜一点钟看完了这本书,而且我觉得有必要做一下笔记,...
概览
rails 中的循环依赖
最近项目上遇到一个问题,某个 http 请求会返回 413 的状态码,一般来讲,这个问题是很好解决的, 网上有非常多的解决方案,但是我依然花了很长的时间找到问题根源,所以我觉得可以把这个过程记录下来。
什么是 WebSocket?
docker-elk Git repo
远程登录到 mongodb 实例
mongodb 创建索引和查询需要遵循的原则
一、默认添加 Mongoid::Timestamps
1. response out of time limit or subscription is canceled hint: (45015)
1. How to kill slow query?
领域驱动设计——软件核心复杂性应对之道
AppID、redirect_uri 参数错误
分布式的实时消息平台
Cassandra 在 Discord 中的应用
类和对象
基本数据结构和控制结构
使用 supervisor 管理进程
celery 的安装,配置及使用
更改tmux默认快捷键
使用 Vagrant 构建虚拟开发环境
寻找 python 和 ruby 的不同之处
使用 jQuery 实现自动补全功能
Rails 源码解读
实现软删除(soft delete)功能
使用 StackOverflow 帐户登录应用
使用 turbolinks 实现网页进度条
使用 GitHub 帐户登录应用
在 Rails 中使用 Ajax
收藏功能的实现
使用 gravatar 生成用户头像
支持 Markdown 语法和代码高亮
实现简单的搜索功能
在应用中使用 Bootstrap
实现简单的用户访问权限控制功能
rails
分页功能的实现
添加用户注册和登录功能
简单介绍如何在 Rails 项目中使用 MongoDB 及模型之间的关联
Rails 源码解读
List, Set, Map
java
方法覆盖和方法重载
内部类,局部内部类,匿名内部类,静态嵌套类
static, abstract, final
介绍 Ruby 多态的实现方式
包括访问权限, mixin, code load 等
Blocks,Procs 和 Lambdas 是 Ruby 最强有力的武器,也最难理解
Capistrano 是 Rails App 最常用的自动化部署工具,本篇文章将介绍 Capistrano 3的安装及配置
rails
java
ruby
rspec
git 常见操作
使用事务过程中常见的错误和解决方案
理解 go 语言中的 interface
golang
golang
Rails 虽然易于使用,但也很容易被滥用。本文聚焦于10个最常见的 Rails 陷进,并指导你如何避免它们以及由它们引发的问题
Uniqueness Validation
异常处理
mysql 常见操作
linux
冒泡排序,快速排序,希尔排序
sublime
你不会学到任何与 Ruby 相关的编程技巧,但你可以更好的理解垃圾回收器是如何工作的
总结了自己在工作中和 stackoverflow 上学到的一些很有用的方法
Active Record, mysql2