Commandパターン

 

どうも。
最近、蒙古タンメンにハマりすぎて困っています。
麻婆麺が辛すぎて病みつきになります。

 

 

Commandパターン
を見ていきます。

Commandパターンの定義

リクエスト(命令)をオブジェクトとしてカプセル化し、
その結果、他のオブジェクトを異なるリクエスト、キュー
またはログリクエストなどでパラメータ化でき、
アンドゥ可能な操作もサポートする。
= リクエストをオブジェクトでカプセル化する。
= クライアントはいろんなリクエストを持つことができる。(→使える)

 

クラス図

縦長。。。

 

・Command
…全てのコマンド(オブジェクト)のためのインターフェースを定義する。

 

・ConcreteCommand
…Receiverとaction()の結びつきを(execute()に)定義する。
Invokerがexecute()することで
ConcreteCommandへリクエストを行い、
ConcreteCommandがReceiverの
1つ以上のaction()を呼び出すことでそれを実行する。

 

・Invoker
…コマンド(オブジェクト)を保持し、
ある時点でのコマンドのexecute()を呼び出すことで
コマンド(オブジェクト)にリクエストを実行するよう依頼する。
様々なコマンド(オブジェクト)をパラメタ化して保持できるが、
具体的なコマンド(オブジェクト)の内容は知らない。
(Commandインターフェースを実装している何かだと知っている程度)

 

・Receiver
…制御されるもの(制御対象)

・Client

 

具体的に…

この章でのは
「複数の電化製品のon/offを制御できるリモコン」
でした。

 

PHPで書いたみたコード

 

・Command
…制御したい命令を定義するインターフェース

・LightOnCommand / LightOffCommand [ConcreteCommand]
…具体的に制御対象であるライトの
制御(点けたり消したりする)方法がここにある

・RemoteControl [Invoker]
…制御対象(Receiver)をsetCommandで設定したり、
実際に制御するコントローラー
複数の制御対象をセットできる。

・Light [Receiver]
…制御対象となるライト

・RemoteLoader [Client]

 

いいところ

Invoker(RemoteControl)自体が
制御するReceiver(Light)を知っている場合、
Receiverが増えるたびに、if文で追記する形になってしまう。

RemoteControl.php

  if($receiver == 'Light') {
   $receiver.on();

  } else if($receiver == 'Door') {

   $receiver.open();

- }
+ //制御対象「Sprinkler」の追加
+ } else if($receiver == 'Sprinkler') {
+
+  $receiver.waterOn();
+
+ }

 


↓ Commandパターンを使うと…

 

Invoker(RemoteControl)は
具体的なコマンドオブジェクトの内容を知らずして
(インターフェスは知ってる)、
コマンドオブジェクトに具体的な処理(制御)を依頼できるので、
Invoker(RemoteControl)とReceiver(Light)を分離することができる。
= 各々の役割分担ができる。

RemoteControl.php
※Receiver(LightやDoorなど)について全く出てこない。

use HFD\Command\Command\Command;
use HFD\Command\Command\NoCommand;

class RemoteControl
{
    /**
     * @var Command[]
     */
    public $onCommands;

    /**
     * @var Command[]
     */
    public $offCommands;


    public function __construct(int $commandCnt)
    {
        for ($i = 0; $i < $commandCnt; $i++) { $this->onCommands[] = new NoCommand();
            $this->offCommands[] = new NoCommand();
        }
    }

    public function setCommand(int $slotNum, Command $onCommand, Command $offCommand): void
    {
        $this->onCommands[$slotNum] = $onCommand;
        $this->offCommands[$slotNum] = $offCommand;
    }

    public function onButtonWasPushed(int $slotNum): void
    {
        $this->onCommands[$slotNum]->execute();
        $this->undoCommand = $this->onCommands[$slotNum];
    }

    public function offButtonWasPushed(int $slotNum): void
    {
        $this->offCommands[$slotNum]->execute();
        $this->undoCommand = $this->offCommands[$slotNum];
    }
}

 
制御対象が増える可能性がある時の
拡張性を考えた時に良さそうなパターンですね!
 

 

 

 

 

Factoryパターン〜AbstractFactory〜

Head FirstのFactoryパターンの
例え話が「ピザ屋」のお話だったので、
すんごいピザが食べたくなり、ピザホール一人で食べました。
やっぱりマルゲリータですよね。
んで、追いオリーブオイル。

 

Factoryパターン一族

– Simple Factory[正確にはFactoryパターンではない]
– Factory Method
– Abstract Factory

