Murayama blog.

AIの民主化。

AndroidでParse入門 - Subclasses -

元ネタ

こちらを参考にSubclassesについてまとめます。
https://parse.com/docs/android_guide#subclasses

前回の記事はこちら。
AndroidでParse入門 - Queries - - Murayama blog.

Subclasses

Parseは、なるべく速く動かせるように設計されています。ParseObjectとget()メソッドを使えば、すべてのデータにアクセスすることができます。一方、熟練したコードベースにおいては、サブクラス化を行うことで、簡潔さ、拡張性、オートコンプリートといったアドバンテージが生まれます。サブクラス化を行うことは任意ですが、コードは次のように置き換わるでしょう。

ParseObjectを使う場合

ParseObject shield = new ParseObject("Armor");
shield.put("displayName", "Wooden Shield");
shield.put("fireproof", false);
shield.put("rupees", 50);

サブクラス化した場合

Armor shield = new Armor();
shield.setDisplayName("Wooden Shield");
shield.setFireproof(false);
shield.setRupees(50);

Subclassing ParseObject

ParseObjectを継承したサブクラスを作成するには

  1. ParseObjectを継承したサブクラスを宣言します。
  2. @ParseClassNameアノテーションを付与します。アノテーションで指定された文字列は、ParseObjectのコンストラクタに渡されます。以降の機能でクラス名を指定する必要がなくなります。
  3. publicな引数なしのコンストラクタを定義します。コンストラクタ内でParseObjectのフィールドをカスタマイズしてはいけません。
  4. Applicationクラス内で、Parse.initialize()を呼び出す前にParseObject.registerSubclass(YourClass.class)を呼び出します。

ParseObjectを継承したArmorクラスを登録する例を以下に示します。

// Armor.java
import com.parse.ParseObject;
import com.parse.ParseClassName;
 
@ParseClassName("Armor")
public class Armor extends ParseObject {
}
 
// App.java
import com.parse.Parse;
import android.app.Application;
 
public class App extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
 
    ParseObject.registerSubclass(Armor.class);
    Parse.initialize(this, PARSE_APPLICATION_ID, PARSE_CLIENT_KEY);
  }
}

Accessors, Mutators, and Methods

ParseObjectのサブクラスには、ロジックをカプセル化するためのメソッドを追加します。ビジネスロジック、ストレージ/トランスミッションロジックといったような層の分離ではなく、対象についてのロジックを一カ所で管理することができます。

ParseObjcetのフィールドに対して、アクセサやミューテータを追加します。これは通常どおり、getterやsetterを定義するのですが、その内部ではget()、put()を使った実装になります。次のコードは、ArmorクラスにdisplayNameを定義したものです。

// Armor.java
@ParseClassName("Armor")
public class Armor extends ParseObject {
  public String getDisplayName() {
    return getString("displayName");
  }
  public void setDisplayName(String value) {
    put("displayName", value);
  }
}


displayNameを取得したい場合はarmor.getDisplayName()を使います。displayNameを設定したい場合は、armor.setDisplayName("Wooden Sword")を使います。また、IDEによってオートコンプリートも可能となるでしょう。タイポもコンパイル時に気づくようになります。

アクセサやミューテータは型に合わせて、getInt(), getParseFile()、getMap()を使用するようにしてください。

アクセサやミューテータだけでなく、より複雑なロジックを実装する必要がある場合は独自のメソッドを定義すると良いでしょう。

public void takeDamage(int amount) {
  // Decrease the armor's durability and determine whether it has broken
  increment("durability", -amount);
  if (getDurability() < 0) {
    setBroken(true);
  }
}

Initializing Subclasses

定義したサブクラスからオブジェクトを生成するには、コンストラクタを使用します。publicなデフォルトコンストラクタを定義する必要があり、コンストラクタの中では、ParseObjectのフィールドをカスタマイズしてはいけません。ParseSDKによって、サブクラスのインスタンスを作る際に型制約に従う必要があります。


既存のオブジェクトの参照を作るには、ParseObject.createWithoutData()を使います。

Armor armorReference = ParseObject.createWithoutData(Armor.class, armor.getObjectId());

Queries

ParseObject.getQuery()を使えば、特定のサブクラスのオブジェクトを検索するクエリを取得できます。次のコードは、ユーザが購入可能なarmorsを検索するものです。

ParseQuery<Armor> query = ParseObject.getQuery(Armor.class);
query.whereLessThanOrEqualTo("rupees", ParseUser.getCurrentUser().get("rupees"));
query.findInBackground(new FindCallback<Armor>() {
  @Override
  public void done(List<Armor> results, ParseException e) {
    for (Armor a : results) {
      // ...
    }
  }
});