メソッドの拡張

次は、メソッドの追加だ。クラスベースのオブジェクト指向言語で、メソッドを追加する構文を比較する。

継承を用いた、新しいクラスへのメソッドの追加

新しいクラス B を宣言して、メソッドを追加する場合。普通の継承だね。

C++

class B : public A {
public:
  void method1();
};

void B::method1() {}

Java

class B extends A {
  public void method1() {}
}

Objective-C

@interface B : A
{}
- (void)method1;
@end

@implementation B
- (void)method1 {}
@end

Smalltalk

A subclass: #B
  instanceVariableNames: ''
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Category-Name'!

!B methodsFor: 'message category'!
message1
    ^ self! !

Dylan

define class <b> (<a>)
end class <b>;

define method method-1( b :: <b> ) => ()
end method;

Ruby

class B < A
  def method1
  end
end

Perl

{ package B;
  our @ISA = qw/A/;
  sub new {
    my $class = shift @_;
    return bless({}, $class);
  }
  sub method1 {}
}

Self

globals _AddSlotsIfAbsent: (| b = () |).
b _Define: (| parent* = a. slot2 = (^self) |)

NewtonScript

prootB := {_proto: protoA, 
  method1: func() begin /* 処理 */ end};

AppleScript

AppleScriptのスクリプトオブジェクトは、parentプロパティにより親オブジェクトを指定する。
厳密に言うと、これは特定のインスタンスに対する動的な機能追加である。

on B()
  script B
    property parent : A()
    on method1()
    end method1
  end script
end B

継承を用いないメソッドの追加

継承を使わないで、既存のクラスにメソッドを追加するもの。フレームワークがある場合は、その内部のクラスも拡張できる。

C++

不可。

Java

不可。

Objective-C

カテゴリを使う。

@interface A (additionalMethod)
- (void)method2;
@end

@implementation A (additionalMethod)
- (void) method2 {}
@end

Smalltalk

!A methodsFor: 'message category'!
message2
  ^ self! !

Dylan

define method method-1( a :: <a> ) => ()
end method;

Ruby

class A
  def method2
  end
end

Perl

{ package A;
  sub method2 {}
}

Self

a _AddSlots: (| slot2 = (^self) |)

NewtonScript

protoA.method2:= func() begin /* 処理 */ end;

AppleScript

on handler3() 
end handler3 
set handler3 of a to handler3

実行時のメソッドの追加

実行時に、動的にクラスにメソッドを追加するものだ。

C++

不可。

Java

不可。

Objective-C

直接はできないけど、forwardInvocation: と methodSignatureForSelector: をオーバーライドすることで、実現できる。

Smalltalk

| code |
code := 'message3', 
  String cr, 
  String tab, 
  '^ self'.
A compile: code classified: 'message category' 
  notifying: nil

Dylan

Generic Function を作成する。局所変数に代入してみた。

let method-2 = make(
  <generic-function>, required: list(<a>));
local method m0 (a :: <a>)
  a.slot-0 := "Goodbye";
end;
add-method(method-2, m0);

Ruby

class A
  def method2
  end
end

または、

a.instance_eval("def_method\nend")

この場合、特異メソッドになる。

Perl

my $code = sub { print "Hellow.\n" };
*A::method3 = $code;

Self

a _AddSlots: (| slot3 = (^self) |)

NewtonScript

imp := func() begin /* 処理 */ end;
SetSlot(protoA, intern("method3"), imp); 

AppleScript

on handler3() 
end handler3 
set handler3 of a to handler3

クラスの置換

あるクラスで、現在あるクラスを置き換えるもの。この機能は、確かに実際のプログラミングでは必要ないかもしれない。やり方によっては、とても凶悪な動作をすることもある。でも、動きを理解しているならばとても便利なものだし、クラスの拡張の柔軟性を比較するにはいいものかもしれない。

C++

不可。

Java

不可。

Objective-C

poseAsClass: を使う。この場合、PseudoA は A のサブクラスでなくてはいけなくて、インスタンス変数を追加してはいけない。これ以降、A へのメッセージは PseudoA に送られる。

@interface PseudoA : A
@end

@implementation PseudoA
+ (void)load {
    [PseudoA poseAsClass:[A class]];
}
- (void)method0 {}
@end 

Smalltalk

become: を使う。この場合、PseudoA は A のサブクラスであってはいけない。

Object subclass: #PseudoA
  instanceVariableNames: ''
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Category-Name'!

!PseudoA methodsFor: 'message category'!
message0
  ^ self! !

!PseudoA class methodsFor: 'class initialization'!
  initialize
  self become: A! !

PseudoA initialize!

Dylan

不可。

Ruby

不可。

Perl

PseudoA は普通に定義しておき、その後に package を丸ごと入れ替える。

{ package PseudoA;
  sub new {
    my $class = shift @_;
    return bless({}, $class);
  }
  sub method0 {}
}
*A:: = \*PseudoA::;

ただし、上記の入れ替え処理の実行前に生成された、既存のインスタンスには無効。 もし、既存のインスタンスが判るのであれば、個別に以下のようにすることは可能。

bless( $a, q/PseudoA/ );

Self

クラスはないので、オブジェクトを置換する。

globals _AddSlotsIfAbsent: (| pseudoA = () |).
pseudoA _Define: (| slot0 = (^self) |).
a _Define: pseudoA

NewtonScript

オブジェクト(プロト)を置換する。

ReplaceObject(protoA, protoB);

AppleScript

不可。


[Home] [Download] [Archives] [BBS] [Cocoa Programming Tips 1001] [Core Foundation の秘密] [Safari Developer News] [はじめてのブラウザのつくり方] [Sketch BP] [スクリーンセイバーを作ろう] [Objective-C 最適化] [Authorization API 完全理解] [Mac OS X Programming Books Review] [オブジェクト指向の言語比較論]

mailto: mkino@xd5.so-net.ne.jp