今回は最後のAbstract Factoryについてです!

 Abstract Factory

オブジェクトを作成をカプセル化し、依存度を下げる。(Factory Methodと同じ)
FactoryMethodと異なり、オブジェクトコンポジションを使います。

具象クラスを指定することなく、
一連の関連オブジェクトや依存オブジェクトを作成するための
インターフェースを提供する。

→ 使い手は、抽象インターフェースを使って、
実際に作成される具体的な製品を知ることなく、
一連の製品を作成できる。

いいところ:
使い手は、具体的な製品の詳細から完全に分離されます。
→ 役割分担できて、個々のクラスの責任が小さくなる

 

クラス図はこんな感じ

 

 

Head Firstでは、
– 工場:ピザの食材を作る食材工場
– 製品:ピザの食材
を例としていました。

こんな感じ(PHPStormのクラス図作れるの教えてもらったので、早速)

PizzaIngredientFactoryクラスで、
関連する一連の食材(Dough, Sauce, Cheese, …)オブジェクトを
まとめてグループ化して作れるのがいいところです。

 

AbstractFactoryのサンプルコード

 

▶︎ PizzaIngredientFactory  ←抽象的な食材工場

interface PizzaIngredientFactory
{
    //実装クラスにピザの食材(製品)の作成方法は任す。
    public function createDough(): DoughInterface;
    public function createSauce(): SauceInterface;
    public function createCheese(): CheeseInterface;
       ...
}

 

▶︎ NYPizzaIngredientFactory (PizzaIngredientFactoryの実装クラス)

↑具象な食材工場

class NYPizzaIngredientFactory implements PizzaIngredientFactory
{
    //具体的なピザの食材(オブジェクト)を作成する。
    public function createDough(): DoughInterface
    {
        return new ThinCrustDough();
    }

    public function createSauce(): SauceInterface
    {
        return new MarinaraSauce();
    }
...

 

▶︎ DoughInterface ←抽象的な食材

interface DoughInterface
{
    public function getName(): string;
}

 

▶︎ ThinCrustDough (DoughInterfaceの実装クラス)

↑具象な食材

class ThinCrustDough implements DoughInterface
{
    private $name;

    public function __construct()
    {
        $this->name = "うっすい生地";
    }

