04 Dec 2014, 22:45

動的に機能追加!Java で Decolator パターンを実装してみた

はじめに

Java であるクラスとべつのクラスの差がちょっとしかない場合を仮定する.

どうすれば共通部分を効率よく再利用できるのだろう??

たとえば

こんなとき, どうする??

class A {
    public static void greeding () {
        System.out.println ("Hello");
        System.out.println ("Nice to meet you");
        System.out.println ("Good Bye");
    }
}

class B {
    public static void greeding () {
        System.out.println ("Hello");
        System.out.println ("はじめまして");
        System.out.println ("Good Bye");
    }
}

継承をつかう

こんなときは, 継承によって共通部をスーパークラスにもっていって, 差分だけサブクラスに実装する.

abstract class C {
    public void greeding () {
        System.out.println ("Hello");
        niceToMeetYou ();
        System.out.println ("Good Bye");
    }

    protected abstract void niceToMeetYou ();
}

class A extends C {
    @Override
    protected void niceToMeetYou () {
        System.out.println ("Nice to meet you");        
    }
}

class B extends C {
    @Override
    protected void niceToMeetYou () {
        System.out.println ("はじめまして");  
    }
}

機能追加で破綻

しかし, もう一言なにか言いたくなったときに破綻する. これは, 委譲 (Strategy Pattern) をつかっても同じ.

class D {
    public static void greeding () {
        System.out.println ("Hello");
        System.out.println ("はじめまして");
        System.out.println ("お元気ですか?");
        System.out.println ("Good Bye");
    }
}

Decolator パターンを利用

Decolator パターンを利用すると, 粒粒の機能を動的に組み合わせることができる.

つまり, 以下のような機能を好きな順番で並び替えることができる.

  • System.out.println (“Hello”);
  • System.out.println (“はじめまして”);
  • System.out.println (“お元気ですか?”)
  • System.out.println (“Nice to meet you”); ;
  • System.out.println (“Good Bye”);

機能をオブジェクト化

まずは, 以下の機能を別々のオブジェクトにする. これがデコレータ本体.

  • System.out.println (“Hello”);
  • System.out.println (“はじめまして”);
  • System.out.println (“Nice to meet you”); ;
  • System.out.println (“Good Bye”);
abstract class Component {
    public abstract void operation ();
}

class EndComponent extends Component {
    public abstract void operation (){
        System.out.println ("Good Bye");
    }
}

abstract class Decorator extends Component {
    private Component component;

    public Decorator (Component component) {
        this.component = component;
    }

    public void callOperation () {
        if (component != null)
            component.operation ();
    }
}

class A extends Decorator {
    A (Component component) {
        super (component);
    }

    public void operation {
        System.out.println ("Hello");
    }
}

class B extends Decorator {
    A (Component component) {
        super (component);
    }

    public void operation {
        System.out.println ("Nice to meet you");
    }
}

class C extends Decorator {
    A (Component component) {
        super (component);
    }

    public void operation {
        System.out.println ("はじめまして");
    }
}

Factory でオブジェクト構築

欲しいオブジェクトを好きな順番で構築する.

class Factory {
    public static Component getA () {
        Component component;
        component = new EndComponent ();
        component = new B (component);
        component = new A (component);
        return component;
    }

    public static Component getB () {
        Component component;
        component = new EndComponent ();
        component = new C (component);
        component = new A (component);
        return component;
    }
}

public class DecolatorSample {
    public static void main (String[] args) {
        Factory.getA ().operation ();
        System.out.println ("");
        Factory.getB ().operation ();
    }   
}

関数型言語ならば当たり前??

思ったのは, これって関数型言語で利用される方法なのでは? 関数型言語では, 関数を値として扱うことができる.

関数をリストに詰め込んで, リストを評価すればよい.

というわけで, 無名クラスとリストを用いて実装してみた.

  import java.util.LinkedList;
import java.awt.List;

public class DecolatorWithFunctional {
    public static void main (String[] args) {
        LinkedList<Component> decorators = new LinkedList<>();

        decorators.add (new Component (){
                public void operation () { System.out.println ("Hello"); }
            });
        decorators.add (new Component (){
                public void operation () { System.out.println ("Nice to meet You"); }
            });
        decorators.add (new Component (){
                public void operation () { System.out.println ("Good Bye"); }
            });

        for (Component decolator: decorators){ decolator.operation (); }
    }
}

interface Component {
    public void operation ();
}

関数型のほうが圧倒的にシンプルな気がする.

Enum Strategy Pattern と組み合わせ

前回学んだ, Enum Strategy Pattern と組み合わせる.

public class DecolatorWithFunctional {
    public static void main (String[] args) {
        LinkedList<Component> components = new LinkedList<>();

        components.add (Component.HELLO);
        components.add (Component.NICE);
        components.add (Component.BYE);     

        for (Component component: components){ component.operation (); }
    }
}

enum Component {
    HELLO{ public void operation (){ System.out.println ("Hello"); }},
    NICE { public void operation (){ System.out.println ("Nice to meet you"); }},
    NICE_JA{ public void operation (){ System.out.println ("はじめまして"); }},
    BYE{ public void operation (){ System.out.println ("Bye"); }}; // 

    public abstract void operation ();
}

さらにシンプルになった.

04 Dec 2014, 14:39

IRC クライアントとして Emacs をつかいたい! ERC を試す

はじめに

仕事で IRC をコミュケーションツールとして利用しはじめた.

Emacs のなかで生きているので, IRC も Emacs から接続したい. ということで, Emacs の IRC クライアントを調べる.

IRC とは

Internet Relay Chat の略.インターネットを利用したチャット専用システム.

詳細は, 以下のページ参照.

Emacs 用 IRC クライアント

Emacs Wiki によると, いつくも種類があるようだ.

Emacs にデフォルトで入っていて, ネット上でも情報のおおい ERC を試す.

IRC サーバを用意

