SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

japan.internet.com翻訳記事

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

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

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

Javaジェネリックを使った共通階層

 ジェネリックの大きな長所は、その「型消去(Type Erasure)」という性質です。これはつまり、コンパイル時チェックのみが行われ、その後はジェネリック変数が消去され、実行時の検証は行われないということを意味します。一方、これには短所もあり、サードパーティ製のコードと併用するときに安全性が保証されないなどの問題があります(内部コードでも、ジェネリックを使用しないコードであれば同様の問題が起こります)。

 このソリューションを実現するには、方法2に簡単な変更を加え、階層内の各クラスに新しいジェネリック変数を追加します。トップレベルでは、RentVehicleManagerの宣言を、Vehicleを拡張(extends)する型のジェネリック変数を使用するように書き換えます。次に例を示します。

package com.sumithp.codeguru.generic.vehicle;

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

public interface RentVehicleMgr< T extends Vehicle > {

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

 さらに、RentVehicleManagerを継承するクラス(つまりRentBikeManagerとRentCarManager)の宣言を、それぞれにふさわしい型のジェネリック変数を使用するように書き換えます。たとえばカーレンタルに関する実装は次のようになります。

package com.sumithp.codeguru.generic.vehicle;

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

public class RentCarMgrImpl implements RentVehicleMgr< Car > {

   // Can use Car as parameter here, as well as allow
   // clients to have a generalized interface

   public void rentOut(Car car) {
      // Renting Out Related DB Operations
   }

   public void checkIn(Car car) {
      // Vehicle Check In Related DB Operations
   }

   public void diagnose(Car car) {
      // Self Diagnose functionality of a vehicle
      // Print diagnosis
   }

   public void repair(Car car) {
      // Perform pre-defined repair
      // Print repair details
   }
}

 これはつまり、クライアント側から特定の種類のManagerクラスのメソッドを呼び出すときは、目的クラスに対応する型のオブジェクトを渡さなければならないということです。これにより、Manager実装クラスはメソッド内で厳密なチェックを行わずに済むようになります。また、こうしたサブクラスのメソッドを修正するときに、instanceofチェックを含める必要はなくなります。

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

 これでクライアントコードは一層すっきりし、安全になります。一般的な実装は次のようになります。

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

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

public class RentGenericVehicleClient {

   public void rentBike() {

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

      rentVehicleMgr = new RentBikeMgrImpl();

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

      /*
       * Client cannot do this:
       *
       * Vehicle vehicle = new Car(104,"FOUR",true,"PETROL");
       * rentVehicleMgr.rentOut(vehicle);
       *
       * Even if there are no instanceof checks, all is well!
       * Client is absolutely clear on what he needs to do.
       *
       */
   }

   public void rentCar() {

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

      rentVehicleMgr = new RentCarMgrImpl();

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

      /*
       * Client cannot do the following as shown for rentBike():
       *
       * Vehicle vehicle = new Bike(104,"TWO",true,150);
       * rentVehicleMgr.rentOut(vehicle);
       *
       * Even if there are no instanceof checks, all is well!
       * Client is absolutely clear on what he needs to do.
       *
       */
   }
}

 このような設計にすると、保守やコーディングがしやすくなるだけでなく、実装についての理解もしやすくなります。この設計方法は、サービスや機能の実装側クラスだけでなく、サービスのコンシューマ側クラスにとってもメリットがあります。

まとめ

 本稿で紹介したジェネリックの使い方は動的継承に役立ちますが、これはコンパイル時の動的処理を実現するだけです。前にも述べたとおり、実行時にはジェネリック変数はクラスから削除されます。

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー