Design pattern forwardable
🎯 Objectif : Construire une classe en exploitant une partie d'un autre et la charge active de l'autre
👆 Remarque : cas d'une Queue LIFO
Anti-pattern
Anti-pattern 1 : from scratch
Construire from scratch, même pas en rêve
Anti-pattern 2 : l'héritage
class MyQueue < Array
alias :enq :push
alias :deq :shift
end
myqueue = MyQueue::new
myqueue.enq 1,45,12
puts myqueue.deq
puts myqueue.deq
pp myqueue
p myqueue.methods
Sortie :
1
45
[12]
[:enq, :deq, :to_h, :include?, :&, :at, :fetch, :last, :union, :difference, :intersection, :push, :append, :pop, :shift,
:unshift, :each_index, :join, :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :filter!, :keep_if,
:values_at, :delete_at, :delete_if, :reject!, :transpose, :fill, :assoc, :rassoc, :uniq!, :compact, :+, :compact!,
:-, :flatten!, :flatten, :combination, :permutation, :*, :repeated_permutation, :repeated_combination, :product,
:bsearch, :sort, :deconstruct, :bsearch_index, :count, :find_index, :select, :filter, :reject, :collect, :map, :first,
:all?, :any?, :one?, :none?, :minmax, :reverse_each, :pretty_print_cycle, :zip, :take, :take_while, :drop, :|, :cycle,
:drop_while, :sum, :uniq, :<=>, :<<, :insert, :==, :index, :[], :[]=, :replace, :rindex, :clear, :empty?, :eql?, :max,
:min, :inspect, :reverse, :reverse!, :concat, :prepend, :length, :size, :each, :to_ary, :to_a, :to_s, :delete, :pretty_print,
:slice, :slice!, :dig, :pack, :shuffle!, :shuffle, :sample, :hash, :slice_after, :slice_when, :chunk_while, :chain, :lazy,
:find, :entries, :sort_by, :grep, :grep_v, :detect, :find_all, :filter_map, :flat_map, :collect_concat, :inject, :reduce,
:partition, :group_by, :tally, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons,
:each_with_object, :chunk, :slice_before, :pretty_print_inspect, :pretty_print_instance_variables, :taint, :tainted?, :untaint,
:untrust, :untrusted?, :trust, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods,
:instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable,
:instance_of?, :kind_of?, :is_a?, :class, :frozen?, :then, :public_send, :method, :public_method, :singleton_method, :tap,
:define_singleton_method, :extend, :clone, :yield_self, :to_enum, :enum_for, :===, :=~, :!~, :pretty_inspect, :nil?,
:respond_to?, :freeze, :object_id, :send, :display, :singleton_class, :dup, :itself, :!, :!=, :equal?, :instance_eval,
:instance_exec, :__id__, :__send__]
👆 Constat : on retrouve l'implementation de Array
Ugly Pattern
class MyQueue
attr :q
def initialize
@q = [ ] # forward un Tableau
end
def enq(*args)
@q.push(*args)
end
def deq
return @q.shift
end
def clear
return @q.clear
end
def size
return @q.size
end
end
myqueue = MyQueue::new
myqueue.enq 1,45,12
puts myqueue.deq
puts myqueue.deq
pp myqueue.size
p myqueue.methods
Sortie :
1
45
1
[:size, :clear, :enq, :deq, :q, :pretty_print_cycle, :pretty_print_inspect, :pretty_print_instance_variables, :pretty_print, :taint,
:tainted?, :untaint, :untrust, :untrusted?, :trust, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods,
:instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?,
:kind_of?, :is_a?, :class, :frozen?, :then, :public_send, :method, :public_method, :singleton_method, :tap, :define_singleton_method, :extend,
:clone, :yield_self, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :pretty_inspect, :nil?, :eql?, :respond_to?, :freeze, :inspect, :object_id,
:send, :to_s, :display, :hash, :singleton_class, :dup, :itself, :!, :==, :!=, :equal?, :instance_eval, :instance_exec, :__id__, :__send__]
✅ Remarque : on a bien un prototype de Queue et non de Array
⚠️ Mais ... c'est verbeux
Pattern
require 'forwardable'
class Queue
extend Forwardable
attr :q
def initialize
@q = [ ] # forward un Tableau
end
def_delegator :@q, :push, :enq
def_delegator :@q, :shift, :deq
def_delegators :@q, :clear, :first, :size
end