fc2ブログ

オブジェクトの非正規化

 オブジェクト指向で有限オートマトンを表現してみるで、オブジェクト指向プログラミングでよくある問題について書きました。むろん頻繁に発生するこの問題は、解決方法もあります。今回はその手法について解説します。それと、学習方法の補足説明をします。
 オブジェクト指向で有限オートマトンを表現してみるで指摘した問題点は、型システムに依存した考え方をすることにより発生する問題です。これは、オブジェクト指向初心者にありがちな間違いです。初心者は定義をそのままオブジェクトにしがちです。定義をそのまま型として表現すると、この様なプログラムを書いてしまいます。
 解決する方法は簡単です。ちゃんと、オブジェクト指向分析と、オブジェクト指向設計をすることです。分析と設計を正しく行えば、硬直したプログラムは作りません。何故ならば、分析を通して本質を見極め、設計を通して賢いオブジェクトを考えるからです。これから、簡単な分析と設計をしてみます。
 有限オートマトンを分析すると、各集合{ Q, Σ, δ, q0, F }と出力との関係が大事です。また、今回の目的を考えると、「有限オートマトンを学習すること」です。従って、{ Q, Σ, δ, q0, F }は必ず指定する方式にする必要があります。そうしないと、有限オートマトンの学習に抜けが生じる恐れがあります。
 次に設計をします。オブジェクト指向設計は、適切に実装できるようにオブジェクトを考える段階です。オブジェクトの実装方法を検討すると、この要件で有限オートマトンの各状態を型として扱うのはやりすぎだと思います。何故ならば、実装が面倒ですし、細部に気を取られて有限オートマトンの概念を覚えるという本題が有耶無耶になる恐れがあるからです。状態オブジェクトを工夫し、各状態はインスタンスとして扱うのが適切だと考えられます。状態遷移関数については、状態オブジェクト・オートマトンオブジェクト・入力オブジェクトのどれにも依存しない形が良いでしょう。従って、柔軟性も考慮し別のオブジェクトとして扱うのがベストです。なお、私は概念を型に当てはめる考える事をオブジェクトの正規化、逆に型にしないでインスタンスで対応することをオブジェクトの非正規化と呼んでいます。
 簡単ながら、これで分析と設計が終わったので、その結果を踏まえて実装してみます。

using System;
using System.Collections.Generic;
using System.Linq;

//有限オートマトン( FA : finite automaton )
class Fa<StateT, InputT, ValueT>
    where StateT : FaState<ValueT>
{
    //FAの定義に必要なフィールド
    private IEnumerable<StateT> _stateSet;
    private IEnumerable<InputT> _inputSet;
    private Converter<StateT, InputT, ValueT> _stateTransition;
    private StateT _firstState;
    private IEnumerable<StateT> _lastStateSet;

    //現在の状態を覚えておく必要がある
    private StateT _currentState;

    //受理
    public bool IsAccept
    {
        get
        {
            return this._lastStateSet.Contains( this._currentState );
        }
    }

    //FAの定義( Q, Σ, δ, q0, F )でインスタンスを生成する
    public Fa(
        IEnumerable<StateT> stateSet,
        IEnumerable<InputT> inputSet,
        Converter<StateT, InputT, ValueT> stateTransition,
        StateT firstState,
        IEnumerable<StateT> lastStateSet )
    {
        this._stateSet = stateSet;
        this._inputSet = inputSet;
        this._stateTransition = stateTransition;
        this._firstState = firstState;
        this._lastStateSet = lastStateSet;

        this._currentState = firstState;
    }

    //記号1つを指定して現在の状態を遷移させる
    public bool StateTransition( InputT input )
    {
        if ( !this._inputSet.Contains( input ) )
            throw new ArgumentException( 
                input + "は想定外です" );
        this._currentState =
            this._stateTransition.NextState( 
                this._currentState, input );
        return this.IsAccept;
    }
}

//オートマトンの状態を表わす抽象オブジェクト
class FaState<T>
{
    //状態の識別子
    private int _id;
    public int ID
    {
        get { return _id; }
    }

    //状態が保持する値
    private T _value;
    public T Value
    {
        get { return _value; }
    }

    //IDと値は必須とする
    public FaState( int id, T value )
    {
        this._id = id;
        this._value = value;
    }

    //等価性を判定する
    public override bool Equals( object obj )
    {
        FaState<T> other = obj as FaState<T>;
        if ( other == null ) return false;
        if ( this.ID != other.ID ) return false;
        if ( !this.Value.Equals( other.Value ) ) return false;
        return true;
    }

    //本題と関係ないのでハッシュコードはいい加減にしている
    public override int GetHashCode()
    {
        return ( 
                this.ID.ToString() + 
                this.Value.ToString() 
            ).GetHashCode();
    }
}

//状態遷移関数の役割を果たすオブジェクト
abstract class Converter<StateT, InputT, ValueT>
{
    //次の状態を取得
    public abstract StateT NextState(
        StateT state, InputT input );
}

//サンプルに特化した状態遷移関数の定義
class SampleConvertoer 
    : Converter<FaState<int>, int, int>
{
    public override FaState<int> NextState( 
        FaState<int> state, int input )
    {
        if ( input == 0 )
            return new FaState<int>( state.ID, state.Value );
        if ( input == 100 )
            return new FaState<int>(
                state.ID + 1,
                state.Value + input );
        throw new ArgumentException(
            String.Format( "状態:{0}と入力値{1}の組み合わせは想定外です。",
               state, input ) );
    }
}

class Sample
{
    static void Main()
    {
        //300円の商品を扱う機械
        Console.WriteLine( "300円の商品を扱う機械の状態遷移" );
        Test( new FaState<int>( 3, 300 ) );
        Console.WriteLine( );

        //400円の商品を扱う機会
        Console.WriteLine( "400円の商品を扱う機械の状態遷移" );
        Test( new FaState<int>( 4, 400 ) );
        Console.WriteLine( );
    }

    static void Test( FaState<int> maxValue )
    {
        //自動販売機の有限オートマトンを用意する
        Fa<FaState<int>, int, int> obj = Init( maxValue );

        //100円投入してみる
        int input = 100;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            input, obj.StateTransition( input ) );

        //もう100円投入
        input = 100;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            input, obj.StateTransition( input ) );

        //投入したふりをしてみる
        input = 0;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            input, obj.StateTransition( input ) );

        //もう100円を投入
        input = 100;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            input, obj.StateTransition( input ) );

    }

    static Fa<FaState<int>, int, int> Init( 
        FaState<int> lastValue )
    {
        //機械が取りうる状態
        var state = new FaState<int>[ ] { 
            new FaState<int>( 0, 0 ), 
            new FaState<int>( 1, 100 ),
            new FaState<int>( 2, 200 ),
            new FaState<int>( 3, 300 )
        };

        //入力できる記号
        var input = new int[ ] { 0, 100 };

        //状態遷移関数
        SampleConvertoer convert = new SampleConvertoer( );

        //初期状態
        var first = new FaState<int>( 0, 0 );

        //最終状態
        var last = new FaState<int>[ ] { lastValue };

        //作成( FA = { Q, Σ, δ, q0, F } )
        return new Fa<FaState<int>, int, int>( 
            state, input, convert, first, last );
    }
}

オブジェクト指向で有限オートマトンを表現してみるのサンプルと比べると、随分とすっきりして、有限オートマトンの定義が分かりやすくなったと思います。
 この記事を読んだ人の中には、随分と面倒だと思った人が居る事でしょう。ですが、実際のところは、全然面倒ではありません。慣れれば一瞬でできる事です。私は慣れているので、今回紹介したプログラムのイメージが直接瞬時に出てきます。ブログに書くときは、間違ったプログラムを逆算して書きました。ちょっと考えて本を読んでいる程度なので、全然負担に感じません。感覚的には小説を読むとき、風景などをイメージしながら読んでいると同じです。こうやって改めて文章で読むと、難解に感じるでしょうが、読書家ならば普通にしている事なので簡単です。おなかつ、学習効果も高いので、落ち着いて専門書を読むときに試してみてください。
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

オブジェクト指向で有限オートマトンを表現してみる

 1つ前の記事を読んで、オブジェクト指向プログラミングで、オートマトンを実装したらどうなるかについて気になった人が居るかと思います。また、オブジェクト指向プログラミングをしない方がよいと誤解した人が居るかもしれません。そこで今回は、オブジェクト指向プログラミングで有限オートマトンを実装する話題について書きます。
 早速ですが、よりオブジェクト指向プログラミングらしく、かつ素直に、有限オートマトンを実装した例を挙げます。

using System;
using System.Collections.Generic;
using System.Linq;

//有限オートマトン( FaOo : finite automaton )のオブジェクト指向版。
class FaOo<StateT, InputT>
    where StateT : FaState<InputT>
{
    //型システムにより必要なフィールドが減少する
    private StateT _firstState;
    private IEnumerable<StateT> _lastStateSet;
    private StateT _currentState;

    //受理
    public bool IsAccept
    {
        get
        {
            return this._lastStateSet.Contains( 
                this._currentState );
        }
    }

    //FaOoの定義( q0, F )でインスタンスを生成する
    //残りの( Q, Σ, δ )は型システムに任せている
    public FaOo(
        StateT firstState,
        IEnumerable<StateT> lastStateSet )
    {
        this._firstState = firstState;
        this._lastStateSet = lastStateSet;
        this._currentState = firstState;
    }

    //記号1つを指定して現在の状態を遷移させる
    public bool StateTransition( InputT input )
    {
        this._currentState =
            ( StateT ) this._currentState.NextState( input );
        return this.IsAccept;
    }
}


enum Coin
{
    Zero,  //硬貨投入なし
    One //100円硬貨一枚
}


//オートマトンの状態を表わす抽象オブジェクト
abstract class FaState<T>
{
    //次の状態を取得
    public abstract FaState<T> NextState( T input );

    public override bool Equals( object obj )
    {
        if ( this.GetType( ) == obj.GetType( ) ) return true;
        return false;
    }
}

abstract class SampleState : FaState<Coin> { }

class StateZero : SampleState
{
    public override FaState<Coin> NextState( Coin input )
    {
        if ( input == Coin.Zero ) return new StateZero( );
        return new StateOne( );
    }
}

class StateOne : SampleState
{
    public override FaState<Coin> NextState( Coin input )
    {
        if ( input == Coin.Zero ) return new StateOne( );
        return new StateTwo( );
    }
}

class StateTwo : SampleState
{
    public override FaState<Coin> NextState( Coin input )
    {
        if ( input == Coin.Zero ) return new StateTwo( );
        return new StateThree( );
    }
}

class StateThree : SampleState
{
    public override FaState<Coin> NextState( Coin input )
    {
        if ( input == Coin.Zero ) return new StateThree( );
        return new StateOne( );
    }
}

class Sample
{
    static void Main()
    {
        //自動販売機の有限オートマトンを用意する
        FaOo<SampleState, Coin> obj = Init( );

        //メッセージ変換用関数
        Func<Coin, string> GetString =
            ( Coin x ) => {
                if ( x == Coin.Zero ) return "0";
                return "100";
            };

        //100円投入してみる
        Coin input = Coin.One;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            GetString( input ),
            obj.StateTransition( input ) );

        //もう100円投入
        input = Coin.One;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            GetString( input ),
            obj.StateTransition( input ) );

        //投入したふりをしてみる
        input = Coin.Zero;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            GetString( input ),
            obj.StateTransition( input ) );

        //もう100円を投入
        input = Coin.One;
        Console.WriteLine( "{0}円投入しました。商品は出てきた?{1}",
            GetString( input ),
            obj.StateTransition( input ) );
    }

    static FaOo<SampleState, Coin> Init()
    {
        //最終状態
        var last = new SampleState[ ] { 
            ( SampleState ) new StateThree( ) };

        //作成( FA = { Q, Σ, δ, q0, F } )
        //※型システムにより簡潔化されている
        return new FaOo<SampleState, Coin>( 
            new StateZero( ), last );
    }
}

メタプログラミングをすればもっと短くなりますが、慣れていない人は読みにくいと思い、今回は愚直にプログラミングしました。以上のようにして、オブジェクト指向で有限オートマトンを実装してみると、新しいことがわかります。
 まず感じたのは、型システムのありがたさです。型システムにより、コンストラクタに指定する情報が減り、なおかつ、人間の入力ミスを減らすことができます。おまけに、ただの文字列よりも理解しやすいです。
 次に感じたのは、一度に知るべき情報が減るという事です。状態をオブジェクト化することにより、一度に考える状態遷移の数を減らせます。何故ならば、1つの状態オブジェクトを実装するときに、次の状態オブジェクトは何かを考えるだけでプログラミングできます。むろん、それは逆に言うと、一度に物事を考えない事も意味します。それで、思わぬ状態遷移の設計見落としが生じるかもしれません。ですがその短所は、設計とテストをすれば防げると思います。
 最後に感じたのは、余計な関数とデータの結合が生じる事です。オブジェクト指向プログラミングは、データと関数をセットで考えます。しかしながら、有限オートマトンは本来、状態と状態遷移関数を強く束縛して考えないと思います。何故ならば、たまたま同じ状態を使用する、オートマトンAとBがあったとします。このAとBの状態遷移が違うときサンプルの方法では上手くいきません。かといって、入力記号に結び付けるのも、有限オートマトンと関数を結びつけるのも、本来の意味から考えて間違いだと思います。これは、オブジェクト指向プログラミングでよくあるジレンマです。
 無暗にデータと関数を結びつけると本質が見えなくなります。従って、あえてオブジェクト指向プログラミングらしく実装しない方が良いときもあります。ただし、オブジェクト指向プログラミングで考えるという行為を否定しているのではありません。オブジェクト指向プログラミングで実装したほうがわかりやすいこともあります。
 今回は有限オートマトンしか実装していません。しかしながら、ミーリー型機械、ムーア型機械、チューリングマシン、非決定性有限オートマトンなどの性質を学びたい場合、オブジェクト指向プログラミングにしてみると、各概念の差異と共通点が良く見えてきます。従って、非オブジェクト指向とオブジェクト指向の両方で実装して、学習するとよいと思います。

テーマ : プログラミング
ジャンル : コンピュータ

オブジェクト指向は真理ではなくドメインに依存する

 オブジェクト指向は、当然のことながら、完璧な理論ではありません。盲目的に使用すると、余計にシステム開発の失敗要因となります。従って、オブジェクト指向の弱点を熟知する必要があります。そこで今回は、オブジェクト指向の弱点を書くことにしました。
 オブジェクト指向の弱点は、細かいところを言えば色々ありますが、その根本的理由はドメイン(問題領域)に依存することから発生しています。巷で誤解が発生するような表現が有名なものの、開発しようとしているドメインに即したものとしてオブジェクトは作成されます。従って、森羅万象あらゆることがオブジェクトで表現できるという誇大広告は一部誤りです。
 この理由は難しいので例を挙げます。例えば、オートマトンを実装するときのことを考えましょう。オートマトンをオブジェクト指向プログラミングで実装する場合、大概の人は状態をオブジェクトとして実装するでしょう。何故ならば、オートマトンの状態遷移関数と出力関数は、状態とセットで実装する方が保守性と拡張性が上がるからです。オートマトンの定義に正確に従って、状態を文字列として実装すると、長い多分岐処理(switch文やif文など)が必要となります。しかしながら、拡張性と保守性を考えると、この状態は好ましくありません。オブジェクト指向で考えたとき、そういう考えから、状態をオブジェクト化して、一部の関数で多分岐プログラムを書くことを避けます。こうすることにより、状態遷移が複雑化した時の、拡張と保守を容易にします。これがオブジェクト指向プログラミングの定石です。
 オブジェクト指向プログラミングの多分岐を避ける定石は、正しく絶対的なように感じる人もいるでしょう。しかしながら、オートマトン本来の意味を改めて考えてみると、必ずしも正解とは言えない事に気づきます。というのも、状態遷移と関数は本来別々のものだからです。たまたま、そのドメイン内でそうなっているからと言って、状態が常にそうなるとは限っていません。状態の本質から離れてしまっています
 これは、システム開発の根源に起因する問題です。誰しも求められるシステム以外の要因をオブジェクトに求めません。学術的に正しいからと言って、ビジネスシステムの人間オブジェクトに、遺伝子などの詳細な情報を実装しません。すなわち、世界の真理とシステムとは明確な乖離があり、オブジェクトは真理ではなく、ドメインに依存しているのです。
 この問題は取るに足りない問題だと考える人が大半でしょう。システム開発が我々のお仕事であり、使用しない真理を追い求める必要はありません。いえ、それどころか、そうする行為は有害だからです。しかしながら、真理とドメインが乖離している事を意識せず、オブジェクト指向が絶対的に正しい錯覚している状態でシステム開発をすれば、見落とされた矛盾がプロジェクトを失敗へと導きます。プロジェクトが失敗する原因は、大きな一つの要因ではなく、小さな無数の要因から構成されています。
 しかし、勘違いしてはならなりません。弱点があるからオブジェクト指向を採用しないという考えは間違いです。何故ならば、全ての人間の思考法に間違いがあり、完璧な方法など存在しないからです。やはり、狼男を撃つ銀の弾丸は存在しません。
 我々技術者およびシステム開発の関係者がするべきことは盲目的な否定でなく、妄信でもなく、長所と弱点をよく把握し、お客様を満足させることです。お客様がついていけない高尚なシステムは要りませんし、迷信に基づくシステムもいりません。お客様を満足させるのが唯一無二の目的であり、それだけを目指するべきと私は考えています。

テーマ : 情報処理技術
ジャンル : コンピュータ

オブジェクト指向の本質

 オブジェクト指向といえば、情報の隠蔽、継承、多態性が有名です。この言葉を知っている人は多いと思います。しかしながら、この3つの言葉の意味を本当の意味で理解している人が少ないと思います。そこで今回はオブジェクト指向の本質について書くことにしました。
 初めに言っておかねばならないことは、オブジェクト指向とは分析(OOA)・設計(OOD)・実装(OOP)の3つの事を考えねばならないという点です。オブジェクト指向はソフトウェア工学のあらゆる領域にまで発展しており、この3つのOOXがあることを念頭に置かねば足りません。さらに、OOA/OOD/OOP(OOX)はいくつも亜流があります。
 提唱者は同時に定義することが多いので、OOAとOODは大概手法が重なっています。それら方法論の中で有名なのは、リカーシブ開発、Booch手法、Coad/Yourdon手法、Texel手法、OMT、SOMA手法、OOSD、OOSE、MERODE手法、SSADMです。私は一応、これら手法に目を通しました。これら方法論の違いは、開発で起こる現象をどのようにしてとらえるのかという点にあります。共通点は分析・設計・実装の流れをスムーズにすることです。オブジェクト指向よりも前に使われていた構造化設計法は、この視点が不足していました。誤解されやすいのですが、オブジェクト指向方法論は、構造化設計技法の知識を前提としています。構造化設計技法を知らないと真に理解できません。また、実際にシステム開発をするときはアジャイル開発の手法とセットで使います。オブジェクト指向方法論は閉じたものではないのです。
 OOPにおいても、特定の言語だけのものではありません。よく見られる間違いは、C++などの特定言語のOOPに思考が縛られる事です。OOPを真に理解するには、少なくとも命令型、関数型、論理型、集合型、宣言型、の各種言語に触れる必要がありますし、さらに静的な型と動的な型によるOOPを経験せねばなりません。これらのOOPを経験して分かったことは、状態と抽象化と制御がOOPの核だといえるということです。
 オブジェクト指向を言語モデルとして考えたとき、キーとなるのは状態の変化です。OOPをする時点で、状態の変化が伴います。何故ならばOOPは、状態ありの計算モデルだからです。
 状態をどのようにして扱うのかという点で、OOPは役立ちます。モジュール性はOOPでなくともありますが、OOPはそれをさらに進めて、ある程度統一した方法でデータの抽象化とプロセスの抽象化を統一化します。さらに、情報の隠蔽の考えを適用し、スコープの範囲を制御します。これにより、変化に強いプログラミングが可能となります。
 もうお分かりになったと思いますが、情報の隠蔽・継承・多態性の3原則は、変化に対処するための概念です。すなわち、あらゆる変化をいかにして扱うのかというのがテーマであり、オブジェクト指向の本質なのです。情報の隠蔽により変化がもたらす影響範囲を狭め、継承により拡張性をもたらし、多態性によりバリエーションと統一性を実現します。
 オブジェクト指向の本質は変化への対処です。オブジェクト指向にある多種多様な概念に触れ、変化に対処する術を学びましょう。そうすれば、きっと優れた開発者になれるでしょう。

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門26

 この記事は、実践的オブジェクト指向設計入門25の続きです。前回は、物理的なパッケージ化について解説しました。今回は、設計における決定事項の文書化を解説します。
 いよいよ、オブジェクト指向設計の最後の作業です。今まで設計で様々な決定を下してきました。それらの決定を文書化する必要があります。システムは終わりがありません。後でシステムをバージョンアップする場合や、開発の途中で仕様が変更される場合すらあります。そうした状況が起こることを前提に、担当者が変わっても今までの流れがわかる状態にせねばならないのです。そのために文章を清書します。
 ただし注意するべき事があります。それは、下書きは他の作業と並行するのが前提である事です。いきなり全てを文章化しようとしても上手くいきません。全ての決定事項を、詳細かつ正確に覚えていられないでしょう。しかしながら、文書化という手段を目的にしてしまう人が居ます。こうした過ちは人間ならば誰しもする可能性があります。文書化はあくまでも手段であって目的ではありません。十分に注意しましょう。
 以上でオブジェクト思考法論OMTにおける、オブジェクト指向設計は終わりです。世の中にはほかにも方法論がありますし、物事は教科書通りに進みません。オブジェクト指向方法論OMTを学び、その知識を応用しましょう。そうすれば、システムの品質は飛躍的に上がるでしょう。この連載を読んでくれた方のご活躍を心から願っています。終わり。

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門25

 この記事は、実践的オブジェクト指向設計入門24の続きです。前回は、オブジェクトの表現について解説しました。今回は、物理的なパッケージ化について解説します。
 今回解説するのは、いよいよ最後の1個手前の作業です。この段階まで設計が進むと、後考えるべきことは、どのようにオブジェクトをパッケージ化するかです。パッケージ化するにあたって、考えるべきことは、情報隠蔽実態の一貫性物理的なモジュールの構築の3点です。これから個々の要素を解説します。
 情報の隠蔽とは、オブジェクト指向のカプセル化の事です。つまり、余計な細部に悩まされることなく、オブジェクトを使用できるように、余計な情報を隠すことを指しています。しかし、何でも隠せばよいというものではありません。極論を言うと、1個の何でもできるオブジェクトがあれば隠蔽度は最大です。ですが、1個の何でもできるオブジェクトを定義してしまうと、分担作業ができなくなりますし、仕様変更や機能拡張に耐えられない設計になってしまいます。設計者は、何の情報を公開するのかをよく考えなくてはなりません。オブジェクト指向の基本は隠蔽であり、何の情報を公開するのかを考える事が肝要です。
 実態の一貫性は、クラス、操作、インタフェースなどといった要素を、設計思想にそって一貫させることです。個々の要素に一貫性があると、将来拡張するのも容易ですし、途中参加したプロジェクトのメンバーの仕事がやりやすくなります。具体的には、命名規則が挙げられます。命名規則がおろそかにされることが多いのですが、人間は名前で意味を理解しようとするので非常に重要です。名前とまったく違う動きをするオブジェクトを理解することは容易ではありません。
 最後のモジュールの構成は、簡単に言うとオブジェクトの分割の仕方です。オブジェクトの粒度をどれくらいにするのか、アセンブリやDLLといった物理的なファイルをどのようにするのか、インタフェースをどのようにするのかなどといったことを考えます。一見簡単そうに見えますが、非常に複雑なものです。参考文献をあげます。




ほかにも参考になる書籍と、必要となる書籍がありますが、ひとまずこの3冊を押さえておきましょう。設計の世界も奥深いものです。続く...

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門24

 この記事は、実践的オブジェクト指向設計入門23の続きです。前回は、関連の設計について書きました。今回は、オブジェクトの表現について書きます。
 オブジェクト指向方法論OMTは、基本データ型を使う状況と、関係するオブジェクトを組み合わせで使うのはどんな状況なのかを、明確に定義しなくてはならないと説いています。ちょっとわかりにくいので噛み砕いて説明します。
 オブジェクトの属性を表現するとき、大まかにいうと、基本データ型(整数型、実数型、文字列型など)で表現するのか、特別なオブジェクトを定義して表現するのかの2通りの方法が考えられます。例えば、社員オブジェクトの属性・住所に使用する郵便番号は、文字列で表現できますし、オブジェクトでも表現できます。どちらが良いのでしょうか?こうした実装者の疑問に対し設計者は、明確に答えねばなりません。しかし、どちらの方法が良いのかは決まっていません。絶対の答えがないからこそ設計者の腕の見せ所なのです。絶対の答えがないというのが分かりにくいと思いますので、両方法についてちょっとだけ詳しく書きます。
 先程の例でいうと、郵便番号を文字列で表現すると簡単に扱えるように思うでしょう。しかし、実現するシステムにより、簡単か否かは変わってしまいます。社員の住所を表示するぐらいの処理しかなければ、文字列でも問題はないでしょう。ですが、郵便番号を解析して複雑な処理をするようなシステムならば、オブジェクトにしたほうが簡単に実装できます。すなわち、実現しようとしているシステムで可否が決まります。よくいわれる、設計のトレードオフの一つといえます。
 絶対に正しい答えというものがないので、設計者はトレードオフに対して、毅然とした態度で決定を下しましょう。もちろん、そこには設計思想がなければなりません。設計思想がないその場限りの決定は、現場を混乱に陥れるだけです。十分に注意しましょう。
 以上がオブジェクト指向方法論OMTの説明です。私個人の考えを付け加えます。日本の状況を考えると、この作業は余計な干渉のもとになるから注意する必要があると思います。日本では、プログラミングを知らない設計者がいます。そんな設計者がデータ型にまで口を出すと、プログラマーの仕事がやりにくくなるだけです。むろん、プログラミングを知らずとして正しい設計などできないと思いますが、日本の体制ではそうなっているので柔軟に対応するしかありません。
 それともう一つ注意するべき点があります。それは、プログラミングと設計の境が薄くなるという点です。もともと設計と実装は切り離された工程ではなく、数直線のように無限に途切れなく続くものですが、設計と実装の目的の違いを常に意識しなければなりません。やはり、設計と実装は違います。この作業(オブジェクトの表現を考える)をする際には特に注意しましょう。

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門23

 この記事は、実践的オブジェクト指向設計入門22の続きです。前回は、継承の調節について解説しました。今回は、関連の設計について書きます。
 オブジェクト指向設計は、オブジェクトそのものについて着目するだけではなく、オブジェクトの関連についても熟考が必要です。情報システムにおいて設計するオブジェクト群が、単独で存在する事は稀で、互いになんらかの関連を持ちます。従って、オブジェクトの関連についても分析と設計が必要なのです。
 オブジェクト指向方法論OMTでは、関連のたどられ方の分析が提唱されています。設計段階では、オブジェクトモデル中の関連を実装する戦略を明確化する必要があります。オブジェクト間の関連を明確にしておかないと、実装の詳細に意識を奪われ設計が失敗します。関連は双方個のものが大半ですが、本当にそうなのかよく分析すると、システムの流れと本質がよく分かります。具体的には、関連の方向と多重度が重要です。
 関連には、互いに参照する双方向と、どちらかが参照しかしない片方向があり得ます。普通に考えて、双方向の場合が多いと思うでしょうが、同じ双方向でもオブジェクト群としてみたとき、設計によりパス数が異なります。上手く設計すれば、同じ操作をするにも効率よく操作できます。ですが、あえて余分なオブジェクトを加えることにより、より柔軟で再利用性が高い設計が可能となる場合もあります。GoFデザインパターンがよい例です。ただし、余分なオブジェクトを無目的に追加しても、混乱をもたらすだけです。よく注意しましょう。
 関連は多重度も大切です。主となるオブジェクトが1、使われるオブジェクトが多数というのがよくあるパターンです。他にも、多対多の関係のオブジェクトもよくありますが、関連オブジェクトを追加して、多対1の関係にすることを検討しましょう。そういった関連の重要さはデータベース設計となんら変わりません。
