ChaichanPapa-World !

燈明日記(2004/03

◆ インデックス

◆ 2004年3月

2004/03/25(木)最終回に思う

実は、木村拓哉の『プライド』と草薙剛の『僕かの』の最終回を見ました。

両方とも、役者もスタッフも気合が入りすぎているのがひしひし伝わり、逆にイマイチだったように感じました。ハルさんがスターになってしまう演出や、凛ちゃんへ不自然に『ハイ』と言わせる演出などなど……。

しかし、どちらも、結構、感動しましたよ。最終回以外で、たまたま見た時は。

職場でも、凛ちゃんぽい『ハイ』が、流行っているような、いないような……。


実は、またまた、バグ出しちゃって、こんな駄文を書いている場合じゃないんです。

この調子だと確実にリストラコースやな。どうしよう。

2004/03/22(月)仕事でのケアレスミス

また、やってしまった。かなり、落ち込んでおります。

なんで、単純ミスを犯してしまうのだろう。ちょっと見直せば回避できたのに……、緊張感とか、意識の高さとかが、欠けているのかな……、やはり。

と、云う事でしばらく謹慎しています。

2004/03/20(土)イテレータパターン

いままで、オブジェクト指向を学んで、アプレットサーブレッドウィンドウズAPドスAP等の初歩的なプログラムをJavaで組んできました。

そして、やっと今回、初歩的なプログラムを1歩踏み出したデザインパターンイテレータを紹介する時が来たのです。

慣れないと、なにかと、チンプンカンプンなデザインパターンですが、これをマスターすると、マスター後がなにかとラクができるみたいなのです。

ですので、今、頑張ってマスターしてしまいましょう!

イテレータとは

イテレータとは、複数のオブジェクトに順番にアクセスし、それを1つ1つ数え上げることをいいます。

では、参ります。

イテレータの例題

とあるコンピュータの修理会社で、修理で使うコンピュータの部品を部品棚に入れて管理をしていました。

そして、部品棚に部品を格納し、その一覧リストを表示することになりました。

さて、ここで問題です。

部品棚に部品を格納し、その一覧リストを表示してください。
イテレータの例題の解答

まず、はじめにクラスを抽出してみましょう。

の2つは、すぐ思いつきます。 とりあえず、クラス図を書いてみましょう。


     +----------+----------+
     | 部品棚              |
     +---------------------+
     | addBuhin()          |
     |                     |
     |                     |
     |                     |
     +---------------------+
                O
                |
                |
                V
     +----------+----------+
     | 部品                |
     +---------------------+
     | name                |
     +---------------------+
     | getname()           |
     |                     |
     +---------------------+

部品棚に部品を格納しなくてはならないので、部品棚クラスは、部品を格納するaddBuhin()メソッドが必要です。 また、格納(集める)することは、、部品クラスとの関係は集約です。

部品クラスは、とりあえず、名前フィールドと名前を取得する getname()を用意しましょう。

また、モノとしては、部品棚と部品ですが、部品棚の部品を走査して一覧をもとめる概念を部品イテレータとしてクラスとします。 この部品イテレータクラスは、部品を走査するメソッドnext()と、走査したとき次の部品があるかを見極めるメソッドhasnext()を持 ちます。

ここまで、整理するとクラスは以下の3つになります。

ここまでが、ごく普通のオブジェクト指向での設計です。

しかし、オブジェクト指向では、常に、再利用とシステムの成長を考慮して設計をしないとなりません。 再利用とシステムの成長を考慮しての設計とは、ずばり、クラスを抽象化してクラスの結びつきを弱くすることに他なりません。

ですので、集めた部品が数えられる部品棚クラスを抽象化した、『集めたある物が数えられる』というAggregateクラスを加えます。

また、部品を数える部品イテレータクラスを抽象化した、『あるものを数える』というIteratorクラスを加えます。するとクラス図は、以下のようになります。


     +---------------------+                 +-------------------+
     | Aggregate           |---------------->| Iterator          |
     +---------------------+                 +-------------------+
     |                     |                 |                   |
     |  iterator()         |                 | hasnext()         |
     |                     |                 | next()            |
     |                     |                 |                   |
     +---------------------+                 +-------------------
                #                                      #
                |                                      |
                |                                      |
                |                                      |
     +----------+----------+                 +---------+---------+
     | 部品棚              |<---------------O| 部品イテレータ    |
     +---------------------+                 +-------------------+
     | buhins              |                 | aggregate         |
     | last                |                 +-------------------+
     +---------------------+                 |                   |
     | addBuhin()          |                 | hasnext()         |
     |                     |                 | next()            |
     |                     |                 |                   |
     +---------------------+                 +-------------------+
                O
                |
                |
                V
     +----------+----------+
     | 部品                |
     +---------------------+
     | name                |
     +---------------------+
     | getname()           |
     |                     |
     +---------------------+

Aggregate と Iterator は、今回は、抽象クラスではなく、インターフェイスとしましょう。 なぜかというと、今回は、数えられるというインターフェイスと数えるというインターフェイスで充分だからです。

部品棚クラスは、Aggregateインターフェイスをインプリメントして、addBuhin() 等のメソッドを持ち、部品クラスを集約します。

部品イテレータクラスは、Iteratoreインターフェイスをインプリメントして、部品棚クラスを集約します。 部品クラスは、名前を持ち、それを得るメソッドgetname() があります。

コーディング

では、Javaでコーディングしていきましょう。

・Aggregateインターフェイス
public interface Aggregate {
    public abstract Iterator iterator();
}

本インターフェイスは、『集めたある物が数えられる』ものなので、抽象メソッドのIterator()を定義します。

・Iteratorインターフェイス
public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();
}

本インターフェイスは、『あるものを数える』というものなので、抽象メソッドの『次があるかを求めるhasNext()メソッド』と『次のあるものを走査するnext()メソッド』を定義します。

・部品イテレータクラス
public class BuhinIterator implements Iterator {
    private Buhindana buhindana;
    private int index;
    public BuhinIterator(Buhindana buhindana) {
        this.buhindana = buhindana;
        this.index = 0;
    }
    public boolean hasNext() {
        if (index < buhindana.getLength()) {
            return true;
        } else {
            return false;
        }
    }
    public Object next() {
        Buhin buhin = buhindana.getBuhinAt(index);
        index++;
        return buhin;
    }
}

本クラスは、Iteratorインターフェイスの抽象メソッドhasNext()とnext()を実装します。

・部品棚クラス
public class Buhindana implements Aggregate {
    private Buhin[] buhins;
    private int last = 0;
    public Buhindana(int maxsize) {
        this.buhins = new Buhin[maxsize];
    }
    public Buhin getBuhinAt(int index) {
        return buhins[index];
    }
    public void addBuhin(Buhin buhin) {
        this.buhins[last] = buhin;
        last++;
    }
    public int getLength() {
        return last;
    }
    public Iterator iterator() {
        return new BuhinIterator(this);
    }
}

本クラスは、部品を格納する配列を作成したり、逆に配列から部品を取り出したり、あと、イテレータを委譲しています。

この委譲ですが、これが、イテレータパターンのポイントになります。Aggregateインターフェイスから継承した抽象メソッドiterator()を実装します。この時、部品イテレータクラスのインスタンスを返すメソッドにします。

そして、 部品イテレータクラスのインスタンスがIteratorインターフェイス型で返されることに注目してください。

つまり、このiterator()メソッドを呼ぶ側にとって、部品イテレータクラスの存在は、知らなくてすむのです。

このようなテクニックによって、クラスの結びつきを弱くすることが出来るのです。