なんでもよかったのだが, 有名そうな ngiIRCd をいれる.

設定はひとまず Default 設定で起動.

$ sudo ngircd

Emacs

まずは, Emacs 上で M-x erc で ERC を起動.

ERC の Web マニュアル.

まずは, default の サーバに接続

  • IRC Server: rc.freenode.net
  • port: 6667
  • username: tsu-nera
  • password: はじめは未設定.

つづいて, /join #emacs とタイプすると, emacs のチャットに参加できる.

ログアウトは, M-x erc-quit-server (C-c C-x).

ngircd を利用

自分で用意したサーバでもう少し遊ぶ.

ログイン

  • IRC Server: localhost
  • port: 6667
  • username: tsu-nera
  • password: はじめは未設定.

これで, ログインできる.

設定ファイルにログイン情報を書くとログインが簡単になる.

(setq erc-server "localhost")
(setq erc-port "6667")
(setq erc-nick "tsu-nera")
;; (setq erc-password "")

オートログインもできる. 以下を書いて, M-x erc-opn

(autoload 'erc "erc" "" t)
(defmacro de-erc-connect (command server port nick)
  "Create interactive command `command', for connecting to an IRC server. The
command uses interactive mode if passed an argument."
  (fset command
    `(lambda (arg)
       (interactive "p")
       (if (not (= 1 arg))
           (call-interactively 'erc)
         (erc :server ,server :port ,port :nick ,nick)))))

(de-erc-connect erc-opn "localhost" 6667 "tsu-nera")
#  Channel 接続 /JOIN or /j
/j #test

# 直接話す
/query <nick>

これでも Chanel に接続 できる.

(setq erc-autojoin-channels-alist
      '(("localhost" "#test")))
;;  ("oftc.net" "#bitlbee")))
(erc :server "localhost" :port 6667 :nick "tsu-nera")

ログアウト

# Channel からぬける
/PART

# メッセージを残してサーバをさる
/QUIT msg
;; Kill buffers for channels after /part
(setq erc-kill-buffer-on-part t)

Highlight

(require 'erc-match)
(setq erc-keywords '("tsu-nera"))

erc-highlight-nicknames

ニックネームをハイライト

(and
  (require 'erc-highlight-nicknames)
  (add-to-list 'erc-modules 'highlight-nicknames)
  (erc-update-modules))

erc-hl-nicks

erc-highlight-nicknames の改良版か?

(require 'erc-hl-nicks)

nerc-nick-notify

ニックネームが呼ばれたら反応する.

(autoload 'erc-nick-notify-mode "erc-nick-notify"
  "Minor mode that calls `erc-nick-notify-cmd' when his nick gets
mentioned in an erc channel" t)
(eval-after-load 'erc '(erc-nick-notify-mode t))

Encoding

こんな感じか?

;; UTF-8
(setq  erc-server-coding-system '(utf-8 . utf-8))

;; Shift-JIS
(setq erc-server-coding-system に (iso-2022-jp . iso-2022-jp))

Color

ダークにはデフォルトのいろがみずらい

(add-to-list 'custom-theme-load-path "~/.emacs.d/elisp")
(load-theme 'blue-erc t t)
(enable-theme 'blue-erc)

Bookmarks

IRC について.

Windows で一番有名? な IRC クライアント.

IRC Client の比較.

ERC

Emacs にデフォルトで入っている.

Riece

Cabon Emacs にデフォルトで入っている.リースと読む.

Circe

けっこう最近 (2013) にでてきたやつ. 開発は盛ん.

weechat.el

最近でてきた CUI 用 IRC Client, weechat を Emacs から利用する.

ngircd

01 Dec 2014, 14:04

Effective Java を読んだ.エレガントな手法に感動した.

はじめに

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

といっても, まだ 8 時間くらいしかプログラミングしてないんだけど・・・.

ここ一か月, 怒涛のようにブログの記事を書いているけれども, そのほとんどが Java に関する記事だ.

たとえば…

それは, 元ネタはほとんど Effective Java だったりする.

2 週間ちかくかかったけれども, ようやく読みきったので感想を書く.

内容の紹介

紹介といっても, あまりに有名な本なので紹介するまでもないかも..

Java をつかうプログラマ必読の書

と, よくネットで見かける.自分も, この誘い文句に惹かれて本を手に取った.

第 2 版 は Java 6 の仕様にそって, Java を使う上での有効なテクニックが 78 項目, 順に紹介されていく.

題名のとおり, Effective な Java 文法の使い方のカタログ. よいとされる Java の書き方が, なぜそうするべきなのか説明される.

  • 第 2 章 オブジェクトの生成と消滅 (項目 1 〜 項目 7)
  • 第 3 章 すべてのオブジェクトに共通のメソッド (項目 8 〜 項目 12)
  • 第 4 章 クラスとインタフェース (項目 13 〜項目 22)
  • 第 5 章 ジェネリックス (項目 23 〜 29)
  • 第 6 章 enum とアノテーション (項目 30 〜 項目 37)
  • 第 7 章 メソッド (項目 38 〜 項目 44)
  • 第 8 章 プログラミング一般 (項目 45 〜 項目 56)
  • 第 9 章 例外 (項目 57 〜 項目 65)
  • 第 10 章 並行性 (項目 66 〜 項目 73)
  • 第 11 章 シリアライズ (項目 74 〜 項目 78)

順番に読む必要はないので, 目次をみて気になったところからつまみ読みできる.

感想

Elegant java

まず, この本に乗っている手法はとてもエレガントだ.

関心して, かつ興奮することが毎日体験できる. 思わず写経して, 記事にしてしまうほど, 感動するのだ!

どんな風に感動したかは, 過去記事に譲る.

Elegant Java というタイトルでも十分通用する.

あたりまえのようにデザインパターンがでてくる

オブジェクト指向言語における, 美しいパターンが各ページにちりばめられている.

Gof のデザインパターンというものが, オブジェクト指向でよく利用されるパターンのカタログならば, Effective な手法と Gof のパターンがかぶってしまうことは当たり前.

出てきたものを, 思いつくままに抜粋.

  • ファクトリーメソッド 項目 1
  • ビルダー 項目 2
  • シングルトン 項目 3
  • デコレータ 項目 16
  • ブリッジ 項目 18
  • ストラテジ 項目 21
  • アダプタ 項目 22
  • オブザーバ 項目 67
  • フライウェイト 項目 71

継承をやたら敵対視

とくに印象的だったのが, 以下の章だ.

  • 第 4 章 クラスとインタフェース (項目 13 〜項目 22)
  • 第 6 章 enum とアノテーション (項目 30 〜 項目 37)

Enum は別記事に譲るとして, ここではインタフェースについてのコメントを抜粋.

  • 継承よりもコンポジションを選ぶ 継承は不必要なメソッドを公開する. つまり, 継承はカプセル化を破る.

  • 継承をつかうならば設計を文書化する, でなければ禁止だ.

  • 抽象クラスよりもインタフェースを選ぶ 実装の観点では,

    • 抽象クラスはメソッドに対する実装を含むことを許されている.
    • インタフェースはメソッドに対する実装を含むことを許されていない.

    機能の観点では, - 抽象クラスはある機能の実装を強制する. - インタフェースは任意の機能を混ぜ合わせる.

    階層化の観点では, - 抽象クラスは物事を階層化することに優れる. - インタフェースは階層を持たないものをまとめることに優れる.

  • インタフェースは, 階層を持たない型システムを構築する.

おわりに

とてもよい読後感だ.

いいエンディングの映画をみたように, ここに掲載されている手法の美しさに心を打たれた.

各項目が細かく分類されているのもよい. Java での実装に困ったとき, 折に触れて読み返そうと思った.

BookMarks

30 Nov 2014, 12:21

Effective Java にのっている エレガントな Enum の使い方メモ

はじめに

Effective Java には毎回驚かされる.

Enum とは

プログラマが選んだ各々の識別子をそのまま有限集合として持つ抽象データ型.

番号を持たないカテゴリ変数. 一意の文字定数.

実行時には, 番号が振られることが覆いが, 言語によっては番号はプログラマに見えないこともある.

int enum パターン

名前つき int 定数のグループを宣言すること.バッドノウハウ.

[sourcecode language=”java” title=””]
public static final int FOO = 0;
public static final int BAR = 1;
[/sourcecode]

  • コンパイラによる型検査の恩恵を受けることができない.
  • 同じ名前がついたものを名前空間で区別することができない.
  • 変更により再コンパイルが必要.
  • 表示可能な文字列へ変換する方法かない.
  • int と enum では実効速度はそれほどかわらない.

定数固有メソッド実装 (constant-specific method implementation)

enum 定数に対して振る舞いを関連付けるための方法.

パターン適用前.

[sourcecode language=”java” title=””]
public enum Operation {
PLUS, MINUS;

double apply (double x, double y) {
switch (this) {
case PLUS: return x + y;
case MINUS: return x – y;
}
throw new AssertionError () ("Unknown op:" + this);
}
}
[/sourcecode]

パターン適用後. enum 型で抽象メソッドを宣言して, 定数固有クラス本体で, 定数ごとに具象メソッドで その抽象メソッドをオーバーライド.

switch 文を排除するので, エレガント!! 抽象メソッドによって実装をカプセル化.

[sourcecode language=”java” title=””]
public enum Operation {
PLUS { double apply (double x, double y) {return x + y;} },
MINUS { double apply (double x, double y) {return x – y;} };

abstract double apply (double x, double y);
}
[/sourcecode]

定数固有クラス

さらに, 定数固有データと実装を組み合わせることで, 強力な表現力を.

[sourcecode language=”java” title=””]
public enum Operation {
PLUS ("+") { double apply (double x, double y) {return x + y;} },
MINUS ("-") { double apply (double x, double y) {return x – y;} };

private final String symbol;
Operation (String symbol) { this.symbol = symbol; }
@Override public String toString () { return symbol; }

abstract double apply (double x, double y);
}
[/sourcecode]

Enum の toString は定数表現は 文字列へ変換することもできる.

戦略 Enum (Strategy Enum)

抽象メソッドをクラスに変更して外部から与えてやるようにすれば, これはいわゆる Strategy Pattern だ.

評価戦略を外部から与えて, Operation は委譲で評価をする.

[sourcecode language=”java” title=””]
public enum Operation {
PLUS (EvaluateType.PLUS), MINUS (EvaluateType.MINUS);

private final EvaluateType type;

Operation (EvaluateType type) {
this.type = type;
}

double apply (double x, double y) {
return type.apply (x, y);
}

// Strategy Enum Type
private enum EvaluateType {
PLUS { double apply (double x, double y) {return x + y;} },
MINUS { double apply (double x, double y) {return x – y;} };

abstract double apply (double x, double y);
}
}
[/sourcecode]

enum 定数と値の関連付けに ordinal をつかわないこと

enum と関連付けられた int 値を取得する メソッドとして ordinal メソッドがある.

これを定数と値を関連付けるときには, 使わない. なぜなら, コードの修正で, 振られる番号が変わるから.

[sourcecode language=”java” title=””]
public enum Number {
ONE, TWE;
public int getNumber{ return ordinal () + 1; }
}
[/sourcecode]

代わりにインスタンスフィールドを利用すればよい.

[sourcecode language=”java” title=””]
public enum Number {
ONE (1), TWE (2);
private final int number;
Number (int number) { this.number = number;}
public int getNumber{ return number; }
}
[/sourcecode]

集合と集合の対応づけに序数インデックス (配列) をつかわない

2 つの集合を対応付けるときには, 配列をつかうよりもいい方法がある.

それは, EnumMap. EnumMap は内部実装は配列でされているものの, インデックスを意識する必要がないというメリットがある.

配列をインデックスするために序数を使用することが適切であることはほ とんどない.代わりに, EnumMap を使用すること.

関連が多次元ならば, EnumMap<…, EnumMap<…>> というように連なっていく.

[sourcecode language=”java” title=””]
Map> herbsByType =
new EnumMap>(Herb.Type.class);
for (Herb.Type t : Herb.Type.values ())
herbsByType.put (t, new HashSet());
for (herb h: garden)
herbsBytpe.get (h.type).add (h);
[/sourcecode]

Enum シングルトンパターン

Enum を利用して, シングルトンパターンをする方法.

[sourcecode language=”java” title=””]
class SampleSingleton {
static public enum EnumUtil {
INSTANCE;

public static int plus (int x, int y) { return x + y; }
public static int minus (int x, int y) { return x – y; }
}

public static void main (String[] args) {
System.out.println (EnumUtil.INSTANCE.plus (1,1));
System.out.println (EnumUtil.INSTANCE.minus (2,1));
}
}
[/sourcecode]

29 Nov 2014, 10:47

Haskell で Hello World! しようとしたらモナドでドナドナした

file:./../img/IMG_3895.JPG

はじめに

最近発売された, Haskell 本を買ってみた.

どんな言語でも, はじめは Hello, World を出力するところからはじめる.

Haskell で Hello, World をするためには, ノマドというものを理解しない といけない. この本では p267 に書いてある. なんと険しき Hello, World…

モナドとは

とりあえず理解したことを自分の言葉でメモ. あまりわかっていない. モナドとノマドとドナドナの違いがわからない.

モナドとは, 純粋関数と副作用を共存さ競るためのしくみ.

純粋関数

同じ引数を渡す限り, どのような順番で何度呼んでも同じ結果が返るような関数.

副作用

ある機能がコンピュータの (論理的な) 状態を変化させ, それ以降で得られる結果に影響を与えること.

  • 状態を参照することで出力が変化すること
  • 状態に変化を与えることで出力が変化すること

例としては,

  • 破壊的代入
  • I/O 制御 (write/print 等)

wikipedia

ちなみに, wikipedia は,

プログラムとはクライスリ圏の射である , という要請から合成規則としてクライスリトリプル (Kleisli triple) というモナドと等価なものが用いられる.

ショボーン. 線形代数の単位を落としたオレをなめるなよ!

不条理な世の中と清められた世界

そう, Hello, World とは純粋で汚れのない pure な世界を汚す副作用.

そして, 純粋関数で構築されたプログラムは, 論理で構築された絶対的な世界!

絶対的な真理として存在する数学や音楽の秩序が美しさを持つように, 純粋関数によって構築された秩序は, それ自体が美しいのだ!

Hello, World!

コードを以下に示す.

main :: IO ()
main = putStrLn "Hello, World!"

IO という部分は, IO モナドと呼ばれる.

putStrLn は String を受け取り, IO を返す.

Prelude> :t putStrLn
putStrLn :: String -> IO ()

Bookmarks

Ruby での解説:

Haskell におけるモナドの解説ページ:

27 Nov 2014, 13:58

お手軽お気楽コードレビューシステム! codebrag に驚いた

はじめに

Subversion をつかっていて, ソースコードレビューでコードにコメントを書きたいと思った.

なにか, お手軽にためせるツールはないか探して見たところ, Codebrag というものを見つけたので試す.

Codebrag とは

オープンソースのコードレビューツール.

サーバにインストールして, Web 画面からコードレビューができる.

Git と Subversion に対応しているようだ. Subversion は, git-svn をつかって使えるようにしているようだ.

インストール

インストール手順は以下にある.

以下から, ダウンロード. ダウンロードでメールアドレスを入れないといけないのがちょっといやだ.

もしかしたら, wget でとれるかも..未検証.

wget http://codebrag.com/latest/codebrag.zip
unzip codebrag.zip

設定

リポジトリクローン

まずは, ダウンロードした zip を解凍.その後, repos ディレクトリに移動.

repos ディレクトリにリポジトリを clone する.

  • Git: git clone
  • Subversion: git svn clone
cd codebrag-2.3/repos
git clone git@github.com:tsu-nera/tdd_by_example.git

設定ファイル編集

codebrag.conf を編集する. リポジトリ認証のための設定を記述.

repository {
    username = "hogehoge"
    password = "password"
}

サンプルの.conf

起動

以下で起動.

./codebrag.sh start         # Unix/OS X
codebrag.bat                # Windows

URL にアクセス. Default は http://localhost:8080

しばらく時間がかかるからコーヒーでも飲んでなさいというメッセージのあ とに, ログイン画面が出てくる.

画面リフレッシュ後, ログイン. UI はかなりオシャレ!!

コードに対して, コメントやイイネ! をすることができる! すごい!

感想

正直, こんなに簡単に導入できて, おしゃれなツールだったので驚いている.

昔, ReviewBoard をインストールしようとしたが, ものすごく苦労した.

これは, インストールがとても簡単なところが気に入った.

gitbucket という,github を模倣して 簡単に github サーバをローカルに立てるツールがあるが, それと同じくらいに簡単. ライバルくらい, 簡単.

仕事で使いたいな・・・使わせてくれるかな・・・

下っ端で権力がないので無理かな…へぇ.

Bookmarks

26 Nov 2014, 16:12

Java の無名クラスにパラメータを渡す方法のメモ

はじめに

Java で, オブジェクト自体にタイムアウト機能を持たせることを考えた. (普通ならば, 外部のオブジェクトが監視するのかな??)

コード

<div class="outline-text-3" id="text-unnumbered-2">
  <p>
    こんなコードを書いた. タイムアウトになったら, 自分自身を Set から削除する.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> import java.util.HashSet;<br /> import java.util.Set;<br /> import java.util.Collections;
  </p>

  <p>
    public class TimeoutObjectSample {<br /> public static void main (String[] args) {<br /> new B ();<br /> }<br /> }
  </p>

  <p>
    class B {<br /> Set<A> set;</p> 

    <p>
      public B () {<br /> set = Collections.synchronizedSet ( new HashSet<A>() );<br /> A a = new A (this);</p> 

      <p>
        set.add (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> a.start ();<br /> }
      </p>

      <p>
        public synchronized Set<A> getSet () {<br /> return set;<br /> }</p> 

        <p>
          }
        </p>

        <p>
          class A {<br /> B parent;
        </p>

        <p>
          public A (B parent) {<br /> this.parent = parent;<br /> }
        </p>

        <p>
          void start () {<br /> System.out.println (&#8220;start&#8221;);
        </p>

        <p>
          new Thread (new Runnable () {
        </p>

        <p>
          public void run () {<br /> try{<br /> Thread.sleep (1000);<br /> } catch (InterruptedException e){<br /> } finally {<br /> Set<A> set = parent.getSet ();<br /> System.out.println (&#8220;I will die&#8221;);<br /> set.remove (this);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> }<br /> }<br /> }).start ();<br /> }<br /> }<br /> [/sourcecode]</p> 

          <p>
            しかし, これがうまく動かない&#x2026; 期待値は最後に Set の要素数が 0 になること.
          </p>

          <p>
            [sourcecode language=&#8221;language&#8221; title=&#8221;&#8221; ]<br /> size is 1<br /> start<br /> I will die<br /> size is 1<br /> [/sourcecode]
          </p>

          <p>
            もう少し調べてみる. 以下を Thread の内部と外に仕込んだ.
          </p>

          <p>
            [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> System.out.println (this);<br /> System.out.println (this.getClass ());<br /> [/sourcecode]
          </p>

          <p>
            どうも Runnable () クラスの内部と外部では, this を呼んでも別のクラスをさしているようだ.
          </p>

          <p>
            [sourcecode language=&#8221;language&#8221; title=&#8221;&#8221; ]<br /> size is 1<br /> start<br /> A@5df86e79<br /> class A<br /> A$1@5f92b8f5<br /> class A$1<br /> I will die<br /> size is 1<br /> [/sourcecode]
          </p></div> </div> </div> 

          <div id="outline-container-unnumbered-3" class="outline-2">
            <h2 id="unnumbered-3">
              無名クラスに引数を渡す
            </h2>

            <div class="outline-text-2" id="text-unnumbered-3">
              <p>
                this でさす内容が違うならば, this をしなければよいのでは?? ということで, 無名クラスにパラメータを渡す方法をしらべる.
              </p>

              <p>
                どうやら, 無名クラスのなかに, メソッドを定義すればよいようだ.
              </p>

              <ul class="org-ul">
                <li>
                  <a href="http://www58.atwiki.jp/chapati4it/pages/61.html">ちゃぱてぃ商店 IT 部 @ ウィキ &#8211; Java/ サンプル/ 無名クラスにパラメータを渡す</a>
                </li>
              </ul>

              <p>
                ということで以下を変更
              </p>

              <ul class="org-ul">
                <li>
                  無名クラスのなかに, パラメータをうけとる属性を作成
                </li>
                <li>
                  無名クラスのメソッドでパラメータをセットする setter を作成. このメソッドは自分自身 (Runnnable) を返す.
                </li>
                <li>
                  スレッドを起動する前に, パラメータをセットする.
                </li>
              </ul>

              <p>
                [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> import java.util.HashSet;<br /> import java.util.Set;<br /> import java.util.Collections;
              </p>

              <p>
                public class TimeoutObjectSample {<br /> public static void main (String[] args) {<br /> new B ();<br /> }<br /> }
              </p>

              <p>
                class B {<br /> Set<A> set;</p> 

                <p>
                  public B () {<br /> set = Collections.synchronizedSet ( new HashSet<A>() );<br /> A a = new A (this);</p> 

                  <p>
                    set.add (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> a.start ();<br /> }
                  </p>

                  <p>
                    public synchronized Set<A> getSet () {<br /> return set;<br /> }</p> 

                    <p>
                      }
                    </p>

                    <p>
                      class A {<br /> B parent;
                    </p>

                    <p>
                      public A (B parent) {<br /> this.parent = parent;<br /> }
                    </p>

                    <p>
                      void start () {<br /> System.out.println (&#8220;start&#8221;);<br /> System.out.println (this);<br /> System.out.println (this.getClass ());
                    </p>

                    <p>
                      new Thread (new Runnable () {<br /> A a;<br /> int time;
                    </p>

                    <p>
                      public Runnable setParam (A a, int time) {<br /> this.a = a;<br /> this.time = time;<br /> // 自分自身を返す.<br /> return this;<br /> }
                    </p>

                    <p>
                      public void run () {<br /> try{<br /> Thread.sleep (time);<br /> } catch (InterruptedException e){<br /> } finally {<br /> Set<A> set = parent.getSet ();<br /> System.out.println (&#8220;I will die&#8221;);<br /> set.remove (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> }<br /> }<br /> }.setParam (this, 1000)<br /> ).start ();<br /> }<br /> }<br /> [/sourcecode]</p> 

                      <p>
                        これでうまくいきました.
                      </p></div> </div>

26 Nov 2014, 13:47

Java でのジェネリックスの使い方まとめ

はじめに

異なる型のオブジェクトを Set に入れる方法を調べた.

Object 型

すべてのクラスの頂点にたつ Object 型を利用すれば, どんな型だっていれることができる.

ジェネリックスを利用しない場合は, Collection は Object 型で代入される.

[sourcecode language=”java” title=””]
class A {
public void show () {
System.out.println ("I’m A");
}
}

class B {
public void show () {
System.out.println ("I’m B");
}
}
public class GenericSample {
public static void main (String[] args) {
HashSet set = new HashSet ();
A a = new A ();
B b = new B ();

set.add (a);
set.add (b);

for (Object x: set) {
if (x instanceof A) {
A xx = (A) x;
xx.show ();
}
if (x instanceof B) {
B xx = (B) x;
xx.show ();
}
}
}
}
[/sourcecode]

欠点は, set に入れるときに Object 型にキャストされるので, メソッド利用時に, 再度 キャストする必要がある.

[sourcecode language=”java” title=””]
for (Object x: set) {
if (x instanceof A) {
A xx = (A) x;
xx.show ();
}
if (x instanceof B) {
B xx = (B) x;
xx.show ();
}
}
[/sourcecode]

ジェネリックス型

利用時にキャストするのが面倒. そんな面倒くささを払拭するのが, Java のジェネリックスという機能.

コンパイル時にのみ型チェックが行われるが, コードとしてキャストをかかなくていいというメリットがある.

ジェネリック利用 共通の親クラス

共通の親クラスを継承させることで,Object の範囲をもう少し狭くする.

[sourcecode language=”java” title=””]
import java.util.HashSet;

public class GenericSample {

public static void main (String[] args) {
HashSet set = new HashSet();
D d = new D ();
E e = new E ();

set.add (d);
set.add (e);

for (C x: set) {
x.show ();
}
}
}

abstract class C {
public abstract void show ();
}

class D extends C {
public void show () {
System.out.println ("I’m D");
}
}

class E extends C {
public void show () {
System.out.println ("I’m E");
}
}
[/sourcecode]

これだと, instanceof やキャストを省略できる.

ジェネリック型を定義する

ジェネリック型を定義してみる.

定義をするためには,

  • <> で囲まれた記号をクラス名の定義につける
  • <> で囲んだ記号で, 型を置き換える.

Example

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    下の例では, ジェネリックスクラスを自分で定義することで, C,D クラスを E クラス一つで表現している.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> import java.util.HashSet;<br /> import java.util.Set;
  </p>

  <p>
    public class GenericsSample2 {<br /> public static void main (String[] args) {<br /> C c = new C ();<br /> c.add (1);<br /> System.out.println (c.get ());
  </p>

  <p>
    D d = new D ();<br /> d.add ("Hello");<br /> System.out.println (d.get ());
  </p>

  <p>
    E<Integer> e = new E<Integer>();<br /> e.add(1);<br /> System.out.println(e.get());
  </p>

  <p>
    E<String> f = new E<String>();<br /> f.add("Hello");<br /> System.out.println(f.get());<br /> }<br /> }
  </p>

  <p>
    class C {<br /> private Set<Integer> set = new HashSet<Integer>();
  </p>

  <p>
    void add (Integer i) {<br /> set.add (i);<br /> }
  </p>

  <p>
    Integer get () {<br /> for (Integer i : set) {<br /> return i;<br /> }<br /> return -1;<br /> }<br /> }
  </p>

  <p>
    class D {<br /> private Set<String> set = new HashSet<String>();
  </p>

  <p>
    void add (String str) {<br /> set.add (str);<br /> }
  </p>

  <p>
    String get () {<br /> for (String s : set) {<br /> return s;<br /> }<br /> return null;<br /> }<br /> }
  </p>

  <p>
    class E<T> {<br /> private Set<T> set = new HashSet<T>();
  </p>

  <p>
    void add (T i) {<br /> set.add (i);<br /> }
  </p>

  <p>
    T get () {<br /> for (T i : set) {<br /> set.clear ();<br /> return i;<br /> }<br /> return null;<br /> }<br /> }<br /> [/sourcecode]
  </p>
</div>

ジェネリックスの名前付け

<div class="outline-text-3" id="text-unnumbered-7">
  <p>
    慣例があるようだ.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://java.keicode.com/lang/generics-naming.php">名前付けルール &#8211; Java 入門</a>
    </li>
  </ul>
</div>

異種コンテナの実装

最後に, Effective Java から, エレガントなジェネリックスの使い方の引用.

[sourcecode language=”java” title=””]
import java.util.Map;
import java.util.HashMap;

public class GenericsSample3 {
public static void main (String[] args) {
Favorites f = new Favorites ();
f.putFavorite (String.class, "Java");
f.putFavorite (Integer.class, 0xcafebebe);

String s = f.getFavorite (String.class);
int i = f.getFavorite (Integer.class);

System.out.println (s + i);
}
}

class Favorites {
private Map, Object> favorites =
new HashMap, Object>();

public void putFavorite (Class type, T instance) {
if (type == null)
throw new NullPointerException ();
favorites.put (type, instance);
}

public T getFavorite (Class type) {
return type.cast (favorites.get (type));
}
}
[/sourcecode]

Environment

  • Java 1.7

25 Nov 2014, 13:47

委譲のまとめと Strategy パターンの実装 (Java)

はじめに

委譲.

よく聞く言葉だが, 実際にどういうものか知らなかったので調べてみた.

Delegation

委譲.あるオブジェクトの操作を一部他のオブジェクトに代替させる手法.

特徴

  • 委譲を行うオブジェクトは委譲先オブジェクトへの参照を持つ
  • 必要に応じてその参照を切り替える事で動作にバリエーションを持たせる事ができる
  • プラグイン機構

コンポジショントデリゲーション

  • 委譲の実現には多くの場合コンポジションを使用する. 委譲は「目的」であり, コンポジションはその「手段」.

参考:

継承との比較

  • 実装の観点では,
  • 抽象クラスはメソッドに対する実装を含むことを許されている.
  • インタフェースはメソッドに対する実装を含むことを許されていない.

  • 機能の観点では,

    • 抽象クラスはある機能の実装を強制する.
    • インタフェースは任意の機能を混ぜ合わせる.
  • 階層化の観点では,

    • 抽象クラスは物事を階層化することに優れる.
    • インタフェースは階層を持たないものをまとめることに優れる.

メリット

  • Java の場合継承は一クラスしかできないが, 委譲なら複数可能
  • 継承なら親クラスのメソッドが全て公開されてしまうが, 委譲なら必要なものだけ公開できる.

デメリット

  • 継承に比べてコードの記述量が多くなる.
  • 継承は何も書かなければ親クラスの機能が使える. 委譲はメソッドの呼び出しを実装しなくてはならない.

  • eclipse では, 右クリック→ソース→委譲メソッドで簡単に作成できる.

  • Ruby には delegation のライブラリがある. Ruby で delegation (委譲) を簡単にする 2 つの方法 - Qiita

参考:

関連する Design Pattern

  • Adapter
  • Proxy
  • Facade
  • State
  • Strategy
  • ほかにもあるかな…

Strategy Pattern

サンプルとして, Gof デザインパターンの Strategy パターンを書いた. 参考:Tricorn Labs » State パターンと Strategy パターンは何が違うのか考える

ここでは, 戦略を別々のクラスに委譲することで, 次々に切り替えている.

動的に A が保持するオブジェクトを切り替えているので, こういう場合は, コンポジションではなくて集約関係というのか な?? (素人の見解)

public class DelegationSample {
    public static void main (String[] args) {
        A x = new A ();

        x.setHuman (new B ());
        x.greeding ();
        x.setHuman (new C ());
        x.greeding ();
    }
}

class A {
    Human a; // 集約

    void setHuman (Human x) {
        a = x;
    }

    void greeding () {
        a.greeding (); // 委譲
    }
}

interface Human {
    void greeding ();
}

class B implements Human {
    public void greeding () {
        System.out.println ("やあ");
    }
}

class C implements Human {
    public void greeding () {
        System.out.println ("オス!");
    }
}

Effective Java から

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

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

24 Nov 2014, 14:25

抽象データ型とドメイン駆動設計の関係について

はじめに

この記事の続きです.

設計とはデータ型を決めること

前回の記事を引用すると,

アプリケーションを設計するということは, まずそのアプリケーションで利用されるデータ型を定義するということ

その後, 自分が定義したデータ型を操作するインタプリタを設計する.

Java をつかっているものの, Java はそれらのデータ型のインタプリタでしかない

オブジェクト指向設計とはなんだろうか?

そんなことを考えていたとき, オブジェクト指向設計の本としてもっとも名高い本, エリック・エバンズのドメイン駆動設計が本屋にあった

思わず衝動買いした.

ドメイン駆動設計

ドメイン駆動設計とは, Eric Evans の提示した設計手法. DDD と略す.

本はこれ.

データ型の設計とは

抽象データ型については前回の記事でまとめた.

抽象データ型もオブジェクトも性質と操作の管理の仕方が異なるだけで, 性質や操作自体は同一だ.

抽象データ型を設計して, 型のインタプリタを作成すること.

DDD でいえば, エンティティと値オブジェクトを決めて, それを操作するサービスや集約, 生成方法を決定すること.

両者はおなじことを言っているように感じた. アプリケーションで扱う型を決めるということは, ドメイン層における, エンティティと値オブジェクトを決めるということ.

これが, とりありず前半部分を読んだ感想だ.

DDD 本の前半まとめ

以下 DDD 本の読書メモ.

とくに, リポジトリの章は, 明日まさに仕事で考えないといけないことなので, とても参考になった.

基本原則 (前書きより)

  • コアドメインに集中すること
  • ドメインの実践者とソフトウェアの実践者による創造的な共同作業を通 じてモデルを探求すること
  • 明示的に境界づけられたコンテキストの内部で, ユビキタス言語を語ること.

基本用語

巻末に用語集がある.

ドメイン

  • 知識, 影響, 活動の領域.
  • アプリケーションが対象とする業務領域.

ユビキタス言語 (p24)

ドメインエキスパートと開発者の間で使う共通言語.

  • モデルを言語の骨格として使用する.
  • チーム内のすべてのコミュニケーションとコードにおいて, 厳格にその言語を用いること.
  • 図, ドキュメント, コード, 会話において, 同一の言語を用いること.

UML

  • UML によって議論に確固とした基盤が与えられる.
  • クラス図と相互作用図がつかいやすい.
  • オブジェクトの名前や関係性を共有できる.
  • オブジェクトの概念, なにをおこなうかははっきり伝えることができない.
  • クラス図の操作名やコミュニケーションでそれとなくは伝えられる. はっきり伝えるためには, 補足的なテキストや会話が必要.
  • 説明のためのモデルはオブジェクトモデルである必要は全くなく, 通常はそうでないほうがよい.

ドキュメント

  • モデルは図ではない.図はコミュニケーションの手段に過ぎない.
  • 設計に関する本質的な詳細は, コードにおいてとらえられる.
  • すでにコードでうまくやっていることを, ドキュメントでもやろうとすべきでない.
  • ドキュメントは活動の役にたたなければならず, 最新の状態を保たなければならない.
  • ドキュメントを最小限にとどめ, その重点をコードと会話の補足に絞る ことで, ドキュメントを常にプロジェクトに結びつけた状態にたもつ.

モデル駆動設計 (P45)

  • 分析モデルと設計ととう二分法を捨て去り, 両方の目的に 使える単一のモデルを探し出す.
  • モデリングと設計のプロセスは, 反復されるただ 1 つのループ.
  • 設計で必要とする用語法と責務の基本的な割り当てをモデルから引き出すこと.
  • 開発は, モデルと設計, コードを単一の活動として改良しつづける, イテレーティブなプロセスとなる.

モデル駆動設計の構成要素 (p65)

レイア化アーキテクチャ (p66)

以下の 4 つに分解される.

  1. UI 層

    ユーザとの相互作用の境界となる層 (Web 層, プレゼンテーション層)

  2. アプリケーション層 (サービス層)

    ドメインオブジェクトを操作することで, ソフトウェアが果たすべき仕事を実現する層. 薄くシンプルにたもち, 仕事はドメイン層のオブジェクトにやらせる.

  3. ドメイン層

    ビジネス上の概念を表現する層.モデル層

  4. インフラストラクチャ層

    上の 3 層を支える技術的な基盤となる層. データベース, 通信など.

エンティティ (参照オブジェクト) (p87)

属性ではなく,連続性と識別性によって定義されるモノ

  • 連続性
    • 状態をもつ.
    • ライフサイクルをもつ.
  • 識別性
    • 一意であることが保証された記号をそえることによって実現できる.
    • ID, 座席番号, 出席番号… システムが生成する.

振る舞いと属性を, 他のオブジェクトに移動できないか検討する. (別のエンティティ, 値オブジェクト, サービス..)

値オブジェクト (p95)

事物の特性を記述するオブジェクト. 概念的な同一性はない.

  • 識別子を持たない (与えてはいけない) 属性にのみ興味がある.
  • オブジェクトは不変でなければならない (fatal)
  • 通例読み出し専用のオブジェクト.
  • Flyweight パターンを用いて共有できる.
  • しばしば, オブジェクト間のメッセージでパラメータとして渡される.

サービス (p103)

  • 操作をおこなう責務をもつ.
  • ソフトウェアが実行すべきことに対応し, 状態には対応しない.
  • オブジェクト自身に操作をさせずに, それぞれごとにオブジェクトの操 作をするものは, しばしばマネージャーと呼ばれる.それは手続的だ.
  • 状態をもたせないこと.
  • 要求に応じてクライアントのために行われるなにか. なので, 名詞よりも動詞として定義される.
  • 操作名がユビキタス言語の一部になること.

モジュール / パッケージ (p108)

  • モデルの意味ある一部.
  • モジュール内は高凝縮, モジュール間は低結合.
  • モジュールは本で言えば章.
  • モジュール名は, ユビキタス言語をつけること. ドメインに関する深い洞察を反映していなければならない.

ドメインオブジェクトのライフサイクル (p122)

集約 (Aggregates) (p123)

  • 関連を最小限にして設計する.
  • モデル内にある参照をカプセル化するための抽象化が集約.
  • 関連するオブジェクトの集まりであり, データを変更するための単位. -> 集約のときに宣言する型は抽象クラスかインタフェースになるのかな?
  • 集約にはルートと境界がある.
    • ルート
  • 集約に含まれている特定の 1 エンティティ.
  • 外部オブジェクトへの参照をもつ.(車がルート, タイヤは違う)
  • グローバルな一貫性をもち, 不定条件をチェックする最終責務をも つ.(リソースの開放処理とか?)
    • 境界 * エンティティと値オブジェクトを集約のなかにまとめ, 各集約の周囲に境界を定義すること.
  • 境界の内部に存在するオブジェクトへのアクセスは, ルートオブジェクトを経由して制御すること.

ファクトリー (p134)

  • オブジェクトや集約全体を生成するのが複雑だったり, 内部構造をさらけ出し過ぎている場合は, 別のオブジェクトに移譲すること.
  • ファクトリーでカプセル化する.
  • 実装を簡単に切り替えられるようにできる.
  • 要求される型によって抽象化する.
  • デザインパターンでいくつかまとまっている
    • ファクトリーメソッド
    • ビルダー
    • アブストラクト・ファクトリー
  • ファクトリの置き場所は,
    • 集約のルートオブジェクトにメソッドを用意する.
    • 他のオブジェクトの生成に密接に関わるオブジェクト.

リポジトリ (p146)

  • オブジェクトを使用するための方法は

    1. 生成する
    2. 関連を巡る
    3. クエリを実行して,
      • 属性に基づいてデータベース内でオブジェクトを見つける
    • オブジェクトの構成要素を見つけて, それを再構築する
  • この第 3 の方法こそがリポジトリ.

  • データベース検索は, グローバルにアクセスすることができて, どんなオブジェクトにも直接到達できる. オブジェクトのネットワークは管理しやすくなる.

  • 開発者は通常, そういう設計の機微についてあまり考えない.

  • 格納されたデータからインスタンスを生成することは, エンティティのライフサイクルの一部. なのでこれを再構築と呼んで, 生成と区別する.

  1. 関連でほとんどの場合は十分!

    • 一時的なオブジェクト (値オブジェクト) は必要ない. ライフサイクルが短く, それを利用するクライアントで生成と破棄がされる.
    • 永続化されりオブジェクトのうちで, 関連を巡ってみつけるほうが便利 なものに対しても, クリエによるアクセスは必要ない. なによりも, 集約内部にあるどのオブジェクトも, ルートから辿る以外の方法でアクセスすることは禁止だ.
    • 永続化された値オブジェクトを見つけるには, それをカプセル化する集約のルートとして機能するエンティティから関 連を巡るのが普通のアプローチ.
  2. どのようなときに検索が必要?

    • オブジェクトの属性に基づいた検索を通じて, グローバルにアクセスできなければならないものもある. そういうアクセスを必要とするのは, 集約のルートのうち 関連を巡って到達しようとする都合の悪いもの.
    • データベースへのアクセス方法はいくつかある
  3. リポジトリの作り方

    • リポジトリは, 特定の型のオブジェクトをすべて概念上の集合として表現する. この定義の集合を通じて, 集約のルートに対するアクセスが提供される.
    • クラアイントがリポジトリに対してオブジェクトを要求する際は, クリエメソッドを使用する.
    • グローバルアクセスを必要とするオブジェクトの各型に対して, あるオブジェクトを生成し, その型のすべてのオブジェクトで構成され るコレクションが, メモリ上にあると錯覚させるようにできるようにすること.
    • 実際に直接的なアクセスを必要とする集約ルートに対してのみ, リポジトリを提供すること.