纏めます。個々のオブジェクトを設計するだけではなく、オブジェクト間の設計も必要だと言う事です。設計と実装の違いはこういった所で現れます。続く...

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門22

 この記事は、実践的オブジェクト指向設計入門21の続きです。前回は、並列タスクによる制御について解説しました。今回は、制御の実装の次の作業である、継承の調節について解説します。
 オブジェクト指向設計が進んでくると、操作やオブジェクトが複雑化してきます。そこで、継承関係が無いのかチェックします。ある程度の規模のシステムとなると、オブジェクトの数は膨大となります。膨大なオブジェクトは、設計の理解を困難にし、あらゆる作業に悪影響を与えます。従って、継承による設計の簡素化が重要となるのです。
 オブジェクト指向方法論OMTでは、設計を簡素化するために、継承の検討が提唱されていますが、それと同時に 注意もされています。継承はカプセル化の原則を崩します。無理な継承関係は、余計にシステムを複雑化してしまいます。ですから、継承だけではなく、委譲も視野に入れて設計のリファクタリングを行いましょう。
 ただし、継承と言っても実装の継承とインタフェースの継承がある点に注意して下さい。プログラムの量を減らす事だけを考えて設計しても、オブジェクトの構造が複雑化し、余計に実装を困難にします。インタフェースの継承を賢く活用しましょう。

テーマ : ソフトウェア開発
ジャンル : コンピュータ

実践的オブジェクト指向設計入門21

 この記事は、実践的オブジェクト指向設計入門20の続きです。前回は、状態機械エンジンについて解説しました。今回は、最後の制御の実装である、並列タスクによる制御について解説します。
 オブジェクト指向方法論OMTが書かれた時代には、並列タスクはあまり一般的ではありませんでした。それ故、オブジェクトをタスクと見做し、それを並列に扱う事しか書かれていません。しかしながら、今現在は並列タスク制御が一般的ですので少し書き足します。
 オブジェクトは一つのタスクと看做せます。また、一つの処理を複数のタスクに分けることも簡単です。問題となるのは実装ではなく、どの様に事象を表現して設計するかです。搭載されるCPUのコア数は年々に増加していますが、それでも無限でありません。有限のリソースを、どの様に使用するのかを考えるのが設計です。
 具体的には、時間と処理プロセスの関係について分析します。直列的な処理でよい時代は、あまり時間に注意を払いませんでした。しかしながら、並列処理では、タスクが資源を占有している処理区間が非常に重要です。従って、時間に注目せねばならならないのです。
 並列処理システムの設計は一大トピックですので、全然書き足りませんが、ひとまず時間と処理の関係について分析する所が要点です。他の事柄については、並列処理全般を学ぶしかありません。実際に並列処理システムを設計すると自ずと分かります。続く...

テーマ : ソフトウェア開発
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター