SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Javaジェネリックを使ったコンパイル時の動的処理

ジェネリックを利用した型安全性の実現

  • このエントリーをはてなブックマークに追加

ダウンロード サンプルソース (6.9 KB)

本稿では、ジェネリックを利用してコンパイル時の動的処理およびクライアント関連の型安全性(type-safety)を実現する方法について解説します。

  • このエントリーをはてなブックマークに追加

はじめに

 本稿では、ジェネリックを利用してコンパイル時の動的処理およびクライアント関連の型安全性(type-safety)を実現する方法について解説します。一般的に、サブクラス化を行う際の最も重要な側面は、クラス固有の機能を実現するために、いかにして同じメソッドパラメータを使ってオーバーライドを実現するかということです。場合によっては、クラス固有のパラメータが必要になることもあるかもしれません。さらに、オーバーライドメソッドが、こうしたクラス固有パラメータのスーパークラスであるパラメータを使用する場合も考えられます。このようなメソッドの例としては、パブリックAPIを通じて公開され、具象実装クラス内でオーバーライドされるメソッドが挙げられます。

シナリオ

 本稿で取り上げるのは非常によくあるシナリオで、多くの人が過去に直面したことがあり、同じような方法で解決してきたのではないかと思います。ここでは、単純なレンタカーシステムの例を使ってジェネリックの利用方法を説明します。

図1 オブジェクトのリレーション図
図1 オブジェクトのリレーション図

 今回の例では、メインのレンタルサービスクラスをRentVehicleManagerとしますが、このクラスはインターフェイスにしても抽象クラスにしてもかまいません。RentCarManagerとRentBikeManagerはRentVehicleManagerのサブクラスで、RentVehicleManagerのメソッドをそれぞれの機能に合わせてオーバーライドします。このシナリオの実用的な実装ソリューションとしては、次のようなものが考えられます。

  1. 一連のManagerクラスの作成にFactoryパターンを使用する
  2. パラメータの共通階層を作り、メソッド内で厳密なチェックを行う
  3. ジェネリックを利用した共通階層を使用する

 方法1は、関連クラスのインスタンス生成という点では優れたソリューションですが、オブジェクトパラメータの一般化は実現できません。

 方法2のソリューションは、たとえば図2のようになります。この場合、個々のオーバーライドメソッドは、そのクラスにふさわしい型の値が引数に渡されているかどうかをメソッドの冒頭で厳密にチェックしなければなりません。

図2 クラス図(方法2の場合)
図2 クラス図(方法2の場合)

 この場合のインターフェイスは、たとえば次のようになります。

package com.sumithp.codeguru.nongeneric.vehicle;

import com.sumithp.codeguru.vehicle.domain.Vehicle;

public interface RentVehicleMgr {

   public void rentOut(Vehicle vehicle);
   public void checkIn(Vehicle vehicle);
   public void diagnose(Vehicle vehicle);
   public void repair(Vehicle vehicle);
}

 方法2の場合、バイクレンタルに関する実装はたとえば次のようになります。

package com.sumithp.codeguru.nongeneric.vehicle;

import com.sumithp.codeguru.vehicle.domain.Vehicle;

public class RentBikeMgrImpl implements RentVehicleMgr {

   // If we don't use Vehicle as the parameter here, the clients
   // will not be able to use a generalized interface to call our
   // methods.

   public void rentOut(Vehicle vehicle) {
      // if (vehicle instanceof bike)
         // Renting Out Related DB Operations
   }

   public void checkIn(Vehicle vehicle) {
      // if (vehicle instanceof bike)
         // Vehicle Check In Related DB Operations
   }

   public void diagnose(Vehicle vehicle) {
      // if (vehicle instanceof bike)
         // Self Diagnose functionality of a vehicle
         // Print diagnosis
   }

   public void repair(Vehicle vehicle) {
      // if (vehicle instanceof bike)
         // Perform pre-defined repair
         // Print repair details
   }
}

 方法2の場合、コンパイル時のクライアント側の使い方は次のようになるでしょう。

package com.sumithp.codeguru.nongeneric.vehicle.client;

import com.sumithp.codeguru.nongeneric.vehicle.RentBikeMgrImpl;
import com.sumithp.codeguru.nongeneric.vehicle.RentCarMgrImpl;
import com.sumithp.codeguru.nongeneric.vehicle.RentVehicleMgr;
import com.sumithp.codeguru.vehicle.domain.Bike;
import com.sumithp.codeguru.vehicle.domain.Car;
import com.sumithp.codeguru.vehicle.domain.Vehicle;

public class RentNonGenericVehicleClient {

   public void rentBike() {

      // You want only one interface to handle all rentals
      RentVehicleMgr rentVehicleMgr;

      rentVehicleMgr = new RentBikeMgrImpl();

      Vehicle vehicle = new Bike(104,"TWO",true,150);
      rentVehicleMgr.rentOut(vehicle);

      /*
       * Client can as well do this
       *
       * Vehicle vehicle = new Car(104,"FOUR",true,"PETROL");
       * rentVehicleMgr.rentOut(vehicle);
       *
       * If there are no instanceof checks, this bombs!
       *
       */
   }

   public void rentCar() {

      // You want only one interface to handle all rentals
      RentVehicleMgr rentVehicleMgr;

      rentVehicleMgr = new RentCarMgrImpl();

      Vehicle vehicle = new Car(104,"FOUR",true,"PETROL");
      rentVehicleMgr.rentOut(vehicle);

      /*
       * Client can do the same as shown for rentBike()
       *
       * Vehicle vehicle = new Bike(104,"TWO",true,150);
       * rentVehicleMgr.rentOut(vehicle);
       *
       * If there are no instanceof checks, this bombs too!
       *
       */
   }

}

 方法3は、最も完成度が高く、有効なソリューションです。必要なメソッド群は1つのクラスで公開され、各メソッドはジェネリック変数を通じてそれぞれの実装を提供するため、一貫性に優れています。それでは、このソリューションについて詳しく見ていきましょう。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
Javaジェネリックを使った共通階層

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Sumith Puri(Sumith Puri)

4年以上にわたりJava/J2EEテクノロジを使ったアプリケーションの設計/開発に携わる。現在はSymantec India(インド、プネー)の開発者として勤務。SRSIT(インド、バンガロール)にて情報工学の学士号を取得。Sun Certified Java Programmerの資格を持つ。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2242 2008/03/13 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング