孤独プログラマー譚

孤独死が近い。

Rubyでクロージャ

JavaScriptでよく見るクロージャを、Rubyでもやってみる。

JavaScript 関数スコープ
・内側から外側の変数は利用できる。
・外側から内側の変数は利用できない。

Ruby ブロックスコープ
・内側から外側の変数は利用できる。
・外側から内側の変数は利用できない。

JavaScriptの場合、関数スコープを利用して、クロージャを実装する。
Rubyの場合、ブロックスコープを利用して、クロージャを実装する。


Procオブジェクトを返す関数を定義する場合。

def createCounter
  num = 0
  Proc.new do
    num += 1
    p num
  end
end

counter = createCounter

counter.call # 1
counter.call # 2
counter.call # 3
counter.call # 4
counter.call # 5


ProcオブジェクトからProcオブジェクトを返す場合。

createCounter = Proc.new do
  num = 0
  Proc.new do
    num += 1
    p num
  end
end

counter = createCounter.call

counter.call # 1
counter.call # 2
counter.call # 3
counter.call # 4
counter.call # 5


クロージャをあまり実務で使ったことない。もっと積極的に使おう。

Ruby Procを触る

引数にブロックを取る関数。

def doSomething(something, &toDo)
  toDo.call(something)
end

PHP = 無名関数
Ruby = ブロック
という考え方で良いと思う。

以下、do から end がブロック。
Rubyでは、ブロックも引数の一種に考えるイメージだろうか。

doSomething 'メロン' do |food|
  p food << 'を食べる'
end

メロンを食べる

ではそのブロック(無名関数)を変数に入れたい場合はどうするか。
Procオブジェクトとしてラッピングする必要がある。

def doSomething(something, toDo)
  toDo.call(something)
end

eatFood = Proc.new do |food|
  p food << 'を食べる'
end

doSomething 'リンゴ', eatFood

リンゴを食べる

こっちは、doSomethingの引数toDoに「&」が無い。

# ブロックを渡す場合
def doSomething(something, &toDo)
# Procオブジェクトを渡す場合
def doSomething(something, toDo)

この「&」は、普通のブロックをProcオブジェクトに変換している…らしい。

Procを制する者がRubyを制す(嘘)

Procオブジェクト。まだよく分からないが、ここらへんを理解できると、後々楽になりそうな気がする。

PHP Proxyパターンを楽に実装する

Proxyパターンは有用である。最近知ったから使ったことないけど。

例えば、以下、RobotクラスとMissileクラス。
ロボットクラスは、ミサイルの発射をミサイルクラスに委譲している。

<?php
class Robot
{
    function __construct()
    {
        $this->missile = new Missile();
    }

    function launchMissile()
    {
        $this->missile->fire();
    }
}

class Missile
{
    public function fire()
    {
        echo '発射!';
    }
}

$robot = new Robot();
$robot->launchMissile();

発射!


しかし、ただ発射するだけでは地味なので、おっぱいからミサイルを発射するように改造したとする。

<?php
class Robot
{
    function __construct()
    {
        $oppai = new Oppai();
        $oppai->missile = new Missile();
        $this->missile = $oppai;
    }

    function launchMissile()
    {
        $this->missile->fire();
    }
}

class Oppai
{
    public function fire()
    {
        echo 'おっぱいミサイル';
        $this->missile->fire();
    }
}

おっぱいミサイル発射!


Missileクラスを一切触っていない。
実行元なる Robot::launchMissile にも一切手を加えていない。
このように、共通のインターフェイスを持つ中間層のクラスを差し込むことで、色々と応用を利かせることが出来る。

ただ、問題点がある。
Missileクラスが100個メソッドを持っていれば、Oppaiクラスにも同名のメソッドを100個用意する必要がある。

でも大丈夫。

<?php
class Oppai
{
    public function __call($name, $args)
    {
        echo '超おっぱいミサイル';
        $this->missile->{$name}($args);
    }
}

超おっぱいミサイル発射!


