SHOEISHA iD

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

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

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

今からでも遅くない これから始めるScala

今からでも遅くない これから始めるScala(後編)

進化したオブジェクト指向


コンパニオンとstatic

 コンパニオンとは、同一スコープ(同じソースファイル内や同じブロック内)で定義されているクラスとオブジェクトの関係を表す言葉です。以下のリスト7の例では、Bookmarkクラスはコンパニオンクラス、Bookmarkオブジェクトはコンパニオンオブジェクトと呼ばれます。

リスト7 コンパニオン関係のクラスとオブジェクト
// Bookmarkコンパニオンクラス
// コンストラクタはprivateに変更
class Bookmark private ( val title:String, val url:URL, val date:Date )

// Bookmarkコンパニオンオブジェクト
object Bookmark {
  // Bookmarkクラスを生成する
  def apply( title:String, url:URL, date:Date ):Bookmark =
    new Bookmark( title, url , date )

  // 文字列のurlからBookmarkクラスを生成する
  def apply( title:String, url:String, date:Date ):Bookmark =
    new Bookmark( title, new URL( url ), date )

  // dateを省略し、文字列のurlからBookmarkクラスを生成する
  def apply( title:String, url:String ):Bookmark =
    new Bookmark( title,new URL( url ),new Date )
}

 上記のBookmarkクラスは、リスト4で定義したものを修正したバージョンです。基本コンストラクタにprivateキーワードが付与されているため、通常の手段ではこのBookmarkクラスをインスタンス化できません。

 そこで、コンパニオン関係にあるBookmarkオブジェクトを利用します。コンパニオン関係にあるクラスとオブジェクトの間では、privateなメンバーへの特権的なアクセスが可能になります。これを利用して、BookmarkオブジェクトのapplyメソッドでBookmarkクラスのprivateな基本コンストラクタを呼び出してBookmarkクラスをインスタンス化しているのです。

 Bookmarkオブジェクトには、リスト4の時点で補助コンストラクタとして定義されていたものもapplyメソッドをオーバーライドすることで実装しています。このようにすると、BookmarkクラスはBookmarkオブジェクトが持つファクトリーメソッド経由でのみインスタンスを生成することが可能となり、インスタンス生成をより細やかに制御することが可能です(例えば、キャッシュを行ったり事前条件のチェックをしたり)。

 さて、applyというメソッド名ですが、これはScalaでは特別扱いされるメソッド名で、オブジェクトに対してあたかも関数呼び出しのようにしてメソッドを呼び出すことを可能とします。

 Bookmark("hoge", "http://example.com")のように呼び出すと、applyメソッドが呼ばれます。これを利用して、シンタックスシュガーのようにBookmarkクラスをインスタンス化させているわけです。

 では、REPLで動作確認をしてみましょう。REPLでは、入力行ごとにスコープが分割されるので、リスト7のコードをそのままREPLに入力してもエラーになってしまいます。コンパニオンをREPLで動作させるためには、以下のリスト8のように適当なobjectのインナークラス/オブジェクトとして定義することでREPL上でコンパニオン関係を作ることができます。

リスト8 REPL上でのコンパニオン関係の確認方法
scala> object m {
     | class Bookmark private ( val title:String, val url:URL, val date:Date )
     |
     | // Bookmarkコンパニオンオブジェクト
     | object Bookmark {
     |   // Bookmarkクラスを生成する
     |   def apply( title:String, url:URL, date:Date ):Bookmark =
     |     new Bookmark( title, url , new Date )

     ... 中略

     | }
defined module m

scala> val bookmark1 = m.Bookmark( "今から始めるScala 前編" ,"http://codezine.jp/article/detail/5193/")
bookmark1: m.Bookmark = m$Bookmark@5e681e45

scala> bookmark1.title
res3: String = 今から始めるScala 前編

scala> bookmark1.date
res4: java.util.Date = Fri Jun 18 15:38:58 JST 2010

 コンパニオンオブジェクトは特権的なアクセス権を持つので、staticメソッドのようなインスタンスに束縛されない処理を定義するのに最適です。逆に、Scalaではstaticなメンバーをクラスに定義できません。

 また、applyでコンパニオン関係のクラスのファクトリーメソッドを提供するような設計を、Scalaではよく行います。

次のページ
トレイトによるMix-in

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

今からでも遅くない これから始めるScala連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

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

WINGSプロジェクト 尾崎 智仁(オザキ トモヒト)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5329 2010/08/08 00:57

イベント

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

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

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

メールバックナンバー