02 Jan 2015, 17:13

conkeror の 黒背景 & ダークテーマ で 目に優しいクールなブラウザをつかおう!

はじめに

ブラウザは conkeror を 利用しています.

今回, 黒背景と黒テーマを偶然にも発見した.

設定したらあまりにもカッコ良かったのでメモする.

黒 Google 検索

白い Google 検索が嫌いだった. 待ってたよ, Dark Google!!

黒背景

ここで手に入る. https://github.com/scottjad/dotfiles/blob/master/.conkerorrc/color-theme.js

カスタマイズを解説した動画もある.

.conkerorrc に color-theme.js に取得した color-theme.js を配置する.

黒テーマ (zenburn)

ここで手に入る.

.conkerorrc/themes/ にチェックアウトした.

.conkerorrc ディレクトリ配下の *.js に以下を.

theme_load_paths.unshift ("~/.conkerorrc/themes/");
theme_unload ("default");
theme_load ("conkeror-theme-zenburn");

02 Jan 2015, 15:41

2015 年の書き初め! Emacs Lisp をはじめて書いてみた

はじめに

今年の目標は, Emacs Lisp がかけるようになること.

というわけで, 新年早々, Emacs Lisp をはじめて書いてみた.

書き初めみたいな. ちなみに, 初夢はなにもみなかった.

はじめて??

はじめて というと, 正確にはウソ.

今までは他人の書いた Code をコピペしたり, 部分的に書き換えたりしながらつかってきた.

今回は, コピペではなく, 文法を理解しつつ書いたという意味で, はじめて.

文法の勉強

まずは, 文法を知らないとなにもできないので,

以下の本のはじめのほうを読む.

書いたもの

もちろん, 他の人の書いたものをベースにして書いた.

ERC で キーワード が呼ばれたら, Growl で通知

Linux では erc-nick-notify があるのだけれども, Windows 環境で 通知する elisp がなかったので,つくってみた.

つくってみたのだが, テストできないので, テストしていないという…

元ネタはこれ.

Windows 環境での Growl の設定は以下を参考にした.

Growl を利用すると, Alt+x, Alt+Shift+x が利用できなくなるという 致命的な問題がある. なんと, M-x が利用できない!

%USERPROFILE%\Local Settings\Application Data\Growl\2.0.0.0\user.config

で Alt+X とかいてあるところをべつのものに修正すればいい.

つくったもの

というわけで, 作成したのは以下.

初仕事は会社で elisp のデバッグだ!!

休憩時間をタイマーではかる

休憩時間に休憩中というメッセージを画面に表示して, 休憩時間を計測する elisp.

こんな感じ.

以下を参考にした.

つくったもの

02 Jan 2015, 10:41

Emacs での eval について調べてみた

はじめに

Elisp を評価 (eval) する方法について調べてみました.

代表的なコマンド

以下の 3 つが代表的.

  • eval-buffer バッファを評価
  • eval-region リージョンを評価
  • eval-last-sexp C-x C-e 最後のかっこを評価

参考:

インタラクティブに評価

こんな感じや, こんな感じに,

片方のウィンドウで評価したら別のウィンドウで動作させたいので, 以下の関数を書いてみた.