PHPには、__call() というマジックメソッド(と呼ばれる特殊なメソッド群)が存在する。
存在しないメソッド名が呼ばれると、この __call() が実行される。

これで、面倒なProxyパターンも気軽に使っていける。

JavaScript ツリー構造はCompositeパターン

ツリー構造といえばあれだ。

営業部
┗ 1課
 ┗ 山田
 ┗ 鈴木
┗ 2課
 ┗ 佐藤

みたいになってるやつ。

デザインパターンには、このツリー構造をうまく処理できる「Compositeパターン」というものがある。

だが、ツリー構造自体、扱う機会が特に無かったので、Compositeパターンの存在を忘れていた。

「営業部」のようなグループは、中にさらにグループ(1課とか)、あるいは個人(山田とか)を格納できる。
しかし、個人はそれ以上何も格納できない。

以下、グループ・個人共通のインターフェイス

function Component(name) {
  this.children = []
  this.name = name
}
Component.prototype.add = function (child) {
  this.children.push(child)
  return this // メソッドチェーン用
}
Component.prototype.showName = function (indent) {
  var indent = indent || ''

  console.log(indent + this.name)

  indent = indent + '  ' // 子要素の表示はインデントを追加

  for (var i = 0; i < this.children.length; i++) {
    this.children[i].showName(indent)
  }
}

以下、グループを表すクラス。Componentを継承している。

function Composite(name) {
  Component.apply(this, arguments)
}
Composite.prototype = Object.create(Component.prototype)
Composite.prototype.constructor = Composite

以下、個人を表すクラス。同じく、Componentを継承している。
addメソッドは、利用不可になるようオーバーライドしている。

function Leaf() {
  Component.apply(this, arguments)
}
Leaf.prototype = Object.create(Component.prototype)
Leaf.prototype.constructor = Leaf
Leaf.prototype.add = null

ツリー構造を作成して表示。

;(new Component('Sony Music')).add(
  (new Component('乃木坂46')).add(
    new Leaf('白石麻衣')
  ).add(
    new Leaf('西野七瀬')
  )
).add(
  (new Component('欅坂46')).add(
    new Leaf('平手友梨奈')
  ).add(
    new Leaf('長濱ねる')
  )
).showName()

Sony Music
 乃木坂46
  白石麻衣
  西野七瀬
 欅坂46
  平手友梨奈
  長濱ねる

うーん、ツリー構造自体、必要になる機会が無い。出番無いかも…。

JavaScript Decoratorパターン

Decoratorパターンの良いところは、
主体となるオブジェクトと、処理を委譲しているオブジェクトの間に、スッと割り込ませることが出来ること。
そして、その処理を委譲しているオブジェクトには、傷をつけなくて済む。

Decoratorでラッピングするか否か、動的に決めることも出来る。

処理を付け足したり、付け足さなかったり…そんな時に使えるかも。使いたい。けど使いにくい。

function Component() {
  this.showNumber = function () {
    console.log(2)
  }
}

function Decorator(component) {
  this.component = component

  this.showNumber = function () {
    console.log(1)
    this.component.showNumber()
    console.log(3)
  }
}

var decorator = new Decorator(new Component())
decorator.showNumber()

1
2
3


Componentの処理のど真ん中に、Decoratorからの処理を埋め込みたい…そんな時もあるかもしれない。

function Component() {
  this.showNumber = function () {
    console.log(2)
    this.decorator.showInnerNumber()
    console.log(4)
  }
}

function Decorator(component) {
  this.component = component
  this.component.decorator = this

  this.showNumber = function () {
    console.log(1)
    this.component.showNumber()
    console.log(5)
  }

  this.showInnerNumber = function () {
    console.log(3)
  }
}

var decorator = new Decorator(new Component())
decorator.showNumber()

1
2
3
4
5

DecoratorはComponentを持ち、ComponentもDecoratorを持つ。お互いに委譲し合っている。
イマイチかもしれない。急遽、応急処置が必要な時に使おう。

ループの中のif文が現れたら、Observerパターンを検討する

やはり自分はObserverパターンを理解していなかった。