・部品クラス
public class Buhin {
    private String name = "";
    public Buhin(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

本クラスは、部品名と部品名取得メソッドを持ちます。

・メインクラス
public class Main {
    public static void main(String[] args) {
        Buhindana buhindana = new Buhindana(4);
        buhindana.addBuhin(new Buhin("CPU"));
        buhindana.addBuhin(new Buhin("メモリ"));
        buhindana.addBuhin(new Buhin("マザーボード"));
        buhindana.addBuhin(new Buhin("ハードディスク"));
        Iterator it = buhindana.iterator();
        while (it.hasNext()) {
            Buhin buhin = (Buhin)it.next();
            System.out.println("" + buhin.getName());
        }
    }
}

本クラスは、イテレータを使用したAPそのものです。 部品棚を作成し、そこへ4つの部品を登録し、イテレータを使って、部品棚を走査し、部品名の一覧リストを表示しています。

まとめ

普通、手続き型C言語等で上記を組むと、部品の入っている配列をforループで回して、部品名の一覧リストを表示します。

一方、オブジェクト指向型のJavaでは、なぜ、イテレータを使って、面倒くさく組むのでしょうか……。

大きな理由は、イテレータを使うことで、実装とは切り離して数え上げることが出来るからです。

それは、部品棚クラスのところですでにご説明した通りです。

つまり、オブジェクト指向では、クラスを抽象化してクラスの結びつきを弱くすることで、再利用とシステムの成長にたいして柔軟性を持つことができるのです。

終わりに

どうでしたか、わかりましたか、オブジェクト指向は難しいので、説明するのも理解するのも大変です。 あせらず、徐々に学んで参ましょう。では、また!

尚、本コンテンツ作成するにあたって、結城さんの『Javaで学ぶデザインパターン』を大変参考にさせていただきました。ここに厚く御礼申し上げます。

2004/03/17(水)クラス図もどき

とりあえず、オブジェクト指向のおさらいです。

オブジェクト指向とは、対象となる実世界(モノと概念)について考えようという指向です。
オブジェクトとは、モノと概念です。
クラスとは、オブジェクトの雛型で、属性・操作・メッセージを持ちます。

さて、おさらいが終わったところで、デザインパターンといきたいところですが、 しかし、その前に、UMLのクラス図の習得がデザインパターン理解には有効ですので、 先にUMLのクラス図をご説明します。しかし、クラス図といっても、クラス図もどきです。ちゃんとしたヤツは、UMLの然るべき本やサイトで学んでください。

では、簡単にUMLを紹介すると、UMLとは、オブジェクト指向で設計をする時のモデリングの単なる表記方法で、9種類の図があります。特にクラス図が重要なので、今回は、クラス図だけを説明します。

クラス図のサンプル

たとえば、コンピュータの部品を部品棚にしまうことをモデリングしてみましょうか。

まず、部品クラスには、名前(name)と名前を取得するメソッド(getname() )があるとします。

これをクラス図で表すと以下のようになります。

     +----------+----------+
     | 部品                |
     +---------------------+
     | name                |
     +---------------------+
     | getname()           |
     |                     |
     +---------------------+

クラス図は、上記のように長方形を3つに区切り、上からクラス名(部品)、フィールド(name)、メソッド(getname() )を記述します。

そして、クラス間の関係は、関連・集約・継承の3つ(実際はもっとある)があり、以下の線で表します。 矢印は、使用する側のクラスから、使用される側のクラスへ向かいます。つまり、使用される側のクラスは、誰が自分を使用するかは関知しません。使用する側のクラスは、当然、知っているからこそ使用できるわけです。

 Association:       Aggregation:           Inheritance:
 関連               集約                   継承
        ^                   O                      #
        |                   |                      |
      <-+->               O-+-O                  #-+-#
        |                   |                      |
        V                   O                      #

     +----------+----------+
     | 部品棚              |
     +---------------------+
     | buhins              |
     | last                |
     +---------------------+
     | addBuhin()          |
     |                     |
     +---------------------+
                O    (使用する側)
                |
                |
                V    (使用される側)  
     +----------+----------+
     | 部品                |
     +---------------------+
     | name                |
     +---------------------+
     | getname()           |
     |                     |
     +---------------------+

上記をJavaでコーディングすると以下のようになります。 尚、普通、コンストラクタは、クラス図には記述しません。

public class  Buhindana{           //使用する側のクラス
    private Buhin[] buhins;
    private int last = 0;
    public Buhindana(int maxsize){ //コンストラクタ
        this.buhins = new Buhin[maxsize];
    }
    public void addbuhin(Buhin buhin){
        this.buhins[last] = buhin;
    }
}

public class  Buhin{               //使用される側のクラス
    private String name = "";
    public Buhin(String name){     //コンストラクタ
        this.name = name;
    }
    public void getname(){
        return name;
    }
}

尚、Javaソース関して、結城さんの『Javaで学ぶデザインパターン』を大変参考にしています。

2004/03/15(月)デザインパターン

デザインパターンとは、さて何でしょうか、辞書を引いてもまず出ていません。

デザインとパターンは、両方とも一般語で良く使いますが、デザインパターンとは……。

実は、単にデザインパターンといった場合は、GoFの23個のデザインパターンを指すみたいなのです。

では、GoFとは、何かというと『the Gang of Four』の略で、オブジェクト指向の達人の4人のことをいいます。

で、その達人4人が経験から編み出したプログラムを組む時の定石に、名前を与え、カタログとして整理し、1冊の本にまとめた物が『Design Patterns: Elements of Reusable Object-Oriented Software』で、そには、23個のオブジェクト指向でのプログラミングの定石が記されていたのです。


この本は、1994年の出版されましたが、日本人には、英語とオブジェクト指向は、なかなか難しく、そして、7年後の2001年に、それを分かり易く噛み砕いた、結城さんの『Javaで学ぶデザインパターン』が出版され、やっと、私のような凡人にも理解ができるようになってきたわけです。


まずは、23個のデザインパターンの概要です。

  1. Iteratorパターン
    複数のオブジェクトに順番にアクセスする(1つ1つ数え上げる)
  2. Adapterパターン
    既存のクラスに別のインターフェースを持たせる(一皮かぶせて再利用)
  3. Template Methodパターン
    具体的な処理をサブクラスにまかせる
  4. Factory Methodパターン
    インスタンス作成をサブクラスにまかせる
  5. Singletonパターン
    あるクラスのオブジェクトを1個だけ作って共有する
  6. Prototypeパターン
    コピーしてインスタンスを作る
  7. Builderパターン
    複雑なインスタンスを組み立てる
  8. Abstract Factoryパターン
    関連する部品を組み合わせて製品を作る
  9. Bridgeパターン
    機能の階層と実装の階層を分ける
  10. Strategyパターン
    アルゴリズムをごっそり切り替える
  11. Compositeパターン
    容器と中身の同一視
  12. Decoratorパターン飾り枠と中身の同一視
  13. Visitorパターン
    構造を渡り歩きながら仕事をする
  14. Chain of Responsibilityパターン
    責任のたらい回し
  15. Facadeパターン
    シンプルな窓口
  16. Mediatorパターン
    相手は相談役1人だけ
  17. Observerパターン
    状態の変化を通知する
  18. Mementoパターン
    状態を保存する
  19. Stateパターン
    状態をクラスとして表現する
  20. Flyweightパターン
    同じものを共有して無駄をなくす
  21. Proxyパターン
    必要になってから作る
  22. Commandパターン
    命令をクラスにする
  23. Interpreterパターン
    文法規則をクラスで表現する

これからは、これらを、結城さんの著作権にはふれないように、自分の中で咀嚼し、解説していきたいと思います。

2004/03/14(日)多忙

普段の日は残業で22時過ぎに帰宅し、土曜日は某勉強会で、日曜日は某教会で会議三昧。

なかなか、ネットをやる時間が取れない。

しかし、勉強会のお蔭様で、日記のネタは、なんとかなっています(謎)。あぁ有り難い、有り難い。

そろそろ、Javaでのデザインパターンネタを開始したい、今日この頃です。

2004/03/12(金)委譲・関連・集約

JavaやUML等のオブジェクト指向の本やWEBページには、

委譲(デリゲーション)、関連(アソシエーション)、集約(アグレゲーション)

等のキーワードが結構沢山出てきます。 初心者の内は、それどころでなく、気になりませんが、そのうちに、どのように違うのか、 どのように同じなのか、などと気になり始めます。 そこで、出る杭は打たれるでなく、出る前に杭を打ってしまいましょう。

たとえは、ChichioyaクラスとChounanクラスがあったとします。 そして、Chichioyaオブジェクト内でChounanクラスのオブジェクトを保持しているとします。 コーディングをすると以下の感じです。

public class Chichioya {
    public static void main(String[] args) {
        Kodomo kodomo = null;
        if(args[0].equals("Chounan")) { // args[0]は1つめの引数
            kodomo = new Chounan();     // 長男オブジェクトを子供クラスに代入できる
        }
        kodomo.comingup(); // 子供(長男)オブジェクトのメソッドが起動できる
    }
}

/**
 * 長男を表すクラス
**/
public class Chounan implements Kodomo { // 長男も子供なので、継承してます
    public void comingup(){
        System.out.println("長男が嫌々タオルをもってくる。");
    }
}

機能面からみると、外見は、 Chichioyaオブジェクトが、"長男が嫌々タオルをもってくる。" を表示していますが、内部では、ChounanオブジェクトへChichioyaオブジェクトが委譲しているのです。

クラス関係からみると、ChichioyaクラスがChounanクラスを集約して『has-a』の関係になっていることがわかります。 そして、このような関係を集約といい、関連しているといいます。

つまり、見る視点が異なるだけで、実は、この3つ(委譲・集約・関連)は、結果的には、ほぼ同じ事をいっているのです。

もしかしたら、間違った事をいっているかもしれませんので、識者の方、フォローよろしくお願い致します。

2004/03/12(金)はじめての『ファイルI/O』on Java

普通の言語でのファイルアクセスは、ほぼ間違えなく、以下の手順です。

  1. ファイルを直接にオープン
  2. ファイルアクセス(リード・ライト)
  3. ファイルクローズ

しかし、オブジェクト指向のJavaだとちょっと雰囲気が異なります。 ファイルを直接にオープンするのではなく、ストリームというオブジェクトを生成すると自動的にオープンされるのです。 そして、ストリームオブジェクトのメソッドを使ってファイルのI/Oやクローズを行います。 また、他の言語と違って、I/Oエラー等の処理を例外として処理でき、本来のI/O処理に専念できます。

ストリームオブジェクトは、大きく分けて4種類あり、それぞれ、以下の通りです。

  1. バイト入力ストリーム
  2. バイト出力ストリーム
  3. キャラクタ入力ストリーム
  4. キャラクタ出力ストリーム

以下に、1と2を使用したプログラムを作成してみました。

プログラム仕様
> Fcp source-file-name destination-file-name

まぁ、UNIXでのcpコマンドのようなものです。

-------------------------------------------------------------------------------
import java.io.*;            // ファイルI/Oでは、必修

class Fcp {
   public static void main( String args[]) {
     FileInputStream f_in;   //ファイルから読み込むバイトストリームの宣言
     FileOutputStream f_out; //ファイルに書き出すバイトストリームの宣言
     int b;                  //読み込んだバイトを格納するエリアの宣言

     if(args.length != 2){   //引数チェック
        System.err.println("Fcp source-file-name destination-file-name");
        System.exit(1);     //プログラム終了
     }

     try{
        f_in = new FileInputStream(args[0]);  //読み込みのバイトストリームオブジェクト作成
        f_out = new FileOutputStream(args[1]);//書き出しのバイトストリームオブジェクト作成
        try{
           while((b=f_in.read()) != -1) {     //1バイト単位で入力
                f_out.write((byte)b);         //1バイト単位で出力
           }
        } catch (IOException e) {             //入出力例外
          System.err.println("IO error");
        } finally {
          f_in.close();                       //入力バイトストリームのクローズ
          f_out.close();                      //出力バイトストリームのクローズ
        }
     } catch (FileNotFoundException e) {      //ファイル不在例外
       System.err.println("Opening error : Input File not found");
     } catch (IOException e) {                //入出力例外
       System.err.println("Openning/Closeing error");
     }
   }
}

2004/03/11(木)はじめての『WINDOWSアプリケーション』 on JAVA

アプレットやサーブレットは、結構あるのですが、今回、はじめて、 WINDOWSでのメニュー付アプリケーションを作成してみました。 説明は、ソースのコメントを参照してください。

フレームは、ウインドウと読み替えた方が、わかりやすいかもです。 ソースは、カット&ペーストでそのまま動きます。しかし、コンパイルは必要です。

import java.awt.*;                       //awtとは、Abstract Window Toolkit の略です。
import java.awt.event.*;
                                         //フレームを継承しアクションリスナーを実装する
public class MyWin extends Frame implements ActionListener {

    public static void main(String args[]) {
        MyWin m = new MyWin();           //フレームオブジェクト作成(コンストラクタ起動)
        m.start();                       //フレーム(ウィンドウ)の作成スタート
    }
    public MyWin() {                     //コンストラクタ
        super("Hollo!!");                //タイトルバーのタイトル
        MenuBar mb = new MenuBar();      //メニューバーオブジェクト作成
        Menu fileMenu;                   //メニュークラス変数
        MenuItem quit;                   //プルダウンメニューの項目クラス変数
        fileMenu = new Menu("ファイル"); //メニュー名設定してメニューオブジェクト作成
        quit = new MenuItem("閉じる...");//項目設定してプルダウンメニューオブジェクト作成
        fileMenu.add(quit);              //項目設定をメニューオブジェクトへ登録
        mb.add(fileMenu);                //メニューオブジェクトをメニューバーオブジェクトへ登録
        setMenuBar(mb);                  //メニューバーオブジェクトをフレームオブジェクトへ登録
        quit.addActionListener(this);    //本オブジェクトをリスナー登録
        setLayout(new BorderLayout());   //フレームをボーダーレイアウトに設定
        Label message = new Label("Hello!! Geniuss");//ラベルオブジェクト作成
        add("North",message);            //ラベルオブジェクトをフレームオブジェクトへ登録

    }
    public void start() {
        setSize(100, 200);               //フレームのサイズを設定
        setVisible(true);                //フレームの表示
    }                                    //プルダウンメニューがクリックされると呼ばれる
    public void actionPerformed(ActionEvent evt) {
        if ("閉じる...".equals(evt.getActionCommand())) {
            System.exit(0);              //プログラム終了
        } 
    }
}
MyWinコンストラクタ処理の主な流れ
  1. メニュー項目オブジェクトをメニューオブジェクトに登録。
  2. メニューオブジェクトをメニューバーオブジェクトに登録。
  3. メニューバーオブジェクトをフレームオブジェクト(ウィンドウ)に登録。
リスナー登録とイベント処理の主な流れ

リスナー登録をすることにより、メニュー項目がクリックされたら、 actionPerformed()メソッドが呼ばれます。

そして、今回の場合、メニュー項目をイベントソースといいます。 イベントソースがクリックされイベントが発生すると、イベントオブジェクト(ActionEvent evt)が作成されます。

つぎに、イベントオブジェクトから、イベントリスナーへイベントが通知され、 イベントリスナーに予め自分(quit.addActionListener(this))を登録していたので、 イベントリスナーより、自分のイベント処理用メソッドactionPerformed()が起動されます。

上記は、少し難しく感じるかも知れませんが…、 昔、VC++でなく、単なるC言語で、はじめてウィンドウズアプリを 組んだときと比べて、数10倍、簡単になっている感じがします。

2004/03/10(水)Javaの簡単な『特長と歴史』

みなさま、ご無沙汰しております。ちょっと、仕事の方が多忙です。

さて、Javaの簡単な特長と歴史です。

特長

前に、Javaの特長は、『オブジェクト指向』と『Write Once, Run Anywhere』で意訳すると、 『どこのPCやPCもどきでもプログラムの変更なしに動作することが保証されたプログラム言語』 と、お話ししましたが、この2つ以外に、まだ以下の3つがあります。

例外処理機能
通常のプログラム言語では、異常時に割り込みが発生して、システムがエラーを出します。 しかし、Javaでは、それを横取りすることが可能(不可能なケースもある)です。 また、エラー時など意識的に割り込み(例外)を発生させて、メイン処理からエラー処理を追放することが出来、 メイン処理をスッキリさせることが可能です。
ガベージコレクション
通常のプログラム言語では、システム資源を確保して使用後は、開放しなくてはなりません。 しかし、Javaでは、自動的に開放してくれるのです。これをガベージコレクションといいます。 つまり、後処理を考えず(記述せず)にプログラムが出来、メイン処理をスッキリさせることが可能です。
マルチスレッド処理機能
通常のプログラム言語では、システムでマルチプロセスを実現しています。 しかし、Javaはシングルプロセスでマルチプロセスと同様なことが実現できます。 これをマルチスレッド処理といます。 つまり、シングルプロセスなので、システム資源を食わないマルチ処理が可能なのです。
歴史

Javaの歴史は、比較的新しく1990年代からですが、オブジェクト指向の歴史は、結構古く、 1960年代後半に、『Simula』というシミュレータのための言語が源流とされています。 1970〜80年代に、『Simula』に『Lisp』と『Logo』の要素を加え『Smalltalk』が誕生しました。 実は、『Smalltalk』で作ったOS(ダイナブック)をジョブスが真似してMacが出来、Macをゲイツが真似して、今のWINDOWSが出来たとされています。

そう、オブジェクト指向がなかったら、MSはなかった!?