OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Lecture 2
Object Oriented Programming in
Ruby
Aleksander Smywiński-Pohl
Elektroniczne Przetwarzanie Informacji
10 kwietnia 2013
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
The only constant thing in the World is change.
How to write change anticipating programs?
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
OOP techniques
I encapsulation
I abstraction
I delegation
I inheritance
I polymorphism
I dependency injection
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
OOP principles
I duplication avoidance
I single responsibility principle
I loose coupling
I high cohesion
I Law of Demeter
I and more . . .
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Encapsulation
Don’t expose the implementation details of the class to the
outside world.
I use accessors
I use protected and private methods
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Accessors
class Post describe Post do
attr_accessor :title subject { Post.new(title: "Ruby") }
end
context "default language" do
class Post it "shows its title in English" do
attr_writer :title subject.title.should == "Ruby"
def title end
translation(@title) end
end
end context "language set to Polish" do
it "shows its title in Polish" do
class Post subject.title.should == "Rubin"
def title end
translation(@title) end
end end
def title=(new_title)
@title = new_title
create_translations(new_title)
end
end Smywiński-Pohl
Aleksander EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Protected and private methods
class TodoList
def toggle_task(index)
raise IllegalArgument if index < 0 || index >= self.size
@list[index].completed = ! @list[index].completed
end
def remove_task(index)
raise IllegalArgument if index < 0 || index >= self.size
@list.delete(index)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Protected and private methods
class TodoList
def toggle_task(index)
check_index(index)
@list[index].completed = ! @list[index].completed
end
def remove_task(index)
check_index(index)
@list.delete(index)
end
protected
def check_index(index)
raise IllegalArgument if index < 0 || index >= self.size
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Rails pathology
# controller
def show
@post = Post.find(params[:id])
end
# view
<%= @post.title %>
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Alternative – Decent exposure
https://github.com/voxdolo/decent_exposure
# controller
class Controller
expose(:post)
def create
if post.save
redirect_to(post)
else
render :new
end
end
end
# view
<%= post.title %>
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Abstraction
Divide the system responsibilities into meaningful
abstractions.
I classes
I methods
I modules
I design patterns
I services
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Class abstraction
class TodoList
def completed?(index)
@task_status[index]
end
def toggle_task(index)
@task_status[index] = ! @task_status[index]
end
def task_name(index)
@tasks[index]
end
def <<(task_name)
@tasks << task_name
@task_status << false
end
def delete(index)
@tasks.delete(index)
@task_status.delete(index)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Class abstraction
class TodoList class Task
def completed?(index) attr_reader :name
@tasks[index].completed?
end def initialize(name)
def toggle_task(index) @name = name
@tasks[index].toggle @completed = false
end end
def task_name(index)
@tasks[index].name def completed?
end @completed
def <<(task_name) end
@tasks << Task.new(task_name)
end def toggle
def delete(index) @completed = ! @completed
@tasks.delete(index) end
end end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Method abstraction
# show.html.erb
<%= post.user.first_name + " " + post.user.last_name %>
# index.html.erb
<% posts.each do |post| %>
<%= post.user.first_name + " " + post.user.last_name %>
<% end %>
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Method abstraction
# show.html.erb
class User
<%= post.user.full_name %>
def full_name
self.first_name + " " +
# index.html.erb
self.last_name
<% posts.each do |post| %>
end
<%= post.user.full_name %>
end
<% end %>
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Module abstraction
module Comparable post1 = Post.new(pub_date: Time.now)
def <(other) post2 = Post.new(pub_date: 1.day.ago)
(self <=> other) < 0 post1 < post2 # => false
end
def >(other)
(self <=> other) > 0
end
end
class Post
include Comparable
def <=>(other)
self.pub_date <=> other.pub_date
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Controller – design pattern example
Controller is a common abstraction in applications with GUI. It
mediates between the View and the Business Model. It defines
actions that operate on the Model, which for the outside world
looks like cohesive resource. In fact it might use many model classes
to achieve this goal, but for the outside world it doesn’t matter.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Service abstraction
Service in SOA (Service Oriented Architecture) is a bunch of
controllers that are accessible from the outside, that provide some
cohesive set of features for the user of the service. E.g. the Wallet
application could define the following services:
I Wallet – buy and sell currencies and stocks
I Banker – define and manage your bank accounts
I Exchanger – define and manage stock exchanges
Services are defined from the end-user perspective. They are not
layers of the application (like DB service, computation service, etc.)
but they divided the application vertically.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Delegation means passing the message received by an object
to another object, that is more suitable for performing the
task.
It means that the class understands given message, but doesn’t
perform the work, that is associated with it. It helps in fulfilling the
Law of Demeter.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Manual delegation
class TodoList
def initialize
@items = []
end
def size
@itmes.size
end
def empty?
@items.empty?
end
def first
@items.first
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
SimpleDelegator
class Task require 'delegate'
attr_accessor :title, :completed
class TextFormatter < SimpleDelegator
def initialize(title) def formatted
@title = title state = self.completed? ? "x" : " "
@completed = false "[#{state}] #{self.title}"
end end
end
def completed?
self.completed task = Task.new("Buy toilet paper")
end task = TextFormatter.new(task)
task.formatted
def complete #=> "[ ] Buy toilet paper"
@completed = true task.title
end #=> "Buy toilet paper"
end task.completed?
#=> false
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Forwardable
require 'forwardable'
class TodoList
def_delegators :@items, :size, :empty?, :first, :last
def initialize(items=[])
@items = items
end
end
list = TodoList.new
list.size #=> delegates to @items.size
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
ActiveSupport Module extension
class TodoList
delegate :size, :empty?, :first, :last, :to => :@items
end
list = TodoList.new
list.size #=> @items.size
class Post < ActiveRecord::Base
belongs_to :user
delegate :name, :to => :user, :prefix => true, :allow_nil => true
end
user = User.new(name: "John")
post = Post.new(user: user)
post.user_name
#=> "John"
post = Post.new
post.user_name
#=> nil
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Inheritance allows for defining type hierarchies. Common
behavior is defined in more abstract (parent) classes, while
specific behavior in more concrete (children) classes.
Children share (by inheritance) the behavior defined in the parent
class.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Animal my_dog = Dog.new
def eat my_dog.eat
"kill some living" #=> "kill some living"
end my_dog.feed_children
end #=> "use breast"
my_dog.make_sound
class Mammal < Animal #=> "bark"
def feed_children
"use breast" my_cat = Cat.new
end my_cat.eat
end #=> "kill some living"
my_cat.feed_children
class Dog < Mammal #=> "use breast"
def make_sound my_cat.make_sound
"bark" #=> "meow"
end
end
class Cat < Mammal
def make_sound
"meow"
end
end Smywiński-Pohl
Aleksander EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Measure
# Initialize the measure with +value+ and +scale+.
def initialize(value,scale)
@value = value
@scale = scale
end
# Default string representation of the measure.
def to_s
"%.2f %s" % [@value, @scale]
end
end
class Temperature < Measure
# Converts the temeperature to Kelvin scale.
def to_kelvin
Temperature.new(convert(@scale,:k,@value),:k)
end
end
temperature = Temperature.new(10,:c)
puts temperature.to_kelvin.to_s #=> 283.15 k
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
ActiveRecord::Base
class Post < ActiveRecord::Base
# attributes title, body
belongs_to :user
end
post = Post.new(:title => "Title", :body => "Some text")
post.title # => "Title"
post.body # => "Some text"
post.user # => nil
post.save
post.destroy
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Task task = FormattedTask.
def initialize(name,description) new("Tesco","Buy toilet paper")
@name = name
@description = description task.to_s
@completed = false # [ ] Tesco
end # or
# [ ] Tesco: Buy toilet paper
def to_s
@name
end
# or
def to_s
"#{@name}: #{@description[0..30]}"
end
end
class FormattedTask < Task
def to_s
state = @completed ? "x" : " "
"[#{state}] #{super}"
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Polymorphism
Polymophism is the property of objects, allowing them to
respond differently for the same message, depending on their
type.
In Ruby you will often hear the term duck-typing: if something
walks like a duck and quacks like a duck it is treated as if it was a
duck.
In Ruby polymorphism doesn’t require inheritance.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Duck typing example
def print_collection(collection)
collection.each do |element|
puts "- #{element}"
end
end
print_collection([1,3,5])
# - 1
# - 3
# - 5
print_collection(1..3)
# - 1
# - 2
# - 3
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Figure apple = Apple.new(0,0)
attr_accessor :x, :y snake = Sname.new(10,0)
def initialize(x,y) objects = [apple,snake]
@x, @y = x, y
end loop do
def move(x_delta,y_delta) snake.move(1,0)
@x += x_delta objects.each do |object|
@y += y_delta object.draw
end end
end end
def Apple < Figure
def draw
puts "*"
end
end
def Snake < Figure
def draw
puts "----->"
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Dependency Injection
Dependency injection allows for replacing the dependencies
of the class with their alternatives during compilation or at
run time.
It removes all hard-coded cooperators of the class.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Dependency example
class TodoList
def initalize
@items = []
end
def <<(name)
@items << Task.new(name)
end
end
Task is a global (name), which can’t be replaced. It is a
hard-coded dependency of TodoList.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Dependency removal
class TodoList
def initialize(options={})
@items = []
@task_factory = options[:task_factory] || Task
end
def <<(name)
@items << @task_factory.new(name)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Alternative dependency
require_relative 'spec_helper'
require_relative '../../lib/todo_list'
stub_class 'Task'
describe TodoList do
subject(:list) { TodoList.new(:task_factory => task_factory) }
let(:task_factory) { stub!.new(task_name) { task }.subject }
let(:task_name) { "Buy toilet paper" }
let(:task) { Struct.new(:title,:completed).(task_name,false) }
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Dependency setter
class TodoList
attr_writer :task_source
def initalize
@items = []
end
def <<(name)
@items << task_source.call(name)
end
private
def task_source
@task_source ||= Task.public_method(:new)
end
end
list = TodoList.new
fake_task_class = Struct.new(:title)
list.task_source = fake_task_class.public_method(:new)
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Default dependency
class Post
def publish(clock=DateTime)
self.pub_date = clock.now
# ...
end
end
class FixedClock
def initialize(date)
@date = date
end
def now
DateTime.parse(@date)
end
end
class DeleyedClock
def now
DateTime.now + 24.hours
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Duplication avoidance
Every piece of knowledge must have a single, unambiguous,
authoritative representation within a system. Wikipedia
It is called DRY – Don’t repeat yourself.
This applies both to data and processing.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
DRY data
DB normalization – removal of duplicated data
name price price + VAT VAT VAT rate
starter 10 12.30 2.30 23
vegetarian dish 20 24.60 4.60 23
main dish 25 31.90 6.90 23
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
DRY data
id VAT rate
name price VAT rate id 1 23
starter 10 1 2 5
vegetarian dish 20 1 3 0
main dish 25 1
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
DRY code
class TodoList
def toggle_task(index)
raise IllegalArgument if index < 0 || index >= self.size
@list[index].completed = ! @list[index].completed
end
def remove_task(index)
raise IllegalArgument if index < 0 || index >= self.size
@list.delete(index)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
DRY code
class TodoList
def toggle_task(index)
check_index(index)
@list[index].completed = ! @list[index].completed
end
def remove_task(index)
check_index(index)
@list.delete(index)
end
protected
def check_index(index)
raise IllegalArgument if index < 0 || index >= self.size
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Single Responsibility Principle
Single responsibility principle states that every class should
have a single responsibility, and that responsibility should be
entirely encapsulated by the class. Wikipedia
Responsibility is understood as a reason for change.
Robert C. Martin.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Product
# Creates new product by parsing the XML
# representation of the product found
# under the +url+.
def self.import(url)
end
# Stores the product in local database.
def save
end
# Converts the product to HTML representation.
def render(context)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Responsibilites of the Product class
What can change?
I the organization and format of the imported file
e.g. individual files might be replaced with aggregated
documents
I the database used to store the product
e.g. a relational DB might be replaced with document-based
one
I the presentation of the product
e.g. HTML might be replaced with JSON
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class ProductParser
# Parses the product definition and
# returns a struct containing the product
# name and price.
def parse(url)
end
end
class Product
# Stores the product in the database.
def save
end
end
class ProductPresenter
# Renders the product as a list item.
def render(context)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class TodoList
def completed?(index)
@task_status[index]
end
def toggle_task(index)
@task_status[index] = ! @task_status[index]
end
def task_name(index)
@tasks[index]
end
def <<(task_name)
@tasks << task_name
@task_status << false
end
def delete(index)
@tasks.delete(index)
@task_status.delete(index)
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Responsibilities of the TodoList class
What can change?
I how the list is persisted – in memory vs. via database
I task lifecycle – e.g. three states: fresh, in progress, finished
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class TodoList class Task
def [](index) attr_reader :name
@task[index]
end def initialize(name)
@name = name
def <<(task_name) @completed = false
@tasks << Task.new(task_name) end
end
def completed?
def delete(index) @completed
@tasks.delete(index) end
end
end def toggle
@completed = ! @completed
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
High cohesion
Cohesion is a measure of how strongly-related or focused the
responsibilities of a single module are. As applied to
object-oriented programming, if the methods that serve the
given class tend to be similar in many aspects, then the class
is said to have high cohesion. Wikipedia
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Loose coupling
A loosely coupled system is one in which each of its
components has, or makes use of, little or no knowledge of
the definitions of other separate components. Wikipedia
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Law of Demeter
For all classes C and for all methods M attached to C, all
objects to which M sends a message must be instances of
classes associated with the following classes:
I The argument classes of M (including C).
I The instance variable classes of C.
Objects created by M, or by functions or methods which M
calls, and objects in global variables are considered as
arguments of M.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Law of Demeter – pragmatic formulation
I Your method can call other methods in its class directly.
I Your method can call methods on its own fields directly (but
not on the fields’ fields).
I When your method takes parameters, your method can call
methods on those parameters directly.
I When your method creates local objects, that method can call
methods on the local objects.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Example
class Post < ActiveRecord::Base
belongs_to :user
def user_full_name
user.profiles.first.personal_data.full_name
end
end
Classes used in user_full_name:
I User
I Profile
I PersonalData
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
class Post < ActiveRecord::Base class User < ActiveRecord::Base
belongs_to :user has_many :posts
has_many :profiles
def user_full_name
user.full_name def full_name
end self.personal_data.full_name
end end
Only User class is used – it’s ok, def personal_data
since the object is returned by self.default_profile.personal_data
end
Post’s own method.
def default_profile
self.profiles.first
end
end
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
What about this?
def format(line)
line.chomp.strip.capitalize
end
It’s ok, since we only have one class – String. line, the method
parameter, is an instance of String.
LoD is more than dot counting.
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
Agenda
Principles of Object Oriented Programming
Encapsulation
Abstraction
Delegation
Inheritance
Polymorphism
Dependency Injection
Principles
References
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
References
I Object Oriented Software Construction, Bertrand Meyer
I Growing Object-Oriented Software, Guided by Tests, Steve
Freeman
I Clean code: A Handbook of Agile Software Craftsmanship,
Robert C. Martin
I Design Patterns: Elements of Reusable Object-Oriented
Software, Erich Gamma, Richard Helm, Ralph Johnson, John
Vlissides
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby
OOP Encapsulation Abstraction Delegation Inheritance Polymorphism DI Principles References
References
I Objects on Rails, Avdi Grimm
I Refactoring: Ruby Edition, Jay Fields, Shane Harvie, Martin
Fowler, Kent Beck
I Refactoring in Ruby, William C. Wake, Kevin Rutherford
I Law of Demeter, Avdi Grimm’s blog
Aleksander Smywiński-Pohl EPI
Lecture 2: OOP in Ruby