Observerパターンは、多種多様な輩をループで回す時、真価を発揮する。

以下、よく見るケース。JavaScriptで。

function Student(name, sex) {
  this.name = name
  this.sex = sex
}

var students = [
  new Student('野比のび太', 'boy'),
  new Student('源静香', 'girl'),
  new Student('剛田武', 'boy'),
  new Student('骨川スネ夫', 'boy')
]

for (var i = 0; i < students.length; i++) {
  if (students[i].sex === 'boy') {
    console.log('ムフフ、女子の着替え覗いちゃおうかなぁ。')
  } else if (students[i].sex === 'girl') {
    console.log('変態男子!ケダモノ!')
  }
}

ムフフ、女子の着替え覗いちゃおうかなぁ。
変態男子!ケダモノ!
ムフフ、女子の着替え覗いちゃおうかなぁ。
ムフフ、女子の着替え覗いちゃおうかなぁ。

ループの中にif文。分岐が多いのは良くない。
これがネストしたり、else if が何個も続くと、見てるだけで気分が悪くなってくる。

こういう時は、Observerパターンを使う。

function Boy() {
  Student.apply(this, arguments)
}
Boy.prototype.say = function () {
  console.log('ムフフ、女子の着替え覗いちゃおうかなぁ。')
}

function Girl() {
  Student.apply(this, arguments)
}
Girl.prototype.say = function () {
  console.log('変態男子!ケダモノ!')
}

var students = [
  new Boy('野比のび太', 'boy'),
  new Girl('源静香', 'girl'),
  new Boy('剛田武', 'boy'),
  new Boy('骨川スネ夫', 'boy')
]

for (var i = 0; i < students.length; i++) {
  students[i].say()
}

ムフフ、女子の着替え覗いちゃおうかなぁ。
変態男子!ケダモノ!
ムフフ、女子の着替え覗いちゃおうかなぁ。
ムフフ、女子の着替え覗いちゃおうかなぁ。

最後のfor文からifが消えた。

Observerパターンが実はとんでもない汎用性があることに今さら気付いた。

デザインパターンは言語を跨いで活用できるから、学習のコスパが良い!

Javascript 関数のデフォルト値設定の罠

今まで何気なくやってた、関数のデフォルト値設定。

function foo(a) {
  var a = a || 1;
  ...
}

実は愚かな行動だったと知った。

JavaScriptの「&&」「||」について盛大に勘違いをしていた件 - Qiita

例えば、

foo(0); // 1

引数が 0 や false の場合、意図どおりに動作しない。

以下のようにしてやればOK。

// 1
typeof a === 'undefined' && (a = 1)
// 2
if (typeof a === 'undefined') a = 1;
// 3
a = typeof a !== 'undefined' ? a : 1;

実はJavascript、「短絡評価」をできる、数少ない過激な言語だったと知った。

論理演算子(&&, ||)の短絡評価 - Qiita

そこで、すべてのif文は、and or に書き換えられるのでは…、と危険な思想が頭をよぎった。

例えば、

if (a === 1) {
  console.log(1);
} else if (a === 2) {
  console.log(2);
} else {
  console.log('unknown');
}

個人的には、else if とか大っ嫌い。

以下のように書き換えられるか?

a === 1 && console.log(1) || a === 2 && console.log(2) || console.log('unknown')

うーん、console.log()の関数実行部分が、true を返すか、false を返すかで、挙動が変わってしまう。

いまいちだが、以下のような関数を定義した。

function t() {
  return true;
}
function f() {
  return false;
}

&& に続く関数は、絶対に true としたい。
|| に続く関数は、絶対に false としたい。

a === 1 && t(console.log(1)) || a === 2 && t(console.log(2)) || console.log('unknown')

一応、意図した動作になってるっぽい。

独自関数をグローバルに定義してるのはキモいので、何とかするとして、

この Javascript の過激な仕様に感激した。

もともとイカれた(改め、クセの強い)言語だと思っていたが、そこを遥か超えてきやがった。すげぇ。