検索結果をハイライト表示、Escで消す

.vimrcを一気にいじりすぎて収集がつかなくなったので少しずつ整理。
意味もわからずコピペした部分が多すぎる・・

検索結果のハイライト表示&Escで消す

" ========== 検索結果のハイライト&Escで消す
" ハイライトON
set hlsearch

" Esc Esc でハイライトOFF
nnoremap <Esc><Esc> :<C-u>set nohlsearch<Return>

" 「/」「?」「*」「#」が押されたらハイライトをON にしてから「/」「?」「*」「#」
nnoremap / :<C-u>set hlsearch<Return>/
nnoremap ? :<C-u>set hlsearch<Return>?                
nnoremap * :<C-u>set hlsearch<Return>*
nnoremap # :<C-u>set hlsearch<Return>#
" ==========

PHPでGoFデザインパターン 03 Adapter

Adapter パターンとは?

Wikipediaによると

Adapter パターンを用いると、既存のクラスに対して修正を加えることなく、インタフェースを変更することができる。Adapter パターンを実現するための手法として継承を利用した手法と委譲を利用した手法が存在する。

とある。

Adapter パターンを適用した場合のメリット

  • 既存のコードを修正せずに再利用できる
  • 利用側はアダプタの向こう側にある実装を知る必要が無い
  • 異なるAPIを結びつけるだけでなく、公開するAPIを制限することも可能
  • protectedがついている非公開メソッドも利用できる

適用例

Wikipediaで紹介されている利用例をベースに、PHPで実装してみる
継承を利用したものと委譲を利用したものがある。

(1)Product.php    既存のクラス。このクラスへの修正は禁止する
(2)ProductClient.php クラスの利用側。既存のクラスをそのまま使用している

Product.php内にあるgetCostメソッドをgetPriceというメソッドから使えるようにしたい、といったケースを考える。

(3)ProductPriceInterface.php 適用したいAPI実装のインターフェイス
(4)ProductAdapter.php     2つの異なるAPI(1と3)を吸収するアダプタ
(5)ProductAdapterClient.php  アダプタ経由でAPIを利用するクライアント

継承を利用したAdapter

クラス図


コードサンプル

(3)ProductPriceInterface.php

<?php

/**
 * ProductPriceInterface
 *
 * @author keynodes <keynodes@gmail.com>
 */
interface ProductPriceInterface
{
    /**
     * setPrice
     *
     * @param mixed $price
     * @access public
     * @return void
     */
    public function setPrice($price);

    /**
     * getPrice
     *
     * @access public
     * @return void
     */
    public function getPrice();

}

(4)ProductAdapter.php

<?php
require_once 'Product.php';
require_once 'ProductPriceInterface.php';

/**
 * ProductAdapter
 *
 * @uses Product
 * @uses ProductPriceInterface
 * @author keynodes <keynodes@gmail.com>
 */
class ProductAdapter extends Product implements ProductPriceInterface
{
    /**
     * setPrice
     *
     * @param int $price
     * @access public
     * @return void
     */
    public function setPrice($price)
    {
        // call Product::getCost()
        parent::setCost($price);
    }

    /**
     * getPrice
     *
     * @access public
     * @return void
     */
    public function getPrice()
    {
        // call Product::getCost()
        $price = parent::getCost();

        return number_format($price);
    }
}

(5)ProductAdapterClient.php

<?php
require_once 'ProductAdapter.php';

$product = new ProductAdapter("item-A");
$product->setPrice(15000000);

print $product->getPrice(); #=> 15,000,000

実行結果

$ php ProductAdapterClient.php
15,000,000

委譲を利用したAdapter

GoF本上の分類

構造に関するパターン

関連するパターン

デザインパターンの分類

Wikipediaをはじめデザインパターンに関する例の多くはJavaでされていますが、
それらを参考にPHPに置き換えていくことで理解することが目的

生成に関するパターン

構造に関するパターン

振る舞いに関するパターン

PHPでGoFデザインパターン 02 Singleton (その2:Clone対策)

前回PHPでGoFデザインパターン 02 Singletonの続き。
今回はオブジェクトのCloneを作成した場合のはなし。

オブジェクトをCloneした場合

元オブジェクトとクローンしてできたオブジェクトの比較をするために
乱数をセットするメソッドを追加し、呼び出して結果を見る。

Singletonクラス側

     public function setRandData()
     {
         $this->data = mt_rand();
     }

クライアント側

// クローンの作成
$instance1_clone = clone $instance1;

// それぞれのオブジェクトを操作する
echo "=====setRandData=====\r\n";
$instance1->setRandData();
$instance1_clone->setRandData();