    public function getName(): string
    {
        return $this->name;
    }
}

 

 

ただし、食材が追加された時
Product(MeetInterface, Bacon)の追加だけでなく、
PizzaIngredientFactoryと
PizzaIngredientFactoryを実装する全てのクラスを変更する必要があります。
→影響範囲が大きめです。

例: 肉(食材)を追加する場合

– PizzaIngredientFactory

interface PizzaIngredientFactory
{
    //実装クラスにピザの食材(製品)の作成方法は任す。
    public function createDough(): DoughInterface;
    public function createSauce(): SauceInterface;
    public function createCheese(): CheeseInterface;
   ...
+   public function createMeet(): CheeseInterface;
}

– NYPizzaIngredientFactory

class NYPizzaIngredientFactory implements PizzaIngredientFactory
{
    ...
+   public function createMeet()
+   {
+       //MeetInterfaceの実装クラスをインスタンス化する
+       return new Bacon();
+   }
}

 

 

 

ある程度、固定された一連のオブジェクトがあって、
それらを作成する必要がある時に使えそうですね。

 

 

Factoryパターン〜FactoryMethod〜

そこに、Factoryパターン一族

– Simple Factory[正確にはFactoryパターンではない]
– Factory Method
– Abstract Factory
の章があったので、
ぜひアウトプットしたく書きます!

今回はFactory Methodについてです!

Factory Method

オブジェクトを作成をカプセル化し、依存度を下げるために使います。
(Simple Factory、Abstract Factoryと同じ)

オブジェクト作成のためのインターフェースを
抽象クラス(スーパークラス)に定義しますが、
どのクラスをインスタンス化するかについてはサブクラスに決定させます

→抽象クラス(親クラス)は、
サブクラスの作成したオブジェクトを利用するだけで
具体的なオブジェクトが何なのかを知らない。

AbstractFactoryと違う部分
– 継承を使うので、サブクラス(子クラス)が
作成するオブジェクトの具体的な型を実装する。

 

クラス図でみるとこんな感じ

 

factoryMethodはサブクラスに任せるために、
Factoryクラス(スーパークラス)は抽象クラスになる。

クラス図からもわかるように、
Factoryクラス(スーパークラス)は
Prodoctオブジェクトを作成する具体的な方法は全く知りませんが、
factoryMethodを使えばProdoctオブジェクトを作成できることを知っています。
なので、anOperationメソッド内でfactoryMethodを使用することが多いです。

 

 

HeadFirstでは、
地域スタイルでピザの作り方が異なる
フランチャイズでの例がありました。

FactoryMethodのサンプルコード

 

クラス図はこんな感じ。

 

▶︎ PizzaStore(スーパークラス)
Pizzaオブジェクトを作成する具体的な方法は全く知りませんが、
createPizzaメソッドを使えばPizzaオブジェクトを作成できることを知っています。
→orderPizzaメソッド内でcreatePizzaを使用して実装している。

▶︎ NYPizzaStore(PizzaStoreのサブクラス)
具象Pizza(NYスタイル)オブジェクトを作成する

▶︎ChicagoPizzaStore(PizzaStoreのサブクラス)
具象Pizza(Chicagoスタイル)オブジェクトを作成する

▶︎ Pizza
抽象Pizzaクラス。
PizzaStoreのサブクラスにより、具象Pizzaオブジェクトが作成される。

└ NYCheesePizza 具象Pizzaクラス
└ NYClamPizza 具象Pizzaクラス
└ ChicagoCheesePizza 具象Pizzaクラス
└ ChicagoClamPizza 具象Pizzaクラス

 

メリット1:
地域ごとにピザメニューの作り方が異なっても大丈夫

地域ごとの具象PizzaStoreクラス、具象Pizzaクラスがある。
そのため、同じチーズピザでも、
NY店はゴーダチーズ、Chicago店はモッツアレラチーズにしたり
切り方はサブクラスでオーバライドするなど
多種多様に対応することができる。

 

メリット2:
ChicagoにあるけどNY出身者が多い地区のピザ屋にも対応可能

こんなクラスを作ればいい。
– ChicagoPizzaStore_ManyNewYorker.php

class ChicagoPizzaStore_ManyNewYorker extends PizzaStore
{
    public function createPizza(string $type): object
    {
        $pizza = null;
        if ($type == "チーズ(NY風)") {
            $pizza = new NYCheesePizza();
        } else if ($type == "チーズ(Chicago風)") {
            $pizza = new ChicagoCheesePizza();
        } else if ($type == "野菜(NY風)") {
            $pizza = new NYVeggiePizza();
        } else if ($type == "野菜(Chicago風)") {
            $pizza = new ChicagoVeggiePizza();
        }

        return $pizza;
    }
}

 
ピザ食べたくなりました。
やっぱりマルゲリータですよね。

 
 

Factoryパターン〜Simple Factory〜

この前、domicoのライブが宮崎であるというレアな事象ありました。
行かないわけにはいかないので、行ってきました。
めっちゃ、カッコ良いかったです。

 

早速ですが、私「増補改訂版Java言語で学ぶデザインパターン入門
を読んでますが、並行して楽しく読めると噂のこれも読んでいます。

そこに、Factoryパターン一族

– Simple Factory
– Factory Method
– Abstract Factory

の章があったので、
ぜひアウトプットしたく書きます!

今回はSimpleFactoryについてです!

Simple Factory

正確にはFactoryパターンではない!ですが便利なやつです。

サブクラスが複数存在する場合、
if文などで、各サブクラスをインスタンス化する
→ アプリケーション部分の各部分にif文が分散してしまったり、
保守と更新が困難になったり、実装の間違いが多くなるという問題があります。

 

したがって、
アプリケーション内で、
インスタンス化する部分(変化する部分)と変化しない部分
を分けてカプセル化する
というのがSimpleFactoryです。

 

SimpleFactoryのサンプルコード

こんなな感じかと思います。

 

上記でいうと、SimplePizzaFactory = SimpleFactoryになります。

 

▶︎PizzaStore

SimplePizzaFactoryのクライアント。
ピザをインスタンス取得しますが、
「ギリシャピザやクラムピザなどの具象ピザ」については知る必要がありません。
「pizzaインターフェースを実装したピザ(具象ピザ)を取得し、
prepareメソッド,bakeメソッド,…を呼び出せる」ことを知ってるだけで良い。
ピザを取得する事に関しては、SimplePizzaFactoryに任せるだけでOK!

 

▶︎SimplePizzaFactory

SimpleFactoryの主役。
ピザをの作成方法だけを扱うクラス。
具象Pizzaクラスを参照する唯一の部分。

 

▶︎Pizza

SimplePizzaFactoryの製品であるPizzaの抽象クラス。
具象ピザはこれを実装する。

└ VeggiePizza   具象ピザ(具象製品)
└ PepperoniPizza 具象ピザ(具象製品)
└ ClamPizza    具象ピザ(具象製品)
└ CheesePizza   具象ピザ(具象製品)

新作ピザの追加、ピザメニューの削除があっても。。。

大丈夫!

SimplePizzaFactory.php

- use HFD\SimpleFactory\Pizza\PepperoniPizza;
  use HFD\SimpleFactory\Pizza\ClamPizza;
  use HFD\SimpleFactory\Pizza\VeggiePizza;
+ use HFD\SimpleFactory\Pizza\GreekPizza;

function createPizza(string $type): object
{
        $pizza = null;
        if ($type == "チーズ") {
            $pizza = new CheesePizza();
-       } else if ($type == "ペパロニ") {
-           $pizza = new PepperoniPizza();
        } else if ($type == "クラム") {
            $pizza = new ClamPizza();
        } else if ($type == "野菜") {
            $pizza = new VeggiePizza();
+       } else if($type == "ギリシャ"){
+           $pizza = new GreekPizza();
        }

GeekPizza.php(新作ピザ)

+namespace HFD\SimpleFactory\Pizza;
+
+
+class GreekPizza extends Pizza {
+
+    public function __construct() {
+        $this->name = "ギリシャピザ";
+    }
+
+}

 

ピザの作成を
SimplePizzaFactoryに任せてるので、
SimplePizzaFactoryの修正と
新作ピザクラス(具象ピザ)の追加のみで対応できる。
さらに、PizzaStoreと分けているので
PizzaStoreには影響が少ない!

 

なによりシンプルでわかりやすいですね。

次は、FactoryMethodについて書きたいと思います!

Singleton(シングルトン)を使ってみる

 

今回は、ご存知デザパタの
第5章 Singleton 〜たった一つのインスタンス〜
について自分なりにまとめたいと思います。

 

シングルトンって音がかわいいですよね、「トン」とかがw

シングルトン(Singleton)とは

何も考えず、実装をしているとなんども同じインスタンスを生成しがちです。
・指定したクラスのインスタンスが絶対1つしか存在しないことを保証したい
・インスタンスが1つしか存在しないことを、プログラム上で表現したい

そんなときに、インスタンス生成コストを下げるためにも、
Singletonパターンを使います。

 

参考:
PHPで書き換えてくれてるソース
https://github.com/HappyDays-jQuery/GoF/tree/master/src/Singleton

 

 

こんな感じ

全体コード→https://github.com/kin29/DezaPata/pull/4/files

– Singletonクラス
– コンテキスト(使う側)

Singletonクラス

<?php

namespace DP\Singleton;

class Singleton
{
    /**
     * @var Singleton
     */
    //static宣言がされているため、
    //クラスのインスタンス化の必要なしにアクセスできる。
    //ただしprivateなので同クラス内のからしかアクセスできない
    private static $singleton;

    //privateなので、同クラス内からしかインスタンス生成をできない。
    //他のクラスからnew Singletonをするとエラーになる。
    //このクラスではgetInstanceがインスタンス生成をしている。
    private function __construct()
    {
        echo "create SingletonClassInstance\n";
    }

    //すでに$singletonにインスタンスがセットされている場合は、newしない。
    public static function getInstance()
    {
        //$singletonがstatic宣言されているため、
             //$this->singletonでアクセスできない。
        if (is_null(self::$singleton)) {
            self::$singleton = new Singleton();
        }
        return self::$singleton;
    }
}

 

 

contextSingleton.php ←コンテキスト(使う側)

<?php

use DP\Singleton\Singleton;

echo "Singletonクラスを普通にnewしてみる。\n";
new Singleton(); //たぶんおこられる。

外部クラスからnewすると
Singleton::__construct()がprivateなので怒られます。

$ php contextSingleton.php

Singletonクラスを普通にnewしてみる。
PHP Fatal error: Uncaught Error: Call to private DP\Singleton\Singleton::__construct() from invalid context in /Users/XXXXX/DezaPata/contextSingleton.php:10
Stack trace:
#0 {main}
 thrown in /Users/XXXXX/DezaPata/contextSingleton.php on line 10

 

 

contextSingleton.php ←コンテキスト(使う側)

<?php

use DP\Singleton\Singleton;

echo "getInstanceしてみる(instance1)\n";
$instance1 = Singleton::getInstance();
echo "もう一度、getInstanceしてみる(instance2)\n";
$instance2 = Singleton::getInstance();
echo "2回目のgetInstanceはインスタンス生成を行わないため、constructを通らないはず\n";
echo "(instance1 === instance2)なのか確認\n";
echo ($instance1 === $instance2) . "\n";

$ php contextSingleton.php

getInstanceしてみる(instance1)
create SingletonClassInstance
もう一度、getInstanceしてみる(instance2)
2回目のgetInstanceはインスタンス生成を行わないため、constructを通らないはず
(instance1 === instance2)なのか確認
1

Singletonクラスのインスタンスを得ることができるgetInsranceメソッドを
2回実行してみる。
1回目でインスタンス生成によりコンストラクラにて初期化でいを行い、
2回目はインスタンス生成していないことがわかる。
さらに、1回目と2回目のインスタンスは同じであることもわかる。

→ Singletonクラスは1つしか存在せず、
getInstanceで毎回同じSingletonクラスのインスタンスを得ることができました!!!

 

<<追記 2019-03-12>>

ただし、このままの方法ではタッチの差で、

if (is_null(self::$singleton))

判定をした場合には
インスタンスが1つ以上作られる可能性があります。

この対策としては二つがあります。
●同期化
●初期化時点でインスタンスを生成し、
getInstanceでは常にそのインスタンスを返すようにする。

class Singleton
{
    private static $singleton = new Singleton();

    private function __construct()
    {
        echo "create SingletonClassInstance\n";
    }

    public static function getInstance()
    {
        return self::$singleton;
    }
}

 

 

static宣言

HogeClass.php

class HogeClass
{
    public static $staticProperty = "staticなプロパティです。\n";

    public static function staticMethod()
    {
        return "staticなメソッドです。\n";
    }
}

 

staticなメソッド、staticなプロパティともに
インスタンス化せずとも外部からアクセスが可能である。

echo HogeClass::$staticProperty;  //staticなプロパティです。
echo HogeClass::staticMethod();   //staticなメソッドです。

 

HogeClass内からのアクセスもself::で行う。
$this->で行うと、エラーとなる。

PHP Fatal error: Uncaught Error: Using $this when not in object context in

 

※注意!

staticなプロパティはインスタンス化されたクラスオブジェクトから
アクセスすることはできない(static なメソッドにはアクセスできます)。

$HogeObj = new HogeClass;
echo $HogeObj->staticProperty;
//PHP Notice:  Accessing static property HogeClass::$staticProperty as non static in...
echo $HogeObj->staticMethod();   //staticなメソッドです。

 

 

イテレーターを(iterator)を使ってみる

 

今回は、ご存知デザパタの
第1章 Iterator 〜1つ1つ数えあげる〜
について自分なりにまとめたいと思います。

 

イテレーター(iterator)とは

何かの集合体を、数える人
→ 何かの集合体(=aggregate)つまり数える対象が必要
→ 何かの集合体(=aggregate)がいてこその役に立つ

参考:
PHPで書き換えてくれてるソース
https://github.com/HappyDays-jQuery/GoF/tree/master/src/Iterator

 

※PHPでは組み込みで複数のインターフェースがあるので便利!
Iteratorインターフェース
IteratorAggregateインターフェース ..など

何かの集合体(aggregate)と、それを数える人(iterator)を別クラスにすることで、
役割分担ができ、疎結合になる。
→ ただし、aggregateとiteratorを別にする必要がない場合は、
両方の役割をもつIteratorAggregateを使うこともできる。

 

こんな感じ

全体コード→https://github.com/kin29/DezaPata/pull/2/files

– Bookクラス
– BookShelfクラス(=aggregate)
– BookShelfIteratorクラス(=iterator)
– コンテキスト(使う側)

BookShelf(集合体)の中にBook(要素)があり、
BookShelfIteratorが本を一つ一つ数えていく感じです。

BookShelfクラス

<?php

/**
 * 何か(=本)の集合体[Aggregate]
 */
class BookShelf
{
....
    public function getIterator(): BookShelfIterator
    {
        return new BookShelfIterator($this);
    }
}

コンテキスト(使う側)

<?php 

$bookShelf = new BookShelf();
$bookShelf->appendBook(new Book('星の王子様'));
$bookShelf->appendBook(new Book('かいけつゾロリ'));
$bookShelf->appendBook(new Book('ミッケ!'));
$bookShelfIt = $bookShelf->getIterator();

while ($bookShelfIt->hasNext())
{
    echo $bookShelfIt->next()->getName() . "\n";
}

実行すると、appendした本の名前が入れた順番に1つずつ表示されます。

$ php contextIterator.php
星の王子様
かいけつゾロリ
ミッケ!

 

イテレータのいいところ

何かの集合体(=aggregate)や数え方(=iterator)を変更しても、
イテレータを使う側には変更の必要がない。

例)
変更前:数え方→集合体へ要素を追加した順番(FIFO)
変更前:数え方→集合体へ要素を追加した逆の順番(FILO)

<?php 

namespace DP\Iterator; 

/**
 * 何か(=本)の集合体を数える人[Iterator]
 *
 * Class BookShelfIterator
 * @package DP\Iterator
 */ 

class BookShelfIterator {