(defun my-inf-elisp ()
  (interactive)
  (eval-buffer)
  (if (one-window-p)
    (split-window))
  (other-window 1)
  (eshell)
)
(define-key emacs-lisp-mode-map (kbd "C-c S") 'my-inf-elisp)

01 Jan 2015, 14:54

SKK サーバを利用して Linux 環境で 親指シフト&Google 日本語入力ができた!

はじめに

Google 日本語入力がもっとも変換にすぐれているとおもう. mozc を利用したいところなのだけれども, 自分には mozc をつかえない致命的な問題があった.

それは・・・ 親指シフトに対応していないこと

Windows 環境では, GoogleIME + やまぶきの組み合わせで実現できていた. Linux 環境での IME は, ibus-anthy を利用していた.

しかし, 今日でそれもおわりだ! Linux 環境でも Google 日本語入力をする方法を偶然にも発見してしまった.

それは,SKK を利用するというワザ.

SKK とは

SKK は, IME の一種.

導入手順は過去記事を参照. 親指シフトにも対応している.

SKK Server で Google 日本語入力サーバにアクセスする

SKK Server という機能を利用すると, Google 日本語入力サーバにアクセスすることができる.

ローカル PC で SKK サーバを動かして, 日本語入力サーバにアクセスすることで, 親指シフト入力が出来るようになる.

install

gem install google-ime-skk

install できたら, google-ime-skk を実行する.

ddskk の設定

IP を設定してアクセスする.

(require 'skk-server)
;; 辞書サーバを利用する場合の設定
(setq skk-server-host "0.0.0.0"
      skk-server-prog "google-ime-skk" ;; パスは通っているようだ.
      skk-server-portnum 55100)

;; 辞書サーバが使用不能になると辞書ファイルを 
;; Emacs のバッファに読み込んで 検索を行う.
(setq skk-server-inhibit-startup-server nil) ;; 通信エラー時はローカル辞書を.
(setq skk-server-jisyo "~/.emacs.d/dic/SKK-JISYO.L")

(add-to-list 'skk-search-prog-list
         '(skk-server-completion-search) t)
(add-to-list 'skk-search-prog-list
         '(skk-comp-by-server-completion) t)

;; 一応手動で起動する手段を用意するが, 起動は OS 側で実施する予定
(defun my/boot-skk-server ()
  "Start SKK server"
  (interactive)    
  (unless (skk-server-live-p)
    (async-shell-command skk-server-prog (get-buffer-create "*google-ime-skk*"))
    (setq skkserv-process (skk-open-server-1))
    (when (skk-server-live-p)
      (set-process-coding-system skkserv-process 'utf-8 'utf-8))))

(defun my/skk-close-server ()
  (interactive)
  (when (skk-server-live-p)
    (skk-disconnect-server)
    (kill-process (get-buffer-process "*google-ime-skk*"))
    (message "Server disconnected")))
(add-hook 'kill-emacs-hook 'my/skk-close-server)

おわりに

以前の記事にも書いたのだけれども, どうも SKK の打鍵方法と NICOLA は相性が悪い気がする. 文節のあたまで打鍵をする必要があるため, いままでに比べて打鍵数が増えているきがするのだ.

まだ慣れていないだけの問題なのだろうか??

しばらく様子見だけれども, そのうちどうするかは決定する. いまは, 長い文章を一気に変換できることに快感を覚えている.

31 Dec 2014, 16:00

SICP を読むために Emacs で Scheme 環境を構築

はじめに

2015 年は SICP を読んでいく予定です.

というわけで, Scheme の開発環境を Emacs で構築しました.

Scheme の処理系 Gauche

まずは, Scheme 処理系をインストール.(ゴーシュ)

gosh -V

scheme-mode

Default で Emacs にはいっている. 以下の設定を参考にした.

;; UTF-8 に統一
(setq process-coding-system-alist
      (cons '("gosh" utf-8 . utf-8) process-coding-system-alist))

(setq scheme-program-name "gosh -i")
(autoload 'scheme-mode "cmuscheme" "Major mode for Scheme." t)
(autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t)

;; 別のウィンドウに gosh を動作させる
(defun scheme-other-window ()
  "Run Gauche on other window"
  (interactive)
  (split-window-horizontally (/ (frame-width) 2))
  (let ((buf-name (buffer-name (current-buffer))))
    (scheme-mode)
    (switch-to-buffer-other-window
     (get-buffer-create "*scheme*"))
    (run-scheme scheme-program-name)
    (switch-to-buffer-other-window
     (get-buffer-create buf-name))))

(define-key global-map "\C-cS" 'scheme-other-window)

smartparens

カッコをあつかうための多機能な移動・編集ツール.

(require 'smartparens-config)
(smartparens-global-mode t)

default

smartparens-config では以下が設定される.

example

設定例.

あまりに多機能すぎて使いこなす自信がないな..

覚えておきたいのは,

  • かっこで囲む xx sp-pair M-(
  • かっこを外す sp-unwrap C-M-s
(define-key sp-keymap (kbd "C-M-f") 'sp-forward-sexp)
(define-key sp-keymap (kbd "C-M-b") 'sp-backward-sexp)

(define-key sp-keymap (kbd "C-M-d") 'sp-down-sexp)
(define-key sp-keymap (kbd "C-M-a") 'sp-backward-down-sexp)
(define-key sp-keymap (kbd "C-S-a") 'sp-beginning-of-sexp)
(define-key sp-keymap (kbd "C-S-d") 'sp-end-of-sexp)

(define-key sp-keymap (kbd "C-M-e") 'sp-up-sexp)
(define-key emacs-lisp-mode-map (kbd ")") 'sp-up-sexp)
(define-key sp-keymap (kbd "C-M-u") 'sp-backward-up-sexp)
(define-key sp-keymap (kbd "C-M-t") 'sp-transpose-sexp)

(define-key sp-keymap (kbd "C-M-n") 'sp-next-sexp)
(define-key sp-keymap (kbd "C-M-p") 'sp-previous-sexp)

(define-key sp-keymap (kbd "C-M-k") 'sp-kill-sexp)
(define-key sp-keymap (kbd "C-M-w") 'sp-copy-sexp)

(define-key sp-keymap (kbd "C-M-s") 'sp-unwrap-sexp)
(define-key sp-keymap (kbd "M-<backspace>") 'sp-backward-unwrap-sexp)

(define-key sp-keymap (kbd "C-<right>") 'sp-forward-slurp-sexp)
(define-key sp-keymap (kbd "C-<left>") 'sp-forward-barf-sexp)
(define-key sp-keymap (kbd "C-M-<left>") 'sp-backward-slurp-sexp)
(define-key sp-keymap (kbd "C-M-<right>") 'sp-backward-barf-sexp)

(define-key sp-keymap (kbd "M-D") 'sp-splice-sexp)
(define-key sp-keymap (kbd "C-M-<delete>") 'sp-splice-sexp-killing-forward)
(define-key sp-keymap (kbd "C-M-<backspace>") 'sp-splice-sexp-killing-backward)
(define-key sp-keymap (kbd "C-S-<backspace>") 'sp-splice-sexp-killing-around)

(define-key sp-keymap (kbd "C-]") 'sp-select-next-thing-exchange)
(define-key sp-keymap (kbd "C-<left_bracket>") 'sp-select-previous-thing)
(define-key sp-keymap (kbd "C-M-]") 'sp-select-next-thing)

(define-key sp-keymap (kbd "M-F") 'sp-forward-symbol)
(define-key sp-keymap (kbd "M-B") 'sp-backward-symbol)

(define-key sp-keymap (kbd "H-t") 'sp-prefix-tag-object)
(define-key sp-keymap (kbd "H-p") 'sp-prefix-pair-object)
(define-key sp-keymap (kbd "H-s c") 'sp-convolute-sexp)
(define-key sp-keymap (kbd "H-s a") 'sp-absorb-sexp)
(define-key sp-keymap (kbd "H-s e") 'sp-emit-sexp)
(define-key sp-keymap (kbd "H-s p") 'sp-add-to-previous-sexp)
(define-key sp-keymap (kbd "H-s n") 'sp-add-to-next-sexp)
(define-key sp-keymap (kbd "H-s j") 'sp-join-sexp)
(define-key sp-keymap (kbd "H-s s") 'sp-split-sexp)

;;;;;;;;;;;;;;;;;;
;; pair management
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)

;;; lisp modes
(sp-with-modes sp--lisp-modes
  (sp-local-pair "(" nil :bind "C-("))

(sp-pair "(" ")" :wrap "M-(")

rainbow-delimiters

かっこの深さに応じて色付けしてくれる.

かっこの強調をどきつくする. これはいいなぁ.

注意 テーマ読み込みのあとに配置すること.

(require 'rainbow-delimiters)
(add-hook 'emacs-lisp-mode-hook 'rainbow-delimiters-mode)
(add-hook 'scheme-mode-hook 'rainbow-delimiters-mode)
(add-hook 'lisp-mode-hook 'rainbow-delimiters-mode)

;; these setting should be placed after load-theme
;; using stronger colors
(require 'cl-lib)
(require 'color)

;; 関数にしないとうまくいかない...手動で有効に
(defun rainbow-delimiters-using-stronger-colors ()
  (interactive)
  (cl-loop
   for index from 1 to rainbow-delimiters-max-face-count
   do
   (let ((face (intern (format "rainbow-delimiters-depth-%d-face" index))))
     (cl-callf color-saturate-name (face-foreground face) 100))))

;; making unmatched parens stand out more
(set-face-attribute 'rainbow-delimiters-unmatched-face nil
            :foreground 'unspecified
            :inherit 'error
            :strike-through t)

SICP を info で読む

以下の設定で Emacs の info で SICP が読める (English)

この方法のよいところは, テキストの文章をそのまま C-x C-e で評価して実 行できるところ.

# sicp.info 取得
wget http://www.neilvandyke.org/sicp-texi/sicp.info.gz
gunzip sicp.info.gz

# /usr/local/info に sicp.info をコピー.
$ sudo mkdir -p /usr/local/info
$ sudo cp sicp.info /usr/local/info

# dir ファイルを編集.
$ sudo emacs /usr/local/share/info/dir

# 次の二行を追記.
 The Algorithmic Language Scheme
 * SICP : (sicp.info). Structure and Interpretation of Computer Programs.

調べたけど利用しないもの

せっかく調べたけど, 設定を有効にしない (できない) ものも列挙.

paredit

Lisp コードで頻出する括弧類のバランスを維持することを目的としたもの.

smartparens に人気をとられてしまったかわいそうな子.

gosh-mode

scheme-mode の拡張.

scheme-mode を継承しているので, 基本的な操作は変わらないそうだ.

el-get で取得. リボジトリから取得後に make && make install

(require 'gosh-config)

M-x gosh-run で gosh が起動すれば OK.

scheme-mode に比べて情報がすくないのと, すごさがわからないので, ひとまずは scheme-mode を利用することにした.

なれてきたらそのうちもう一度挑戦する.

scheme-complete

auto-complete で補完をすることができる. デフォルト設定で, そこそこの補完候補が出る.

scheme-complete というものもあるそうなので,気休め程度に導入.

本家のサーバ落ちた?? github の mirror より取得.

以下を参考にして, auto-complete の source に scheme-complete の情報源を加える.

メンテされていないのと, auto-complete で何とかなるので削除.

(autoload 'scheme-smart-complete "scheme-complete" nil t)
(autoload 'scheme-get-current-symbol-info "scheme-complete" nil t)

(eval-after-load 'scheme
  '(define-key scheme-mode-map "\e\t" 'scheme-smart-complete))

;; scheme-mode-hook
(defvar ac-source-scheme
  '((candidates
     . (lambda ()
         (require 'scheme-complete)
         (all-completions ac-target (car (scheme-current-env))))))
  "Source for scheme keywords.")

(add-hook 'scheme-mode-hook
          '(lambda ()
             (make-local-variable 'ac-sources)
             (setq ac-sources (append ac-sources '(ac-source-scheme)))))

eldoc

scheme の eldoc は scheme-complete と合わせて利用するらしいが, eldoc error void-function eldoc-current-symbol とでてエラーする.

(require 'eldoc-extension)
(add-hook 'scheme-mode-hook
  (lambda ()
    ;; Gauche の場合, 次の 2 個の変数を設定しておいたほうがよいのかも.
    (setq default-scheme-implementation 'gauche)
    (setq *current-scheme-implementation* 'gauche)
    ;; eldoc-mode
    (set (make-local-variable 'eldoc-documentation-function)
     'scheme-get-current-symbol-info)
    (eldoc-mode t)
    )
  )
(setq lisp-indent-function 'scheme-smart-indent-function)

flymake 設定

glint というものがあるらしい. gauche 0.8.13 でしか動作しないようなので試していない.

31 Dec 2014, 04:54

2014 年の過去記事振り返りと 2015 年の目標

はじめに

2014 年にかいた過去記事を振り返りつつ, 2015 年の目標をたててみる.

2014 年の目標

2014 年の主な目標は以下

  • オブジェクト指向に慣れ親しむ
  • デザインパターンを学ぶ
  • 関数型言語に触れる
  • MOOC をがんばる

新年の記事.

2014 年のまとめ

Windows を捨てて Linux になった

去年, Windows 環境と決別することを決意した. 今年は, 上期は Mint Linux, 下期は ArchLinux を自分のノート PC に導入した.

と同時に, GUI 環境をすてて CUI 環境ですごすことにした.

Eclipse を捨てて Emacs になった

テキスト環境にすんでいると, 自然に Emacs を利用するようになった. そして, 気づけば, かなり Emacs の改造に熱がはいってしまった.

C 言語を捨てて Rubist, Javaer になった. いろんな言語に触れた

仕事では, Ruby, Java をつかうようになった.

また, MOOC を利用することで, 多くのプログラミング言語をまなんだ.

オブジェクト指向とデザインパターンをまなんだ

とくにデザインパターンを今年は努力した.

関数型言語にふれた

また, 関数型言語の Oz, Scala, Haskell を学んだ.

一番がんばったのは MOOC

そしてなにより, 一番がんばったのは, MOOC だ.

2015 年の目標

旗があれば, そこにむけて進んでいける.2015 年のすすむ方向をきめる.

2015 年は統計解析と関数型言語の学習に力をいれたい.

統計解析

統計学・データマイニング・機械学習・ビックデータ解析の知識に触れる.

もうこの記事がかかれてから 5 年が過ぎた.

今や本やさんにいくとデータサイエンティストやビッグデータという本でいっぱいだ.

学習の手段は去年からの MOOC を考えている.

Gakko とか, Coursera や edX に比べれば…と軽視していたけどこれやってみようかな.

関数型言語

2014 年で関数型の考え方になれたので, 2015 年はより知識を深めていきたい.

できれば, Emacs Lisp のひとつやふたつは簡単にかけるようになりたい.

31 Dec 2014, 01:43

Emacs DDSKK で NICOLA 親指シフト入力をする

はじめに

私は親指シフターだ.

Emacs の入力システムで SKK というものがある.

いままで利用していなかったのだけれども, 今朝調べてみたら, 親指シフトに対応しているようだ.

方法:

どんなものだか, ちょっと利用してみることにした.

SKK

インストール

インストールは el-get で実施した.

一般的な方法は以下.

設定

(require 'skk-autoloads)
(global-set-key "\C-x\C-j" 'skk-mode)
(global-set-key "\C-xj" 'skk-auto-fill-mode)

;; 親指シフト
(setq skk-use-kana-keyboard t)
(setq skk-kanagaki-keyboard-type 'omelet-jis)

使いかたは以下にある

キーバインド

以下に親指シフト専用のキーバインドがのっている.

感想

まず, SKK 自体に慣れていないので利用しにくい… Emacs のなかでは SKK を利用するのだが, Emacs の外側では ibus を利用するこ とになる. これがはたして効率がよい方法なのかどうかは疑問だ.

以下の意見に同感.引用します.

ローマ字入力の SKK は, 普通のローマ字入力「 kyouhasibuyani 」と体感上同じテンポで, 「 KyouHaSibuyaNi 」と入力できます.

しかし, JIS かなや親指シフトの SKK は, 普通のかな入力「きょうはしぶやに」とは別の, 「□きょう□は□しぶや□に」というテンポにどうしてもなってしまう. 体感するテンポが明らかに違ってしまうんですよ.

「これは常用できない……」と試したとき思いました

しかしここで諦めるのもなんだかくやしいので, もう少し試してみてから, 諦めることにする.

30 Dec 2014, 14:46

Java で Bridge パターンを実装をしてみた

はじめに

Java で Bridge パターンを実装をしてみました.

Bridge パターンとは

クライアントがアクセスするクラス (インタフェース) と実装クラスを分離して, それぞれを独立に変更できるようにする.

機能追加と機能実装の組み合わせ爆発を抑止することができる.

パターン適用前

言語と時間帯の分だけ, Man のサブクラスが増えていく.

なので, 言語や時間帯をひとつ追加すると その度にサブクラスが増えると言う問題がある.(組み合わせ爆発)

public class BridgeSample {
    public static void main (String args[]) {
        new JapaneseInTheMorning ().say ();
        new JapaneseInTheEvening ().say ();     
        new EnglishInTheMorning ().say ();
        new EnglishInTheEvening ().say ();      
    }
}

abstract class Man {
    public abstract void say ();
}

// ここで組み合わせ爆発が発生する!!!!
class JapaneseInTheMorning extends Man {
    public void say () { new Japanese ().inTheMorning (); }
}
class JapaneseInTheEvening extends Man {
    public void say () { new Japanese ().inTheEvening (); }
}
class EnglishInTheMorning extends Man {
    public void say () { new English ().inTheMorning (); }
}
class EnglishInTheEvening extends Man {
    public void say () { new English ().inTheEvening (); }
}

abstract class Language {
    public abstract void inTheMorning ();
    public abstract void inTheEvening ();   
}

class Japanese extends Language {
    public void inTheMorning () {
        System.out.println ("おはよう");
    }
    public void inTheEvening () {
        System.out.println ("こんばんわ");
    }
}

class English extends Language {
    public void inTheMorning () {
        System.out.println ("Good Morning");
    }
    public void inTheEvening () {
        System.out.println ("Good Evening");
    }
}

パターン適用後

言語と時間帯を分離して, 時間帯の引数で言語を渡す.

  • 言語の種類が増えても, 時間帯のクラスを増やす必要はない.
  • 時間帯の種類が増えても, 言語のクラスを増やす必要はない.

言語と時間帯はそれぞれ独立して機能拡張できる. つまり, 仕様変更に強い設計.

public class BridgeSample2 {
    public static void main (String args[]) {
        new Morning (new JapaneseSpeaker ()).say ();
        new Evening (new JapaneseSpeaker ()).say ();        
        new Morning (new EnglishSpeaker ()).say ();
        new Evening (new EnglishSpeaker ()).say ();     
    }
}

abstract class Man {
    protected Speaker speaker;
    public Man (Speaker speaker) {
        this.speaker = speaker;
    }
    public abstract void say ();

    protected void inTheMorning () {
        speaker.inTheMorning ();
    }
    protected void inTheEvening () {
        speaker.inTheEvening ();
    }
}

class Morning extends Man {
    public Morning (Speaker lang){ super (lang); }
    public void say () { inTheMorning (); }
}
class Evening extends Man {
    public Evening (Speaker lang){ super (lang); }  
    public void say () { inTheEvening (); }
}

abstract class Speaker {
    public abstract void inTheMorning ();
    public abstract void inTheEvening ();   
}

class JapaneseSpeaker extends Speaker {
    public void inTheMorning () {
        new Japanese ().inTheMorning ();
    }
    public void inTheEvening () {
        new Japanese ().inTheEvening ();        
    }
}

class EnglishSpeaker extends Speaker {
    public void inTheMorning () {
        new English ().inTheMorning ();
    }
    public void inTheEvening () {
        new English ().inTheEvening ();     
    }
}

abstract class Language {
    public abstract void inTheMorning ();
    public abstract void inTheEvening ();   
}

class Japanese extends Language {
    public void inTheMorning () {
        System.out.println ("おはよう");
    }
    public void inTheEvening () {
        System.out.println ("こんばんわ");
    }
}

class English extends Language {
    public void inTheMorning () {
        System.out.println ("Good Morning");
    }
    public void inTheEvening () {
        System.out.println ("Good Evening");
    }
}

実行結果

30 Dec 2014, 12:53

html ファイルを org ファイル形式に変換する方法メモ

はじめに

学生のときに Yahoo geocities で作成した html によるサイトを Futurismo Wiki に移行したい.

なぜなら, Yahoo geocities は, いつサービスが停止してもおかしくない気がするからだ.(人気的に) 昔の思い出は失いたくない.

  • 移行元サイトは完全な html 形式のファイル群
  • 移行先 wiki は org 形式でデータを管理している

ということで, html から org へ変換する方法を調べた.

Pandoc が利用できそう

以前, pandoc を利用して, markdown を org-mode へ変換することをやった.

今回もこの pandoc を利用して変換しよう. 導入方法は過去記事参照.

htlm を org 形式に変換するコマンド

$ pandoc index.html -f html -t org -o index.org

文字コードを Shift-Jis から UTF-8 へ変換

pandoc は UTF-8 形式しか受け付けないので注意. 変換には nkf を利用するとよい.

$ nkf -w index.html | pandoc ....

サイトを移行

FTP で接続してサイト取得.

とりあえずローカルに落として git 管理配下におく. 非公開で bitbucket へ upload.

これで若き青春の日々の日記はクラウド上で永遠の生命を得た.

30 Dec 2014, 08:14

Gof デザインパターンの勉強メモ記事とブックマークまとめ

はじめに

今年の目標は, デザインパターンの攻略!

ということで, この一年でまとめた情報や書いた記事のブックマークページです.

過去記事は, Ruby と Java が入り混じっていたり, 気まぐれでどんどん更新していったので, とてもまとまりがないとおもう.

強引に一つのページにまとめてみた感じ… (*‘д`*)

一年の振り返り

Rubyist になる

去年の 12 月から Rubyist になった.

そして, オブジェクト指向開発に触れることになった.

楽しかったので, 何も考えずにデザインパターンを使ってみたりした. しかし, これはのちに後悔することになった.

保守性よりもスピードを重視するべきだったのに, デザインパターンをつかって, 仕事が遅れてしまったという悲しい思い出.

POSA を学ぶ

coursera で POSA (Pattern Oriented Software Archtecture) をまなんだ.

ここで登場した Schmidt さん (POSA2 を書いた人) がとても情熱的に Pattern を語るのをきき, パターンが素晴らしいと洗脳された.

Javaer になる

年の暮れごろに Javaer になった.

すると, 一緒に仕事する人にすごく怖くてパターンに詳しいひとがいた.

OO でまともに設計した経験のない自分は, その人からしてみれば素人なので, レビューしているのだか教育をされているのだかわからない感じだった.

そんなことだから考え方がいつも手続的なんだ と, しょっちゅう罵倒された../ (._.)

毎日怯えつつ, あんなやついつかギャフンと言わせてやるという, なかば憎悪に似た感情を抱きつつ??, パターンの勉強をしたのだった.

これからどうするか?

Gof デザインパターンは 20 年前のもの.

最近, おもしろい podcast を発見した.

Gang of Four のメンバが 20 年たった今, なにを感じているのかをインタビューした podcast.

Gof デザインパターンは, 20 年も前のものなのだ.

そして, 今や時代はオブジェクト指向から関数型へと向かっている.

OO から FP へ

デザインパターンを学習していると, 関数型だともっと簡潔にかける気がしてきた.

たとえば, これ.

というわけで, 来年は関数型言語を頑張る. 関数型言語のパターンみたいなものはあるのかな??

Pattern

パターン

建築環境に繰り返し現れる課題を解決に導く具体的な方策を記述したもの.

アレクサンダーのパターン形式

  • パターン名
  • 写真
  • 上位パターンへのつながり
  • 本文
  • 下位パターンへのつながり

パターンランゲージ

建築において繰り返し現れる構造を再利用しやすい形式でまとめたもの. あるいは, パターンを集めて一つの体系としてまとぬあげたもの.

建築家クリストファーアレクサンダーが考えた建築手法.

時を超える建築の道

パターンランゲージを記した建築理論. 本の題名.

角谷信太郎さんのおもしろいはなしの youtube 動画も見つけた.

無名の質

生き生きとした建築や街が備えている特性. 古い街並みに潜む住みやすさや美しさ.

Design Pattern

Gof Degign Pattern

生成に関するパターン

Factory の原則

生成と実装を分離することで, プログラムはシンプルになる.

  • 生成パラメータの指定方法をシンプルに
  • 生成後の管理をシンプルに
  • 生成するオブジェクトの指定方法をシンプルに

特定のケースで特定のオブジェクトを生成するのは手続き思考的.

2 つをわけて考えることで設計に集中.

  • 動作方法
  • 生成,管理方法

Factory Method

オブジェクトの生成を行う時のインタフェースを規定して, インスタンス化するクラスを決定するのはサブクラスに任せる.

factoryMethod の中でオブジェクトの生成をすることで, 生成を生成オブジェクト (メソッド) 内にカプセル化.

switch 文は Abstract Factory によってリファクタリング可能.

  1. C 言語での応用

    C 言語で Abstruct Data Type な設計をつかうときの常套手段.

    int createInstance (void) {
      return calloc (4);
    }
    
    int destroyInstance (int ptr) {
      free (ptr);
      return NULL;
    }
    
    int main (void) {
      int *instance = createInstance ();
      instance = destoryInstance (instance);
      return 0;
    }
    
  2. 使いどころ

    グループ化されたオブジェクトについて,

    • 生成用オブジェクト (Creator)
    • 振る舞い用オブジェクト (Product)

    のペアを作成するとき.

Abstract Factory

関連するオブジェクト群を, その具象クラスを明確にせずに生成するための インタフェースを提供する.

関連するインスタンス群を生成するための API を集約することによって, 複数のモジュール群の再利用を効率化することを目的とする.

実装は意識せずに, インタフェース (API) のみで, 抽象的な部品をつくりあげる.

Factory Method 自体のカプセル化. マルチ Factory Method. Factory Methods.

Builder

オブジェクトの生成手順が複雑な場合に, その生成過程をカプセル化する.

ドメイン駆動設計でいうところのエンティティオブジェクトを生成する Factory.

Prototype

生成するオブジェクトの原型をコピーして新しいオブジェクトを生成する.

Abstract Factory と似ている.

  • new でオブジェクトを生成すれば Abstract Factory.
  • clone をつかう場合の Prototype.

複製を作成するためのメソッドを用意する. といういたって単純なもの.

プロトタイプ が複製を担当し, それ以外の生成における操作をクライアントが 担っている.

Map にテンプレートを登録しておいて, 利用するときに複製する. バイナリデータをマップにいれておいて, キーとなる名前をつけて管理する, など.

Java には, Clonable インタフェースがある.

クラスの数をかなり減らすことができる.

  1. 利用シーン

    • Abstract Factory パターンでなされるように,

    クライアント・アプリケーションにおいて オブジェクトの生成者をサブクラスにすることを回避する

    • 標準的な方法 (例えば’new’) で新しいオブジェクトを作ることによる

    固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する.

Singleton

システム内で生成可能なインスタンス数をひとつだけに制限する.

一般的なシングルトンパターンの実装方法は以下.

  • static method
  • private な 定数に オブジェクトを保存
  • オブジェクトは getInstance () メソッドで取得

各 Factory の違い

デザインはしばしば,

  • 比較的に複雑でなく,
  • カスタマイズしやすく,
  • サブクラスを急速に増やす

ファクトリメソッドを用いるところから出発

一層の柔軟性が必要となる箇所が発見されるに伴い,より柔軟だが複雑な Abstract Factory, Prototype, Builder へと発達してゆく.

  1. Factory Method

    ファクトリのクライアントとなるオブジェクトが, ファクトリオブジェクトにインスタンスの生成を委譲する.

    • 親クラスである Creator クラスが子クラスである

    ConcreteCreator クラスにオブジェクトの生成を委ねる

    • Creator クラスと ConcreteCreator クラスとの関連である.
    • 継承
    • [オブジェクト生成] の抽象化にポイントを置いたパターン
  2. Abstract Factory

    親クラスであるファクトリが, 実際のオブジェクトの生成をサブクラスに委譲する

    • Client のインスタンスが ConcreteFactory のインスタンスにオブジェクトの生成を委ねる
    • オブジェクト同士の関連
    • 委譲
    • [関連するオブジェクト群をまとめて生成するための手順] の抽象化
  3. 参考:

構造に関するパターン

Adapter

インタフェースを変換することにより, インタフェースに互換性がない クラス同士を接続する.

単なるラッパークラスとも言える.

ラッパー方法は 2 つ.

ここでは, ConcurrentLinkedQueue と ConcurrentArrayQueue を 生成時に交換するために, Adapter をつかっている.

Bridge

クライアントがアクセスするクラス (インタフェース) と実装クラスを分離して, それぞれを独立に変更できるようにする.

オブジェクト指向のこころの本にとても詳しく書いてある.

これぞ, オブジェクト指向の本質! みたいな.

  • インタフェースを用いて設計する.

機能追加と機能実装の組み合わせ爆発を抑止することができる.

Composite

部分-全体階層を表現するために, クラスの木構造に組み立てる. 同一の クラスから派生したサブクラスを木構造のノードとし, クライアントは木構造の任意の部分を同一のインタフェースで扱える.

別名, フォルダパターン. フォルダには, フォルダとファイルがある. こっちの名前のがわかりやすいし, 覚えやすい.

Decorator

サブクラス化ではなく委譲により, クラスに新しい機能を追加する.

ポイントは, オブジェクトの委譲方法が,

  • 集約ではなくてコンポジション
  • 継承ではなくてコンポジション

LinkedList 構造.

Facade

複数のクラス群からなるサブシステムにアクセスするための, インタフェースを提供する.

facade とは, 正面という意味.

Proxy

オブジェクトへのアクセスをフックするための代理オブジェクトを提供する.

Proxy は英語で代理人.

Windows のデスクトップショートカットもプロキシ.

本物のオブジェクトにアクセスするまえにクッションを置くことで, そこに機能追加できる.代理プラスアルファの機能をもつ.

Flyweight

一度生成したインスタンスはプーリングしておき, 必要なときに取り出して使う.

シングルトンパターンは フライウェイトパターンと合わせて利用されることがおおい.

特徴は,

  • private な 変数に オブジェクトを保存.
  • オブジェクトが存在すれば, getInstance で渡す. オブジェクトが存在しなければ, オブジェクトを作成して getInstance で渡す.
  1. wikipedia から説明引用

    その時点で対象のインスタンスが生成されていない場合

    • 対象のインスタンスを新たに生成する.
    • 生成したインスタンスをプールする (言い換えると, メンバのコンテナオブジェクトに格納する).
    • 生成されたインスタンスを返す.

    対象のインスタンスが既に生成されていた場合

    • 対象のインスタンスをプールから呼び出す.
    • 対象のインスタンスを返す.

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

Command

動作を表現するオブジェクト. 動作とそれに伴うパラメータをカプセル化したもの.

  1. 特徴

    • 手続きに必要なパラメータの一時格納場所として便利.
    • 関数呼び出しのためのパラメータを集めて,

    後で使用するためにコマンドを保存しておくことができる.

    • 保存されたデータ構造に対する追加, 削除が可能になる.
    • コマンドの生成と実行のタイミングの分離.

Chain of Responsibility

責務を持たせたオブジェクトの Chain に 要求を渡していく.

要求は,

  • そのオブジェクトで処理できればそこで処理する
  • そのオブジェクトで処理できなければ, 次のオブジェクトに渡す.
  1. 参考記事:

Interpreter

文字列からなる構文を構文解析 (Interprete) し, 構文を表現したオブジェクト構造ともとの文字列を関連付ける.

Iterator

オブジェクトの集合 (データ構造, コンテナ) があるとき, その集合の内部構造はカプセル化したままで, 要素に対して順にアクセスする方法を提供する.

コンテナオブジェクトの要素を列挙する手段を独立させることによって, コンテナの内部仕様に依存しない反復子を提供することを目的とする.

言語でサポートしていることがおおい. 拡張 for 文, for-each 文などと呼ばれる.

自前で実装するよりも, 言語に頼るほうがよい.

  1. Java

    Collection フレームワークでは, 反復子が利用できる.

    List<Integer> list = LinkedList<Integer>
    for (int i; list) {
    System.out.println (i);
    }
    

    Iterator インタフェースを実装することで, 自前のクラスにイテレータを適用できる.

  2. Ruby

    Enumerable モジュールを Mix-in する.

  3. 参考:

Mediator

複数のオブジェクトを相互作用させる場合に, お互いのオブジェクト同士が直接参照することをなくすため, 相互作用そのものをオブジェクトとして定義する.

Memento

オブジェクトの状態を保存しておき, 元に戻せるようにしておく. オブジェクトを以前の状態に (ロールバックにより) 戻す能力を提供する.

Observer

あるオブジェクトに依存した複数のオブジェクトがある場合に, 被依存オブジェクトの状態変化を, 依存オブジェクトに通知する.

Ruby ではライブラリがある.

イベントリスナ.

State

状態に応じてオブジェクトの振る舞いを変更したいときに, 振る舞いを別オブジェクトにカプセル化する.

Strategy

アルゴリズムをカプセル化して, アルゴリズムを交換可能にする. ひとつの入力データに対して, アルゴリズム毎に異なる結果を出力する.

アプリケーションで使用されるアルゴリズムを動的に切り替える必要がある際に有用.

  • Android
  • Windows
  • Linux
  1. 変更を考慮して設計するアプローチ

    オブジェクト思考のこころより引用.

    • 変更内容を予測するのではなくて, どこに変更が発生するのかを予測する
    • 実装を用いてプログラミングするのではなくて, インタフェースを用いてプログラミンクする.
    • クラス継承よりも, オブジェクトの集約を多用する.
    • 流動的要素をカプセル化する.

    switch 文を多用したり, グチャグチャになってきたら赤信号. switch 文は流動的要素なので, その部分をクラスに分離してカプセル化する.

    クラスに分離する際は, 継承をさけて集約を多用する.

  2. Effective Java から

    p101 戦略を表現するために関数オブジェクトを使用する

    • 戦略を現すインタフェースを用意
    • 個々の具象戦略に関してそのインタフェースを実装しているクラスを定義.
      • 具象戦略が一度しか利用されないならば, 無名クラスで作成
      • 繰り返し利用されるならば, public static final の フィールド or static factory method を通じて提供.
  3. 名前のつけかた

    xxxStrategy

Template Method

単なる継承.

アルゴリズムを複数のステップに分解し, それぞれのステップを抽象メソッドにする. 各ステップでのメソッドの実装はサブクラスで定義する.

システムのフレームワークを構築するための手段としてよく活用される.

Factory Method パターンは, 内部に Template Method パターンを包含することが多い

class A
  def execute ()
    raise "to be implemented"
  end
end

class B < A
  def execute ()
  end
end

class C < A
  def execute ()
  end
end

Visitor

複数のオブジェクトからなるオブジェクト構造があるときに, それぞれのオブジェクト要素に処理を追加または オブジェクト要素の処理を変更するため, Visitor クラスを用意する.

OOP の 2 大原則

オブジェクト指向のこころとは, ズバリ以下だ.

  • 流動的要素を探し出してカプセル化する
  • クラス継承よりもオブジェクトの集約を多用する

デザインパターンとともに学ぶオブジェクト指向のこころより

カプセル化の視点で整理

カプセル化がデータ隠蔽というのは狭義の定義.

カプセル化とはあらゆるものを隠蔽すること.

  • データ
  • メソッド
  • 実装
  • 派生クラス
  • 設計の詳細
  • 実体化の規則

流動的要素を探し出してカプセル化する. 委譲は手段.

この観点から, デザインパターンをとらえ直すと,

流動的要素 Pattern


アルゴリズム Strategy 状態 State 振る舞い Decorator パターンマッチ, 型 Visitor 動作, 要求 Command 実装 Bridge 変化への反応 Observer 相互作用 Mediator 生成 Factory Method, Abstract Factory , Prototype 一意性 Singleton, Flyweight 構造の生成 Builder 集合の巡回構造 Iterator インタフェース Adapter システム Facade 設計の詳細 Template Method

Links

概要がかかれたページ

噛み砕かれた, わかりやすい説明.

図解で解説されている.

サンプルソースが豊富.