Exhibits and Presenters

Post on 24-May-2015

158 views 1 download

Tags:

description

Briefly about Decorator, Exhibits and Presenter Patterns

Transcript of Exhibits and Presenters

@AtifTweets

Exhibits and Presenters

@AtifTweets

Agenda

• Decorators• Exhibits• Presenters

@AtifTweets

Decorators

PresentersExhibits

@AtifTweets

Decorators

“Decorators attach additional responsibilities to an object dynamically. They provide a flexible alternative to subclassing for extending functionality.” - Design Patterns: Elements of Reusable Object-Oriented Software - GoF

@AtifTweets

Decorators

• Decorators: The Cure for Ugly Code• Can easily add responsibility for any object• Delegate any unknown method to object it

decorates• Decorators only copy the type of the

component class not the behaviour• Follow open and close philosophy = Open to

Extend … Close for Modifications

@AtifTweets

@AtifTweets

The decorator pattern

@AtifTweets

Why do we need this?

• Only thing constant is the CHANGE• Inheritance Powerful but NOT Flexible or

Maintainable design pattern• So we prefer Composition and Delegation

@AtifTweets

Example

example courtesy Head First Design Patterns

@AtifTweets

Coffeessimo

• A big coffee chain• They have some basic coffee drink types• And also customers can customize there

coffee by adding different condiments on offer

• They have coffee types: HouseBlend, DarkRoast, Espresso, Decaf

• Condiment types: Milk, Mocha, Soy, Whip

@AtifTweets

Class Explosion

@AtifTweets

@AtifTweets

Dark Roast

cost()

@AtifTweets

Dark Roast

cost()

Mocha

cost()

@AtifTweets

Dark Roast

cost()

Mocha

cost()

Whip

Cost()

Whip Mocha Dark Roast coffee is ready!

@AtifTweets

Dark Roast

cost()

Mocha

cost()

Whip

Cost()

Cost

0.20

0.100.99

€1.29

@AtifTweets

Espresso

cost()

Whip

cost()

Dynamically created different coffees

0.10 0.90

Decaf

cost()

Mocha

cost()

0.20 1.20

€1.00€1.40

Whip Espresso Mocha Decaf

@AtifTweets

Exhibits

@AtifTweets

Exhibits

• Flavor of Decorators• The primary goal of exhibits is to connect a

model object with a context for which it's rendered

• Very often you'll likely want to add some additional functionality. Such is the case with exhibits. The additional functionality added will extend (but not disrupt) the delegate object.

@AtifTweets

Exhibits• Wraps a single model instance.• Is a true Decorator. • Brings together a model and a context. Exhibits need

a reference to a "context" object—either a controller or a view context—in order to be able to render templates as well as construct URLs for the object or related resources.

• Encapsulates decisions about how to render an object. The tell-tale of an Exhibit is telling an object "render yourself", rather than explicitly rendering a template and passing the object in as an argument.

@AtifTweets

Example

class CarExhibit < Decorator def initialize(car, context) @context = context super(car) # Set up delegation end

def additional_info "Some cars with 2 doors have a back seat, some don't. Brilliant." end

def render @context.render(self) endend

class TextRenderer def render(car) "A shiny car! #{car.additional_info}" endend

class HtmlRenderer def render(car) "A <strong>shiny</strong> car! <em>#{car.additional_info}</em>" endend

class Car def price 1_000_000 endend

example courtesy mikepackdev.com

@AtifTweets

car = CarExhibit.new(Car.new, TextRenderer.new)car.render #=> "A shiny car! Some cars with 2 doors have a back seat, some don't. Brilliant.“car.price #=> 1000000

car2 = CarExhibit.new(Car.new, HtmlRenderer.new)car2.render #=> "A <strong>shiny</strong> car! <em>Some cars with 2 doors have a back seat, some don't. Brilliant.</em>"

@AtifTweets

Presenters

@AtifTweets

a_view.html.rb

<% if entry.image_url.present? %> <%= render "/posts/picture_body", post: entry

%> <% else %>

<%= render "posts/text_body", post: entry %> <% end %>

@AtifTweets

VIEW MODEL

@AtifTweets

Presenters

• Presenters were originally formed as a more composite-oreinted object, but modern day presenters are more like decorators.

• Presenter deals with view and model• Clean the view by moving the logic to the

presenter class

@AtifTweets

VIEW MODELPRESENTER

Logic

Main Goal

@AtifTweets

Secondary Goal

VIEW MODELPRESENTER

Helpermethods

methods

@AtifTweets

Difference b/w Exhibit and Presenters

• A key differentiator between exhibits and presenters is the language they speak. Exhibits shouldn't know about the language of the view (eg HTML). Exhibits speak the language of the decorated object. Presenters speak the language of the view.

• Presenters and exhibits differ in their proximity to the view. Presenters live very close to the view layer. In fact, they are meant to be a representation of the delegate object within the view.

@AtifTweets

Presenter in action

example courtesy railscast.com

@AtifTweets

@AtifTweets

/app/views/users/show.html.erb<div id="profile"> <%= link_to_if @user.url.present?, image_tag("avatars/#{avatar_name(@user)}", class: "avatar"), @user.url %> <h1><%= link_to_if @user.url.present?, (@user.full_name.present? ? @user.full_name : @user.username), @user.url %></h1> <dl> <dt>Username:</dt> <dd><%= @user.username %></dd> <dt>Member Since:</dt> <dd><%= @user.member_since %></dd> <dt>Website:</dt> <dd> <% if @user.url.present? %> <%= link_to @user.url, @user.url %> <% else %> <span class="none">None given</span> <% end %> </dd> <dt>Twitter:</dt> .....

@AtifTweets

<%= link_to_if @user.url.present?, image_tag("avatars/#{avatar_name(@user)}", class: "avatar"), @user.url %>

Helper Method

module UsersHelper def avatar_name(user) if user.avatar_image_name.present? user.avatar_image_name else "default.png" end endend

Condition

@AtifTweets

/app/presenters/user_presenter.rb

class UserPresenter

def initialize(user, template) @user = user @template = template end def avatar @template.link_to_if @user.url.present?, @template.image_tag("avatars/#{avatar_name}", class: "avatar"), @user.url end private def avatar_name if @user.avatar_image_name.present? @user.avatar_image_name else "default.png" end end

end

@AtifTweets

/app/views/users/show.html.erb

<% present @user do |user_presenter| %><div id="profile"><%= user_presenter.avatar %> <!-- Rest of view code omitted --></div><% end %>

module ApplicationHelper

def present(object, klass = nil) klass ||= "{object.class}Presenter".constantize presenter = klass.new(object, self) yield presenter if block_given? presenter end

end

@AtifTweets

Further learning

• Head First Design Patterns di Eric Freeman, Elisabeth Freeman, Kathy Sierra e Bert Bates

• Design Patterns in Ruby di Russ Olsen• Design Patterns for Dummies• Objects on Rails by Avdi Grimm• http://mikepackdev.com/blog_posts/31-exhib

it-vs-presenter

• http://railscasts.com/episodes/287-presenters-from-scratch

@AtifTweets

Grazie!