    private $bookShelf;
    private $index;
  
    public function __construct(BookShelf $bookShelf)
    { 
        $this->bookShelf = $bookShelf;
-       $this->index = 0;
+       $this->index = $this->bookShelf->getLength() - 1;
    }

    public function hasNext(): bool
    {
-       return $this->index < $this->bookShelf->getLength();
+       return $this->index >= 0;
    }

    public function next(): Book
    {
        $book = $this->bookShelf->getBookAt($this->index);
-       $this->index++;
+       $this->index--;
        return $book;
    }
}

実行結果

$ php contextIterator_FILO.php
ミッケ!
かいけつゾロリ
星の王子様

 

イテレータ、便利だしスマートですね!

しかし未だ、これイテレータパターン使えるっ
って言う場面に直面したことがないので、
何か集合体を見つけては、ソースに落とし込むとかして
そういう直感を養っていこうと思います。

デザインパターン入門を読み始めました。〜GoFとは〜

 

有名なやつですね。

存在はもちろん知っていましたが、
難しそうという思い込みで読んでいませんでした。

読まなくては!といういい機会をいただき読み始めました。
入門なのもあり、Javaを知らない私でも意外に読める感じでした!
(思い込みはだめですね。)

 

PHPerな方が、この本と一緒によむといいのが、
デザパタをPHPで書いてくれてるやつ → HappyDays-jQuery/GoF

 

今回は、この本の導入部分のまとめを
自分なりに書いていきたいと思います。

 

GoF(ゴフ)とは

\「GoF」ってよく聞くけど、なんですか?/
という、私の初歩的な疑問がありました。
「はじめに」部分に詳しく書いてくれてました。

開発する上でのよくあるパターンを「デザインパターン」という形で整理したのが、
GoF(ゴフ)と呼ばれた4人だそうです。※GoF = the Gang of Fourの略

もっと詳しく言うと、このGoFにより
オブジェクト指向における再利用のためのデザインパターン
という本がかかれました。
この本では、23個のデザインパターンに「名前」をつけ、
「カタログ」としてまとめられています。

 

–まとめ–
GoF(ゴフ)とは、
デザインパターンを整理してくれた4人の人たちの名称。

 

デザインパターンを学ぶ前に

デザインパターンとは、クラスやインターフェースの関係性である。

デザインパターンの目的は、プログラムを再利用可能なものにすること。
→プログラムを部品として再利用すること
→プログラムを常に、機能拡張や変更を加えていくものとして見る必要がある。

なので、デザインパターンの理解を深めるためには以下を考えると良い。
・どんな機能が拡張される可能性があるか
・その拡張が行われると、修正が必要になるクラスはどれか
・逆に、修正が不要なクラスはどれか

 

また、役割を理解する必要がある。
この本では、デザインパターンをドラマに例えて整理しています。

– 白雪姫(というドラマ) … デザインパターン
– 白雪姫(登場人物) … クラスA
– 王子様(登場人物) … クラスB

白雪姫には、りんごを食べて永遠の眠りについてしまうという役目があるように、
クラスAは役割がある。
また、王子様には、白雪姫にキスをして目覚めさせるという役目があるように、
クラスBには役割がある。
白雪姫が眠らなければ王子様も役目を果たせないように、
し役割をまっとうする必要がある。
登場人物全員が役割を果たしてドラマができあがるように、
デザインパターンもできるという感じでしょうか。

 

次は、第1章Iteratorについてまとめたいと思います!

 

PHP7.3からbreakの代わりにcontinueを使うとWarningになる。

最近PHP7.3にしました!
すると、以下のエラーで大好きなcomposerが使えなくなりました。

 "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?  

Google翻訳さんを使って、
「continue」ターゲティングスイッチは「break」と同じです。 “continue 2″を使用するつもりでしたか?
的なことをいってるみたいだなとわかりました。

 

( 解決策はQiitaに書いてます! )

composer installができなくなった時の解決法(PHP7.3)

 

 

そこでまず、
▶︎PHP7.3から、continueをbreakの代わりに使うと、Warningになる?
▶︎continue 2とは?使ったことない!
と私は直感で思いました。

 

 

よくわからなかったので、

とりあえず、やってみます。

参考:https://blog.ohgaki.net/php-7-3#continue

$ php -v
PHP 7.3.1 (cli) (built: Jan 10 2019 13:15:37) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies

 

test_continue.php

<?php
//$month = 1;を想定

for ($day = 1; $day <= 31; $day++) {

    $message = "{$day}日は、";
    switch ($day) {
        case 1:
            $message .= "月初\n";
            continue;  //break;と同じらしい
        case 15:
            $message .= "月のど真ん中\n";
            continue;
        case 31:
            $message .= "月末\n";
            continue;
        default:
            $message .= "なんともいえない日\n";
            continue;
    }

    echo $message;
}

 

いざ、実行!

$ php test_continue.php 
PHP Warning:  "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /Users/kin29/php7_3/test_continue.php on line 11
...
/Users/kin29/php7_3/test_continue.php on line 14
...
/Users/kin29/php7_3/test_continue.php on line 17
...
/Users/kin29/php7_3/test_continue.php on line 20
1日は、月初
2日は、なんともいえない日
...
15日は、月のど真ん中
16日は、なんともいえない日
...
31日は、月末

やはり、warningでてますねえ。
おっしゃる通りにcontinue→breakにしてみる。

test_break.php

<?php

//$month = 1;を想定

for ($day = 1; $day <= 31; $day++) {

    $message = "{$day}日は、";
    switch ($day) {
        case 1:
            $message .= "月初\n";
            break;  //continue;と同じ動作をするはず
        case 15:
            $message .= "月のど真ん中\n";
            break;
        case 31:
            $message .= "月末\n";
            break;
        default:
            $message .= "なんともいえない日\n";
            break;
    }

    echo $message;
}

breakで実行すると、
warningも出ず、continueの時と同じ挙動のようです!!!

$ php test_break.php 
1日は、月初
2日は、なんともいえない日
...
15日は、月のど真ん中
16日は、なんともいえない日
...
31日は、月末

そもそも、switchには普段からbreak使ってます。
なんとなくcontinueを使わず、break使ってましたが、それが正しいようです。

ではcontinueの使い時は?continue 2とは?
の確信につきたいと思います。

 

test_continue_2.php

<?php 

//$month = 1;を想定

for ($day = 1; $day <= 31; $day++) {

    $message = "{$day}日は、";
    switch ($day) {
        case 1:
            $message .= "月初\n";
            break;
        case 15:
            $message .= "月のど真ん中\n";
            break;
        case 31:
            $message .= "月末\n";
            break;
        default:
            $message .= "なんともいえない日\n";
            continue 2; //抜けるループのレベル指定
    }

    echo $message;
}

 

さっそく実行!

$ php test_continue_2.php 
1日は、月初
15日は、月のど真ん中
31日は、月末

continueに引数を使うと、抜けるループレベルが指定できるようです。
今回の例でいくと、breakやcontinue(引数なし)ではswitch文しか抜けません。
ただし、continue 2(引数あり)とするとfor文からも抜けだすことができます。

 

まとめ

breakとcontinue(引数なし)は同じ意味なのに、別で存在しているので統一させたい。
あんど、continueは引数ありで使うべきと言いたいんでしょうか。
(そう私は解釈しました。)

短縮URL取得ボタンを記事編集画面に設置する。

 

わたし、ブログ書いたらTwitterに書いたよーって
宣伝してるんですが、その時のURLが長くてきもいって
言われたり思ってたりしてたので、
短縮URL取得ボタンを記事編集画面に設置しました。

なのでこの度、
\短縮URLをTwitterに貼れるようになりました!/

 

参考:https://tamore.net/add-shorturl-button/

 

before

 

after:パーマリンク横に「短縮URL取得」ボタンが追加されました!

 

●やり方

wp-content/themes/twentyfifteen/functions.php

の終了行に以下を追記するだけです!
わたしの場合、使用していたテーマがTwentyFiftyなのでtwentyfifteen/以下のfunction.phpをいじります。
ご使用のテーマに合わせてください。

/**
 * 「短縮 URL を取得」ボタンを編集画面に表示させる
 */
add_filter( 'get_shortlink', function( $shortlink ) {return $shortlink;});

 

wp-admin/edit-form-advanced.phpを見てみると、
「短縮URLの取得」ボタンはデフォルトで隠してるみたいですね。

wp-admin/edit-form-advanced.php

// As of 4.4, the Get Shortlink button is hidden by default.
if ( has_filter( 'pre_get_shortlink' ) 
    || has_filter( 'get_shortlink' ) ) {
   $shortlink = wp_get_shortlink($post->ID, 'post');

   if ( !empty( $shortlink ) 
        && $shortlink !== $permalink 
        && $permalink !== home_url('?page_id=' . $post->ID) ) {
      $sample_permalink_html .= '<input id="shortlink" type="hidden" value="' 
            . esc_attr( $shortlink ) 
            . '" /><button type="button" class="button button-small" onclick="prompt(&#39;URL:&#39;, jQuery(\'#shortlink\').val());">' 
            . __( 'Get Shortlink' )
            . '</button>';
   }
}

 

 

●感想

こんな簡単だったのかとびっくりしました。

ただ、Twitterカードの表示確認ツール「Card validator」で確認してみると、

WARMでてる・・・見逃していいやつですか・・・?

slackコマンドを作ってみた!

どうも、今週は#Webナイト宮崎でLTしてきました!
そのLTの内容を書きます!

にしても、connpassのプロフィールにLTする人の一覧がありますが、
自分のアイコン画像(Facebookの)が高校の時の写真なので
そろそろ変えないとですね

 

本題に入ります!

今回は、heroku(+SendGrid) +  PHP + slack
でslackコマンドを作ってみました。
ソースはこちら→[kin29/slack_command]

 

こんなslackコマンド

slackの投稿エリアにて、

/(設定したcommand) [メール件名]|[メール内容]

と入力し、エンターを押すと、

1. herokuサーバにキックされる。
2. herokuのadd-onであるSendGridから、メールを送信する。
送信先:WordPressメール投稿機能(プラグインPostie)で設定されたメールアドレス
2′. WordPress(ブログ)に記事が下書きの状態で投稿される。
3.メール送信結果を、slackに投稿する、

 

使ったもの

– Slack

– heroku
今回はPHP 7.2.12を使用しました。

– SendGrid…メール機能が使えるherokuのadd-onです。
freeプランがあり、最大12,000通/月送信することができます。
※herokuはデフォルトでメール機能が使えません。

 

作った理由

私はブログを週1は更新する!という目標があります。
そこで、ブログ(kin29.info)のネタを
忘れないうちに、サクッと貯めておきたかったので作りました。

slackで技術的なお話をしてる時や、
レビューの返しなどをもらった時に
「これ使える!」ってネタが思くので、
その時に使いどきかなって思います!

 

作り方

ソースはこちら→[kin29/slack_command]

 

1.heroku経由でSendGridを導入する。