// 結果を比較
echo "instance1      :[" . $instance1->getData() . "]\r\n";
echo "instance1_clone:[" . $instance1_clone->getData() . "]\r\n";

結果

つまり、Singletonの特徴である

そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される。

(Wikipediaより引用)
が実現できていないことになる。

Clone対策

http://php.net/manual/ja/language.oop5.cloning.phpによると

オブジェクトのコピーは、clone キーワード (これは、そのオブジェクトの __clone() メソッドがある場合にこれをコールします)により作成されます。 オブジェクトの __clone() メソッドを直接コールすることはできません。

__clone()メソッドを追加し、その内で例外を発生させてみる。

SingletonSample.php

     public final function __clone()
     {
         throw new RuntimeException ('Clone is not allowed class:'. get_class($this));
     }

実行結果

PHPでGoFデザインパターン 02 Singleton

Singletonパターンって?

Wikipediaによると

そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される。

唯一のインスタンスとそれにアクセスするための方法もあわせて提供される。
グローバル変数みたいなもの?

Cloneされた場合の対応

Clone対策が必要になる模様・・後日調査する
→続き:PHPでGoFデザインパターン 02 Singleton (その2:Clone対策)

分類

生成に関するパターン

パターンの例

パターンの構造

SingletonパターンにはSingletonクラスしかない。
コンストラクタをprivateにし、他のクラスから直接インスタンスを生成できないようにしている。
呼び出しは自分自身のインスタンスを生成するstaticなメソッドがある。
自分自身のインスタンスをstatic変数に保持する。

Singletonパターンを使うメリット

自分自身のインスタンスを内部に持ち、そのインスタンスへのアクセス方法も限られているので
他のクラスからのアクセスも制御できることになる。

3つまで生成可能、とか。

Singletonパターンを使うデメリット

Singletonパターンの使いどころ

プログラム内で
(良い) インスタンスを1つしか作らない   → Singleton使おう
(悪い) インスタンスを複数作られると困る → Singleton使おう

Singletonパターンのsample

インスタンスが複数生成されているかを区別するために、privateな変数$dataを持ち、コンストラクタ内で乱数をセットする。
複数回インスタンスを生成し、変数の値が同じであれば同一インスタンスと判断する。

SingletonSample.php

<?php
namespace GofStudy\Singleton;

/**
 * SingletonSample
 *
 * @version $id$
 * @author keynodes <keynodes@gmail.com>
 */
class SingletonSample
{
    /**
     * data
     *
     * @var mixed
     * @access private
     */
    private $data;

    /**
     * instance
     *
     * @var mixed
     * @access private
     */
    private static $instance;

    /**
     * __construct
     *
     * @access private
     * @return void
     */
    private function __construct()
    {
        // インスタンスが生成されるたびに乱数を発生させる
        $this->data = mt_rand();
    }

    /**
     * getData
     *
     * @access public
     * @return void
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * getInstance
     *
     * @static
     * @access public
     * @return void
     */
    public static function getInstance()
    {
        // new してないのでself::でアクセス
        if(!isset(self::$instance)) {
            // インスタンスがなければ生成する
            self::$instance = new SingletonSample();
            echo "instance created\r\n";
        } else {
            echo "instance already created\r\n";
        }

        return self::$instance;
    }
}

続いてクライアント側のコード。

直接インスタンス生成できないよう、SingletonSample のコンストラクタはprivaeで実装しているので、newしようとするとエラーが発生する。

Call to private SingletonSample::__construct() from invalid context

ダブルコロン(::)でメソッドを直接呼び出している。

SingletonClient.php

<?php

require_once 'SingletonSample.php';

$instance1 = GofStudy\Singleton\SingletonSample::getInstance();
sleep(1);
$instance2 = GofStudy\Singleton\SingletonSample::getInstance();


echo "=====instance1=====\r\n";
echo "data:[" . $instance1->getData() . "]\r\n";

echo "=====instance2=====\r\n";
echo "data:[" . $instance2->getData() . "]\r\n";

クラス図

あとで作る

実行結果

php CloneableSingletonClient.php
instance created
instance already created

instance1:[832348161] 
instance2:[832348161] ←同じ値(2回目はインスタンスが生成されていない)

Singletonパターンに関連するパターン

PHPでGoFデザインパターン 01 Template Method

Template Method パターンとは?

Wikipediaによると

ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せることである。

とある。

普通の継承と一見変わらないが、処理の一部分をサブクラスで実装するというのがこのパターンのポイント。
継承ではなく委譲によって似たようなことを実現するパターンとしてStrategyパターンがある。

Template Methodパターンを適用した場合のメリット

  • 共通する処理をスーパークラスに置くことで、サブクラスの重複する実装を排除できる。
  • 実現したい一連の処理が把握しやすい(スーパークラスを見れば処理の流れがわかる)
  • 必要なメソッドのみオーバーライドすることで、処理の内容を変更できる。

クラス図


コードサンプル

Wikipediaで紹介されている利用例をベースに、PHPで実装してみる

まずは抽象クラス
サブクラスに実装を任せるメソッドはabstractを付けて抽象メソッドとして定義する。

<?php
namespace GofStudy\TemplateMethod;

/**
 * AbstractStringLister
 *
 * @abstract
 * @version $id$
 * @author keynodes <keynodes@gmail.com>
 */
abstract class AbstractStringLister
{
    /**
     * data
     *
     * @var string
     * @access private
     */
    private $data = "";

    /**
     * display
     *
     * TemplateMethod
     *
     * @param mixed $items
     * @access public
     * @return string
     */
    public function display($items)
    {

        $this->data .= $this->formatHeader();

        $items = is_array($items) ? $items : (array) $items;
        foreach ($items as $item) {
            $this->data .= $this->formatItem($item);
        }

        $this->data .= $this->formatFooter();

        return $this->data;
    }

    /**
     * formatHeader
     *
     * @abstract
     * @access protected
     * @return void
     */
    abstract protected function formatHeader();

    /**
     * formatItem
     *
     * @param mixed $item
     * @abstract
     * @access protected
     * @return void
     */
    abstract protected function formatItem($item);

    /**
     * formatFooter
     *
     * @abstract
     * @access protected
     * @return void
     */
    abstract protected function formatFooter();

}

続いて具象クラス
ConcreteClassに相当する

2つの表示方法を実装するため、2つのConcreteClass

  • テキストでのリスト形式 PlainTextStringLister
  • HTMLでのリスト形式 HtmlStringLister

を実装する

PlainTextStringLister.php

<?php
namespace GofStudy\TemplateMethod;

require_once 'AbstractStringLister.php';

/**
 * PlainTextStringLister
 *
 * ConcreteClass
 *
 * @uses StringLister
 * @author keynodes <keynodes@gmail.com>
 */
class PlainTextStringLister extends AbstractStringLister
{
    /**
     * formatHeader
     *
     * @access public
     * @return string
     */
    public function formatHeader()
    {

        return "";
    }

    /**
     * formatItem
     *
     * @param mixed $item
     * @access public
     * @return string
     */
    public function formatItem($item)
    {

        return " - " . $item . "\r\n";
    }

    /**
     * formatFooter
     *
     * @access public
     * @return string
     */
    public function formatFooter()
    {

        return "";
    }
}

HtmlStringLister.php

<?php
namespace GofStudy\TemplateMethod;

require_once 'AbstractStringLister.php';

/**
 * HtmlStringLister
 *
 * ConcreteClass
 *
 * @uses StringLister
 * @author keynodes <keynodes@gmail.com>
 */
class HtmlStringLister extends AbstractStringLister
{
    /**
     * formatHeader
     *
     * @access public
     * @return string
     */
    public function formatHeader()
    {

        return "<ul>\r\n";
    }

    /**
     * formatItem
     *
     * @param mixed $item
     * @access public
     * @return string
     */
    public function formatItem($item)
    {

        return "  <li>" . $item . "</li>\r\n";
    }

    /**
     * formatFooter
     *
     * @access public
     * @return string
     */
    public function formatFooter()
    {

        return "</ul>\r\n";
    }
}

これらのクラスを使うクライアントプログラムを作成

TemplateMethodClient.php

<?php

require_once 'PlainTextStringLister.php';
require_once 'HtmlStringLister.php';

$items = array("first", "second", "third");

$plainTextStringLlist = new GofStudy\TemplateMethod\PlainTextStringLister();
$htmlStringList       = new GofStudy\TemplateMethod\HtmlStringLister();

print "=====plainTextStringList=====\r\n";
print $plainTextStringLlist->display($items);
print "\n\n";
print "=====htmlStringList=====\r\n";
print $htmlStringList->display($items);

実行結果

$ php TemplateMethodClient.php
=====plainTextStringList=====
 - first
 - second
 - third


=====htmlStringList=====
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

GoF本上の分類

振る舞いに関するパターン

関連するパターン

Strategyパターン 継承によるTemplateMethodに対し、こちらは委譲によるもの