Skip to content

kslazarev/code_style_advanced

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 

Repository files navigation

**Draft

Паттерны проектирования

Template Method (Шаблонный Метод)

Varying the Algorithm with the Template Method Варирование алгоритма с помощью Шаблонного Метода

Bad

class Users::Physic < Users::Base
  def initialize name, website
    @name = name
    @website = website
  end

  def description
    puts("#{@name} [#{@website}] (#{class.to_s})")
  end
end

class Users::Juristic < Users::Base
  def initialize name, company
    @name = name
    @company = company
  end

  def description
    puts("#{@name} [#{@company}] (#{class.to_s})")
  end
end

Good

class Users::Base
  def description
    puts("#{printable_name} (#{class.to_s})")
  end

  def printable_name
    'abstract name'
  end
end

class Users::Physic < Users::Base
  def initialize name, website
    @name = name
    @website = website
  end

  def printable_name
    "#{@name} [#{@website}]"
  end
end

class Users::Juristic < Users::Base
  def initialize name, company
    @name = name
    @company = company
  end

  def printable_name
    "#{@name} [#{@company}]"
  end
end

Example

> physic = Users::Physic.new('Google', 'http://google.com') 
> physic.description

> 'Google [http://google.com] (Users::Physic)'

=> juristic = Users::Juristic.new('Yandex', 'Yandex Inc') 
=> juristic.description

> 'Yandex [Yandex Inc] (Users::Juristic)'

=> abstract_user = Users::Base.new
=> abstract_user.description

> 'abstract name (Users::Base)'

Strategy (Шаблонный Метод)

Replacing the Algorithm with the Strategy Замена Алгоритма с помощью Стратегии

Bad code

class Users::Base
  def description
    'It's a description of Users::Base'
  end
end

class PlainTextFormatter
  def report text
    puts '<plain text>'
    puts text
    puts '<plain text>'
  end
end

class HTMLFormatter
  def report text
    puts '<html>'
    puts '<head>'
    puts '</head>'
    puts '<body>'
    puts text
    puts '</body>'
    puts '</html>'
  end
end

Good code

class Users::Base
  def initialize name, formatter
    @name = name
    @formatter = formatter
  end

  def report
    fomatter.report(self)
  end
end

class PlainTextFormatter
  def report context 
    puts '<plain text>'
    puts context.name
    puts '<plain text>'
  end
end

class HTMLFormatter
  def report context
    puts '<html>'
    puts '<head>'
    puts '</head>'
    puts '<body>'
    puts context.name
    puts '</body>'
    puts '</html>'
  end
end

Example

> user = Users::Base.new('username', HTMLFormatter.new)
> user.report

> user = Users::Base.new('username', PlainTextFormatter.new)
> user.report

Good code (Ruby way)

class Users::Base
  def initialize name, &formatter
    @name = name
    @formatter = formatter
  end

  def report
    formatter.call self
  end
end

Example

> PLAIN_TEXT_FORMATTER = lambda do |context|
>   puts '<plain text>'
>   puts context.name
>   puts '<plain text>'
> end

> HTML_FORMATTER = lambda do |context|
>   puts '<html>'
>   puts '<head>'
>   puts '</head>'
>   puts '<body>'
>   puts context.name
>   puts '</body>'
>   puts '</html>'
> end

> user = Users::Base.new('username', PLAIN_TEXT_FORMATTER)
> user.report

> user = Users::Base.new('username', HTML_FORMATTER)
> user.report

Observer

Keeping Up with the Times with the Observer

Not good code

class Users::Base
  attr_reader :payment

  def initialize name, payment, payment_notification
    @name = name
    @payment = payment
    @payment_notification = payment_notification
  end

  def payment= new_payment
    @payment = new_payment
    payment_notification.update(self)
  end
end

class PaymentNotification
  def update
    puts "#{self.name} payment updated to #{self.payment}"
  end
end

Good code

module Observers
  def initialize
    @observers=[]
  end

  def add_observer &observer
    @observers << observer
  end

  def delete_observer observer
    @observers.delete(observer)
  end

  def notify_observers
    @observers.each do |observer|
      observer.call(self)
    end
  end
end

class Users::Base
  include Observers
  attr_reader :payment

  def initialize name, payment
    super()
    @name = name
    @payment = payment
  end

  def payment= new_payment
    @payment = new_payment
    notify_observers
  end
end

Example

> user = Users::Base.new('username', 35000)
> user.add_observer do |changed_user|
>   puts "#{changed_user.name} payment updated to #{changed_user.payment}" 
> end

> user.payment = 40000
=> 'username payment updated to 40000'

Good code (Rails way)

class Users::Base < ActiveRecord
  attr_accessor :payment

  def initialize name, payment
    super()
    @name = name
    @payment = payment
  end

  def payment= new_payment
    @payment = new_payment
    notify_observers
  end
end

class NotificationObserver < ActiveRecord::Observer
  observe Users::Base

  def after_update(user)
    puts "#{user.name} updated"
  end
end

Example

> user = Users::Base.new('username', 30000)
> user.payment = 45000
=> 'username updated'

Composite

Assembling the Whole from the Parts with the Composite

class Users::Base < ActiveRecord
  attr_reader :payment

  def initialize name, payment
    super()
    @name = name
    @payment = payment
    @children = []
  end

  def add child
    @children << child
  end

  def children
    @children 
  end
end

> user_one = Users::Base.new('username', 30000)
> user_one.add Users::Base.new('username', 40000)
> user_one.add Users::Base.new('username',50000)
> user_one.children[0].add Users::Base.new('username', 60000)
> 
> payment_sum = user_one.payment + user_one.children[0].payment 
>   + user_one.children[1].payment + user_one.children[0].children[0].payment

class UsersComposite < User
  def payment_sum
    payment_sum = 0.0
    @children.each{|child| time += child.payment}
    payment_sum
  end

  def << child
    add child
  end

  def [] index
    @children[index]
  end

  def []= index, new_child
    @children[index] = new_child
end

> composite = UsersComposite.new
> composite << user_one
> payment_sum = composite.payment_sum

Iterator

Reaching into a Collection with the Iterator

class ExternalArrayIterator
  def initialize(array)
    @array = array
    @index = 0
  end

  def has_next?
    @index < @array.length
  end

  def next_item
    value = @array[@index]
    @index += 1
    value
  end
end

>> array = [1,'aaa', Users::Base.new]
>> iterator = ExtrenalArrayIterator.new(array)
>> while iterator.has_next?
>>   iterator.next_item.to_s
>> end

class ArrayIterator < Enumerable
end 

class InternalArrayIterator
  def self.for_each_element(array)
    i = 0
    while i < array.length
      yield(array[i])
      i += 1
    end 
  end
end

>> array = [1, 'aaa', Users::Base.new]
>> InternalArrayIterator.for_each_element(array){|element| element.to_s}

Command

Getting Things Done with Commands

class Users::Administrator < Users::Base
  def on_action
    #Maybe get list of all users
  end
end

class Users::Support < Users::Base
  def on_action
    #Maybe get list of all users except administrators
  end
end

class Users::Base
  attr_accessor :command

  def initialize command
    @command = command
  end

  def on_action
    @command.execute if @command
  end
end

class UsersListCommand
  def execute
  end
end

class UserListExceptAdminsCommand
  def execute
  end
end

> Users::Administrator.new(UsersListCommand.new)
> Users::Support.new(UserListExceptAdminsCommand.new)

class Users::Base
  attr_accessor :command

  def initialize &block
    @command = block
  end

  def on_action
    @command.call if @command
  end
end

> Users::Base.new do 
>
> end

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published