  • herokuダッシュボードよりCreate new appを押下し、
    プロジェクトを作成します。
    プロジェクト名がサブドメインになります。
    イメージ:https://[プロジェクト名].herokuapp.com/
  • herokuダッシュボード > Resources > Add-onsにて、
    「SendGrid」を検索し導入する。
    Starter – Free(送信通数上限12,000通/月)を選択し、
    Provisionを選択。
  • SendGridダッシュボード > 左ナビのSettings > API Keys より
    「Create API Key」を押下する。
    ※API Keyはコピーしておく。

 

2.slack app を新規作成する。

https://api.slack.com/apps より、Create New Appを押下する。

  1. AppName と 導入するSlack Workspaceを選択する。
    ※Verification Tokenをコピーしておく。
  2. Slash Commands の設定
    – Command :設定したいslack コマンド
    – Request URL :commandが投稿された時に実行されるURL
  3. Install Appより、「Install App to Workspace」を押下する。
    → Incoming Webhookが設定されます。
    メール送信結果を投稿するslackチャンネルを選択し、
    投稿をAuthorize(許可)する。
    ※Webhook URL をコピーしておく。

 

3.heroku でデプロイ

  1. コードを書く → [kin29/slack_command]
  2. herokuダッシュボード > Setting > Config Varsより
    環境変数を設定する。
  3. herokuダッシュボード > Deploy よりデプロイする。
    Heroku Git(Githubでもできます。)
    $ git push heroku master  //これでデプロイされます。
  4.  

    4.Postie(WordPressプラグイン)を導入し、メール投稿設定をする

    Postieは、WordPressのプラグインです。
    これにより、メール投稿を使って
    Wordpressに記事を投稿することができます。

    参考:http://nb-style.info/?p=3072

     

    !!完成!!

     

    最後に

    もっともっとslackコマンドつくって、
    作業時短化や自動化していきたいです!