2010年7月23日金曜日

クラスの作り方

Javaプログラミングでは、まず、クラスが必要となります。それでは、クラスを設計する上での基準などあるのでしょうか?。これが、正しいかはわかりませんが、私が考えるクラス設計方法について述べたいと思います。
私は非常に長い間、構造化プログラミングに従ってプログラム設計を行っていましたが、システムプログラム分野では、データの関連をポインターを使ったツリーやノードで表現するデータ構造が決まるとほとんど、プログラム構造が決まってくることがわかってきました。その結果、プログラミングの多くの時間はデータ構造の設計に費やすようになりました。データ構造の設計では、今後、想定される仕様変更や機能追加に対応できるかが大きなポイントとなります。
オブジェクト指向の設計方法でも、クラスを単位を決定するには、今後、どのような仕様変更があるか、作成したクラスが他のモジュールで再利用できるかを観点に決める必要があると思います。
高速性が必要とされるサブルーチンや仕様変更が発生することが想定されないサブルーチンに迄、クラス化する必要はないと思います。

Yawdbaでは、クライアントからWebリクエストから、クライアントのブラウザやパラメータなどを内部データに持つクラスインスタンスを作成し、その後の処理では、このクラスインスタンスのみを使用して処理します。もし、クライアントからの呼び出し方法が変更された場合には、このクラスインスタンスを拡張するだけで、後続の処理に影響を与えないことが可能にしています。

構造化プログラミング

わたしが、プログラマーになったころ(1978年頃)、大量のソースコードを開発する方法として構造化プログラミング手法が確立したころでした。それまでのアセンブラやFortranなどのプログラムロジックには、プログラムを開発する手法がなく、ロジックを記述する手法としてフローチャートがあったのみでした。
構造化プログラミング手法では、 順次繰り返し分岐を組み合わせて論理構造を作り上げるものです。このように論理構造を限定化することにより、大量のソースコードの品質を向上することが可能となりました。最近のプログラム言語では、このような構造化プログラミング技法での順次・繰り返し・分岐をif文やwhile文などの構文として組み込まれています。
したがって、CやJava,VisualBasicなどを使ってgoto文を使わずにコーディングすれば、まずは、構造化プログラミング手法に準じたプログラムとなります。
私の知っている人で、ロジックを従来の方法で設計してフローチャートで記述した後、このフローチャートから順次・繰り返し・分岐の構造を作り出した人がいました。しかし、このモジュールの非常に分かり難く、デバッグが非常に困難になってしまいました。このような方法は、構造化プログラミングとは言えません。

2010年7月18日日曜日

Cプログラマーから見たJava

私は、長くC言語(約20年くらい)プログラミングを行ってきました。当初、C言語は、CobolやFortranには無かった構造化設計が可能な上に、PL/IやPascalで可能であったポインタが利用できる点において、システム開発では有効であったと思います。(PL/Iは、コンパイラーが非常に重くIBMコンピュータでしか完全には利用できませんでしたし、Pascalでは、ビット演算など小回りの効くコーディングができなかったり、オブジェクトモジュール別の開発が面倒でした。)
その後、SmallTalkなどの成功によりオブジェクト指向プログラミングが流行るようになると、C言語でも同様の処理系が開発できないかと言うことが検討されC++が開発されました。しかし、C++を利用せずに、C言語でオブジェクト指向風のコーディングでできないかというアプローチも行われました。なぜ、オブジェクト指向プログラミングが大切かお話するまえに、C言語でオブジェト志向風プログラミングを行うコーディングにつてお話しましょう。これが、分かるとJava処理系の動作について分かるかと思います。

クラスには、インスタンスとメソッドがありますが、これは、C言語での構造体で定義します。インスタンスについては、構造体内の一般の変数、メソッドは、関数へのアドレスを格納します。

例えば、次のように書きます。
struct {
  int  instance;
  int  (*get_method)(void);
}  myClass;

instanceフィールドは、このクラスのインスタンス変数を格納するフィールドであり、get_methodフィールドは、get_method関数ポインターが格納されます。オブジェクト指向は、それぞれのオブジェクト毎に内部インスタンスとメソッドがありますが、このようにすることで、C構造体に付随するインスタンスとメソッドを定義します。あとは、この構造体を通じて、メソッドを通じて操作することでオブジェクト指向を実現します。

しかし、この構造体では、get_methodフィールドは、単に関数ポインターが格納されると宣言しているだけで、実際の関数アドレスが可能されている訳ではありません。そこで、これらの構造体に関数アドレスを事前に設定する必要があります。これらの初期設定する部分を関するにして、上記構造体のアドレスを返却する関数を以下のように用意します。
  myClass *handle = Create();

このCreate関数で、get_method関数アドレズを設定したります。このようにすると、次のように利用できます。
  thisValue =(* handle->get_method)();

Javaでもオブジェクトをクラスから作り出す際に、newオペレーターを使っていますが、内部的には、クラス特有に存在している構造体に、メソッド関数などを定義したり、各クラス内のインスタンス関数を実行しているものと思われます。この方法で、擬似的にオブジェクト指向風のプログラムを作成することができますが、クラスのインヘリタンス(継承)機能をC言語で記述することはできません。

2010年7月11日日曜日

Excelって印刷のことを考えていないと思う

みなさんは、Excelを使って印刷するケースが多いと思いますが、実は、Excelからの印刷では注意すべき点が沢山あります。
Wordなどでは、Wordのファイルメニューにあるページ設定で用紙サイズを指定すると、この用紙で印刷されます。プリンタドライバーの印刷設定に「用紙サイズ」や「原稿サイズ」などの設定がありますが、この用紙サイズを変えても、Wordで設定した用紙サイズで印刷され、印刷レイアウトはあまり変化しません。つまり、Wordでは、Wordで指定された用紙サイズで印刷のレイアウトが決定され、プリンタドライバによって変化することはありません。
一方、Excelでは、印刷指示を行った際に、プリンタドライバで設定した用紙サイズやExcelの[ページ設定]で指定した「用紙サイズ」に合わせて、Excelで印刷できる行数や桁数を計算して印刷します。Excelのページ設定で印刷領域から印刷ページ数を指定してレイアウトを決定する方法もありますが、印刷レイアウトは、プリンタドライバの能力(解像度・印刷可能領域サイズ・搭載フォント種類)によって自動的に変化します。
このため、プリンタドライバを変えてしまうと、思ったように印刷されないなどの現象が発生します。
Excelは、基本的にセルで計算するためのソフトであり、印刷に向いていないことを十分知っておく必要があります。

2010年7月4日日曜日

コンピュータ昔話(PC起動をなぜブートと言うか)

みなさんは、PCを立ち上げる際にブート(Boot)するといいますが、なぜかご存知でしょうか?昔のコンピュータでは、ハードウェアリソースが限られており、そのためにシステムを立ち上げるために必要なプログラムをROMに書き込んでおくことができませんでした。
そこで、最低限の入出力を行う処理だけがコンピュータハードウェアとして用意されており、PCを立ち上げるプログラムをメモリにロードする手順(ブートストラップローダー)を行った後、立ち上げ少しずつ機能を加えながら立ち上げを繰り返しました。まるで、靴紐を編み上げるようにコンピュータを起動するために、コンピュータの立ち上げをBootStrap(靴紐)と言いました。ブートストラップからストラップが無くなり、現在では、PCを立ち上げるのにブートと言うようになりました。


サーブレットからクライアントブラウザを知る方法

お久しぶりです。一ヶ月以上空いてしまいました。
サーブレットは、クライアントブラウザからに表示指示に対して、クライアントブラウザにHTMLページを送信します。しかし、クライアントブラウザの表示機能には差があるため、クライアントブラウザによっては、出力するHTMLページを変更する必要があります。
サーブレットを構築するためのTomcatでは、リクエストを発行したブラウザを検知する方法があります。
クライアントからブラウザ表示指示を送信すると、サーブレット上のdoGetやdoPostメソッドが呼び出されます。この際のパラメータであるHttpServletRequest内のヘッダーからユーザーエージェント文字列を取得してブラウザを判別することが可能です。
世の中にある各ブラウザのユーザーエージェント文字列は、userAgent一覧のように沢山ありブラウザを特定するプログラムを作成するのは大変面倒です。

このようなとき、私は、JavaのStringTokenizerを使って対応しています。
StringTokennizerは、文字列内の空白など文字列を分割する文字(区切り文字)を指定します。すると、この文字が発見されると同時に、分割することができます。

例えば、
    StringTokenizer st = new StringTokenizer(myString, " /");
    while(st.hasMoreTokens()) {
      String s = st.nextToken();
    }
とすると、区切り文字が空白と「/」なので、myString文字列が、"aaaa/bbbb"の場合には、"aaaa"と"bbbb"に分割されます。これをnextTokenメソッドとhasMoreTokenメソッドを使って取り出します。

このメソッドを使って、ユーザーエージェント文字列を解析し、ブラウザを判断することができます。さらに、ブラウザのバージョン情報などの取得も可能です。

    StringTokenizer st = new StringTokenizer(user_agent, " ();,/");
    while(st.hasMoreTokens()) {
      String s = st.nextToken();
      if(0 <= s.indexOf("MSIE")) {
        browser = IEブラウザ
        break;
      }
      if(0 <= s.indexOf("Chrome")) {
        browser =Chromeブラウザ
        break;
      }
      ......
      ......
    }

皆さんも、使って頂ければと思います。