Design pattern forwardable

code 22 juin 2025

🎯 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  

Mots clés

Romain GEORGES

Open Source evangelist & Ruby enthousiast