Design Patterns in Ruby by Russ Olsen | Jason Meridth’s Blog

After nudging by Joe Ocampo and Scott Bellware, I finally sat down at finished “Design Patterns in Ruby” by Russ Olsen.
The format of most of the chapters made the book an interesting read:
1. A introduction to why you might need the pattern
2. A static language developer’s approach with the Ruby language
3. A seasoned Ruby developer’s approach to the design pattern
4. Using and Abusing
5. in the wild
6. Wrapping up
Some of the items that I learned [LosTechies is not a cult contrary to some of the examples you read below; some of the examples below are using LosTechies nomenclature but closely resemble what the author had in the book]
If any of the stuff below intrigues you: GO BUY THE BOOK. You won’t regret it. Even if you are trying to understand patterns in another language. Russ Olsen does an excellent job explaining the INTENT of the patterns.
FUN
When teaching the reader about “Truth, Lies, and nil”, the author even pokes fun at himself:

'russ' == 'smart'    # sadly, false

BOOLEAN
In Ruby, zero, being neither false nor nil, evaluates to true in Boolean expression.

if 0 puts('Zero is true!')end

will print out: Zero is true!

ARRAYS
Points for matrix reference in array examples

x = []y = Array.newa = ['neo', 'trinity', 'tank']

REGULAR EXPRESSIONS
The flow of the language when creating regular expressions:

/old/ =~ 'this old house'     # 5 - the index of 'old'/Russ|Russell/ =~ 'Fred'      # nil - Fred is not Russ nor Russell/.*/ =~ 'any old string'      # 0 - the RE will match anything

ARBITRARY PARAMETERS
Any author that uses DC comic character to explain arbitrary numbers of arguments, is a winner in my mind:

def describe_hero(name, *super_powers> puts("Name: #{name}") for power in super_powers     puts("Super power: #{power}") endenddescribe_hero("Batman")describe_hero("Flash", "speed")describe_hero("Superman", "can fly", "x-ray vision", "invulnerable")   # w00t!

DUCK TYPING AND UNIT TESTS
He mentions duck typing and the fact that “Unit Tests Are Not Optional” is a section heading when teaching the Template Method Pattern.

PROCS AND BLOCKS

# using the do/end notationhello = lambda do puts('Hello') puts('I am a follower of Pablo')end#you may use curly braces instead of do/endhello = lambda { puts('Hello, I am a follower of Pablo')}#the preferred way to use curly braceshello = lambda {puts('Hello, I am a follower of Pablo')}

STRATEGY PATTERN
using proc-based formatters to create a ruby-based strategy pattern

class Report attr_reader :title, :text attr_accessor :formatter def initialize(&formatter)   @title = 'Monthly Report'   @text = ['Things are going', 'really, really well.' ]   @formatter = formatter end def output_report   @formatter.call( self ) endendHTML_FORMATTER = lambda do |context|...code to output HTMLreport = Report.new &HTML_FORMATTERreport.output_report

You could create any type of formatter you want in a proc instead creating new classes.

OBSERVER PATTERN
Modules exist that encapsulate things that some of us static developers might already be used to:

require 'observer'class Employeeinclude Observableattr_reader :name, :addressattr_reader :salarydef initialize( name, title, salary) @name = name @title = title @salary = salaryenddef salary=(new_salary) @salary = new_salary changed notify_observers(self)endend

ITERATOR PATTERN
Internal Iterators versus External Iterators: (had never heard it put this way)
External iterator – client drives the iteration…you won’t call next until you are good and ready for the next element
Internal iterator – the aggregate relentlessly pushes the code block to accept item after item.

COMMAND PATTERN
The Command pattern translates very smoothly into code blocks. Here is a PabloForPresidentButton class reworked to use code blocks:

class PabloForPresidentButtonattr_accessor :commanddef initialize(&block) @command = blockend## Lots of button drawing and management# code omitted ...#def on_button_push @command.call if @commandendendnew_button = PabloForPresidentButton.new do## Make a developer stop looking so nerdy# by placing one over his pocket protector#end

The author does not diminish the needs for classes. For straightforward actions, use a Proc object. For complex object or objects that will carry around a lot of state, create a command class.

ADAPTER PATTERN
Instead of adhering to some interface and trying to create your adapter, why not just extend the original class.

# load original classrequire 'lostechies_text_object'# now add some methods to original classclass LosTechiesTextObjectdef sponsor return friend_of_pabloenddef blogger return follower_of_pabloendend

Before any of you Open-Closed people attack, please re-read the definition of OCP – Open for extension, closed for modification. Doesn’t this adhere to that? 🙂

PROXY PATTERN
There are three tyes of Proxies: The Protection Proxy, Remote Proxy, Virtual Proxy
These are mentioned in the Gang of Four book. He introduces a Ruby-esqe way to approach proxies: the method_missing Method

class AccountProxydef initialize(real_account) @subject = real_accountenddef method_missing(name, *args) puts("Delegating #{name} message to subject.") @subject.send(name, *args)endendap = AccountProxy.new( BankAccount.new(100) )ap.deposit(25)ap.withdraw(50)puts("account balance is now: #{ap.balance}")

Will output:
delegating deposit method to subject.
delegating withdraw method to subject.
delegating balance method to subject.
account balance is now: 75

DECORATOR PATTERN

module Decorator1def do_something(common_item_to_decorate) #codeendendmodule Decorator2def do_something(common_item_to_decorate) #codeendendd = SimpleItem.new()d.extend(Decorator1)d.extend(Decorator2)e.do_something('howdy')

SINGLETON PATTERN
The author admits the career of the singleton has been checkered, but still shows that you can use it in the Ruby world. An example he gives us to allow testing of singleton implementation code is to put the implementation code in a base class and have the child be the singleton:

require 'singleton'class SimpleLogger#  All of the logging functionality in this class...#  Test this codeendclass SingletonLogger < SimpleLogger

FACTORY/ABSTRACT FACTORY PATTERN
I never had it straight, exactly, what the difference between these patterns were (yes, besides name). I never bothered to look. According to the author, Factory returns back a single object while Abstract Factory is “an object dedicated to creating a compatible set of objects”. According to GoF book (which I have open in front of me), Abstract Factory “provides an interface for creating families of related or dependent objects without specifying their concreate classes”. Which one do you think would have turned the light bulb off in your head? 🙂
The other item was using “Convention Over Configuration” to generate abstract factories:

class IOFactorydef initialize(format) @reader_class = self.class.const_get("#{format}Reader") @writer_class = self.class.const_get("#{format}Writer")enddef new_reader @reader_class.newenddef new_writer @writer_class.newendendhtml_factory = IOFactory.new('HTML')html_reader = html_factory.new_readerpdf_factory = IOFactory.new('PDF')pdf_writer = pdf_factory.new_writer

Notice the correct classes (reader/writer) are generated dynamically with the help of the const_get Ruby method.

BUILDER PATTERN
Magic methods: “very easy to implement using the method_missing technique…you simply catch all unexpected method calls with method_missing and parse the method name to see if it matches the pattern of your magic method name”.

#example method passed into computer builder classbuilder.add_dvd_and_harddisk#orbuilder.add_turbo_and_dvd_dvd_and_harddiskdef method_missing(name, *args)words = name.to_s.split("_")return super(name, *args) unless words.shift == 'add'words.each do |word| #next is same as continue in for loop in C# next if word == 'and' #each of the following method calls are a part of the builder class add_cd if word == 'cd' add_dvd if word == 'dvd' add_hard_disk(100000) if word == 'harddisk' turbo if word == 'turbo'endend

Last 3 Chapters are the meat of the book:
INTERPRETER PATTERN (place where Bellware told me to start)
DOMAIN SPECIFIC LANGUAGE (DSL)
CONVENTION OVER CONFIGURATION
Those stay obscure so you can go read it. I think the book is worth a visit on Safari books if you have an account or worth the purchase for the bathroom reading.
I enjoyed it. Thanks Scott and Joe

Implementasi Table Data Gateway di PHP

Dari blog saya memahami-table-gateway-pattern saya akan mencoba mencontohkan implementasi SEDERHANA pada PHP,

Implementasi ini menggunakan teknik pemrograman Metaprogramming bagi yang memang merasa tidak suka bisa mencoba teknik code generation namun

Kalo menggunakan code generation ya silakan dicoba sendiri.. hehehe

  

Ok langsung 2 the point, pertama buat dulu table mahasiswa dengan field2 yang seperti di bawah ini :

  

mysql> desc mahasiswa;

+——–+————–+——+—–+———+——-+

| Field | Type | Null | Key | Default | Extra |

+——–+————–+——+—–+———+——-+

| nrp | int(10) | NO | PRI | NULL | |

| nama | varchar(255) | YES | | NULL | |

| gender | tinyint(1) | YES | | NULL | |

+——–+————–+——+—–+———+——-+

3 rows in set (0.23 sec)

  

Lalu tahap kedua saya membuat class TableGateway secara umum terlebih dahulu yang nantinya akan dijadikan parent class untuk class Gateway per table :

  

<?php

/**

@author radityo pw (radityo_pw@is.its.ac.id)

**/

class TableGateway{

      

    protected $db;

      

    protected $table;

      

    public function __construct($db,$table){

        $this->db = $db;

        $this->table = $table;

    }

      

    protected function generate_sql($mode,$data=array(),$where=”1=1″){

$sql = “”;

         $table = $this->table;

switch($mode){

case “add” :

$sql = “INSERT INTO $table”;

$akey = array();

$avalue = array();

foreach ($data as $key => $value) {

$akey[] = $key;

$avalue[] = “‘”.$value.”‘”;

}

$skey = implode(“,”,$akey);

$svalue = implode(“,”,$avalue);

$sql .= “(“.$skey.”) values(“.$svalue.”)”;

break;

  

case “del” :

$sql = “DELETE FROM $table WHERE $where”;

break;

  

case “edit” :

$sql = “UPDATE $table SET”;

$aupdate = array();

foreach ($data as $key => $value) {

$aupdate[] = “$key=’$value'”;

}

$supdate = implode(“,”,$aupdate);

$sql .= ” $supdate WHERE $where”;

break;

}

return $sql;

}

      

    public function search($where_condition,$order_by = null,$offset = null,$size = null){

        $sql = “SELECT * FROM “.$this->table.” WHERE “.$where_condition;

        if($order_by != null){

            $sql = $sql.” ORDER BY “.$order_by;

        }else if($offset != null){

            $sql = $sql.” LIMIT “.$offset.”,”.$size;

        }

        $sth = $this->db->prepare($sql);

        $sth->execute();

        return $sth->fetchAll(PDO::FETCH_ASSOC);

    }

      

    protected function find_by($prefix,$arguments,$order_by = null,$offset = null,$size = null){

        $sql = “SELECT * FROM “.$this->table.” WHERE “.$prefix.” = ‘”.$arguments.”‘”;

        if($offset != null){

            $sql = $sql.” LIMIT “.$offset.”,”.$size;

        }

        if($order_by != null){

            $sql = $sql.” ORDER BY “.$order_by;

        }

        $sth = $this->db->prepare($sql);

        $sth->execute();

        return $sth->fetchAll(PDO::FETCH_ASSOC);

    }

      

    protected function delete_by($prefix,$arguments){

        $sql = $this->generate_sql(“del”,array(),$prefix.” = ‘”.$arguments.”‘”);

        $sth = $this->db->prepare($sql);

        $sth->execute();

    }

      

    protected function edit_by($prefix,$value,$arguments){

        $sql = $this->generate_sql(“edit”,$arguments,$prefix.” = ‘”.$value.”‘”);

        $sth = $this->db->prepare($sql);

        $sth->execute();

    }

      

    public function add($data){

        $sql = $this->generate_sql(“add”,$data);

        $sth = $this->db->prepare($sql);

        $sth->execute();

    }

      

    public function findAll($order_by = null,$offset = null,$size = null){

        $sql = “SELECT * FROM “.$this->table;

        if($order_by != null){

            $sql = $sql.” ORDER BY “.$order_by;

        }

        if($offset != null){

            $sql = $sql.” LIMIT “.$offset.”,”.$size;

        }

        $sth = $this->db->prepare($sql);

        $sth->execute();

        return $sth->fetchAll(PDO::FETCH_ASSOC);

    }

      

    public function deleteAll(){

        $sql = $this->generate_sql(“del”);

        $sth = $this->db->prepare($sql);

        $sth->execute();

    }

      

    public function __call($name, $arguments) {

          

        if(strpos($name, “find_by_”) !== FALSE){

            $prefix = str_replace(“find_by_”, “”, $name);

              

            if(count($arguments) == 1){

                return $this->find_by($prefix,$arguments[0]);

            }else if(count($arguments) == 2){

                return $this->find_by($prefix,$arguments[0],$arguments[1]);

            }else if(count($arguments) == 4){

                return $this->find_by($prefix,$arguments[0],$arguments[1],$arguments[2],$arguments[3]);

            }

        }else if(strpos($name, “delete_by_”) !== FALSE){

            $prefix = str_replace(“delete_by_”, “”, $name);

            $this->delete_by($prefix,$arguments[0]);

        }else if(strpos($name, “edit_by_”) !== FALSE){

            $prefix = str_replace(“edit_by_”, “”, $name);

            $this->edit_by($prefix,$arguments[0],$arguments[1]);

        }

    }

}

/*END OF FILE*/

  

Dari kode di atas dapat dilihat saya menggunakan magic method __call(…) dimana tujuannya adalah memberikan fleksibilitas dalam pemanggilan dan pengesetan attribute dari class

Misalnya seperti contoh di atas bahwa table mahasiswa terdapat field nrp, maka nanti saya dapat mencari mahasiswa yang bernrp tertentu menggunakan

$class->find_by_nrp(…..) , yang sebenarnya ini dimapping ke fungsi find_by(,…..). untuk koneksi database dalam hal ini menggunakan PDO.

  

Langkah selanjutnya tinggal membuat class gateway per table yang diinginkan, dalam hal ini yaitu MahasiswGateway.php :

<?php

require_once(“TableGateway.php”);

class MahasiswaGateway extends TableGateway{

      

    public function __construct($db){

        parent::__construct($db,’mahasiswa’);

    }

      

    public function search_top_ten(){

        return $this->findAll(null,0,10);

    }

}

/*END OF FILE*/

  

Dari class MahasiswaGateway dapat dilihat melakukan penurunan dari class TableGateway berarti nantinya kemampuan TableGateway akan diturunkan ke MahasiswaGateway, sekarang mari buat Test Class nya :

  

<?php

require_once(‘MahasiswaGateway.php’);

$dsn = ‘mysql:dbname=test_for_blog;host=127.0.0.1’;

$user = ‘root’;

$password = ”;

  

try {

$dbh = new PDO($dsn, $user, $password,array( PDO::ATTR_PERSISTENT => true));

} catch (PDOException $e) {

echo ‘Connection failed: ‘ . $e->getMessage();

     exit(1);

}

  

$mhs_gateway = new MahasiswaGateway($dbh);

  

$data = array(

    ‘nrp’=>’5202100002’,

    ‘nama’=>’radityo prasetianto wibowo’,

    ‘gender’=>0

);

  

$mhs_gateway->add($data);

  

var_dump($mhs_gateway->find_by_nama(‘radityo prasetianto wibowo’));

/*END OF FILE*/

  

Nah dari Test Class diatas dapat diluihat untuk menginsert data saya hanya membutuhkan sebuah associative array (HashMap kalo di Java) lalu saya tinggal memasukkan dalam method add..

Jika ingin melakukan pencarian dengan filter sebuah field , maka tinggal melakukan pemanggilan layaknya memanggil atribut biasa.. (find_by_nama(…..)) seperti pada contoh diatas.

Masih banyak fungsi2 yang belum tercover pada Test class ini namun dapat anda coba langsung..

Jika anda tertarik dan ingin berdiskusi jangan sungkan untuk mengemail saya di radityo_pw[at]is.its.ac.id

Memahami Table Data Gateway Pattern

Table Gateway pattern adalah salah satu dari sekian design pattern yang dapat digunakan untuk melakukan hubungan antara class dengan database.Table Gateway ini bertujuan untuk menghandle semua baris dalam sebuah table database.

Media_httpblogitsacid_umsxe

Seringkali para pengembang sebuah perangkat lunak menemui kebutuhan untuk menyimpan data pada media disk yang permanen, salah satunya adalah disimpan dalam database. Untuk membangun sebuah database dibutuhkan proses tersendiri dalam merancang dan membangun database tersebut yang tidak discover dalam bahasan kali ini.

Nah, untuk menggunakan database(Relational) dalam pemrograman berbasis objek bisa dikatakan susah susah gampang, umumnya para programmer pemula akan melakukan pengkodean campur antara kode logic dengan kode sql untuk menghubungkan antara aplikasi, berdasarkan banyak literature dan pengalaman pribadi tentunya, hal ini sangatlah tidak baik dan merupakan kebiasaan yang sangat harus dihindari.

Dengan bercampurnya kode logic dengan kode sql paling tidak ada beberapa masalah yang dapat muncul misalnya kode logic semakin sulit untuk dilihat (dalam bahasa gaul ini mbikin mata picek!) akibatnya jika sulit untuk dilihat akan sulit pula untuk dimaintain. Kebanyakan programmer juga sebenarnya tidak nyaman dalam menulis program yang memiliki cara campur aduk seperti ini (spaghetti code), dan walaupun ada yang nyaman akan memungkinkan terjadi banyak kesalahan dalam pembuatannya.

Sebenarnya mengapa hal sulit dalam pembuatan aplikasi Object Oriented(OO) yang menggunakan database (Relational) adalah adanya perbedaan secara konseptual pada keduanya.. dimana memang programmer dituntut untuk berfikir Objek dan Relasi secara bersamaan, bayangkan saja jika anda diminta berbahasa 2 bahasa sekaligus.. tentu akan ribet…:hammer:

Cara kerja pattern ini persis seperti namanya yaitu sebagai pintu gerbang antara objek yang diminta dengan database, sehingga nantinya objek yang diminta dapat digunakan dalam aplikasi yang dibuat seperti halnya mengakses objek biasa. TableGatweay akan berisi method – method yang berhubungan dengan behavior yang bisa dilakukan untuk semua baris yang ada di dalam table. Misalnya saja method find_by_id(..) , add(..) del_by_id(..) dan lain sebagainya yang nantinya method – method ini akan mengenerate sql yang akan diproses di database.Ciri utama dari TableGateway adalah walaupun sesimple apapun akan mengembalikan kumpulan dari baris yang ada di table, bukan baris yang bersangkutan saja. Misal method find_by_id(..) dipanggil akan mengembalikan array dari object yang diinginkan, dimana bisa saja isi array tersebut hanya satu saja.Contoh implementasi dalam class diagram adalah seperti berikut :

Media_httpblogitsacid_gngkj