HOME Sather を試そう download 書き込む

7. 抽象クラス


1.はじめに

抽象クラスは Java のインターフェースに相当するもので、 メソッドを宣言したものです。

実装抜きで宣言することによって、実装に依存しないクラス間の関係を構築でき、 コードの再利用を促進します。

The Online Sather Code Browser をみるとわかるように、 Sather では、継承の多くは抽象クラスを用いて行われており、通常のクラスの継承は底のほうで少しあるだけです。

抽象クラスは、次の章で説明するパラメター付クラス (Parametrized Class) と組み合わせることにより、柔軟なデータ型を構築することができます。

2. 例:暗号化通信

早速、例を挙げて説明します。 暗号化には AES, DES, RC4 などのさまざまなアルゴリズムがあり、抽象クラスを作ってまとめるのに 適した題材だと思いました。 [code 1] に簡単な暗号化通信の例を示します。

[code 1]
01:     -- an example of abstract class; $CRYPT and $MESSAGE
02:     
03:     
04:     -- algorithm for cryptogram
05:     abstract class $CRYPT is      -- 暗号化アルゴリズムの抽象クラス。抽象クラスは $ に続けて全て大文字で書く。
06:        encrypt(s:STR):STR;        -- 暗号化と
07:        decrypt(s:STR):STR;        -- 復号化の2つのメソッドを持つ。
08:     end; -- end $CRYPT
09:     
10:     -- sipher message
11:     abstract class $MESSAGE is    -- メッセージ用抽象クラス
12:        send(s:STR):STR;
13:        receive(s:STR):STR;
14:     end; -- end $MESSAGE
15:     
16:     -- Plain text
17:     class PLAIN < $CRYPT is      -- 何もしない暗号化アルゴリズム
18:        create:SAME is
19:           return new;
20:        end;
21:     
22:        encrypt(s:STR):STR is
23:           return s;
24:        end;
25:     
26:        decrypt(s:STR):STR is
27:           return s;
28:        end;
29:     end; -- end PLAIN
30:     
31:     -- Simple XOR cryptogram
32:     class XOR < $CRYPT is           -- キーとの排他的論理和をとる暗号化アルゴリズム
33:     
34:        private attr keylist:ARRAY{INT};
35:     
36:        create(key:STR):SAME is
37:           return new.init(key);
38:        end;
39:     
40:        private init(key:STR):SAME is
41:           keylist:=#(key.size);
42:           loop
43:     	 keylist.set!(key.elt!.int);   -- キーを整数の配列として保持
44:           end;
45:           return self;
46:        end;
47:     
48:        private key_rotate!:INT is         -- 呼ばれるたびに keylist の次の要素を返す。最後まで行ったら最初に戻る。
49:           i:INT:=0;
50:           n:INT:=keylist.size-1;
51:           loop
52:     	 yield keylist[i];
53:     	 if i=n then
54:     	    i:=0;
55:     	 else
56:     	    i:=i+1;
57:     	 end;
58:           end;
59:        end;
60:     
61:        encrypt(s:STR):STR is
62:           fs:FSTR:=#(s.size);  -- FSTR は変更可能な文字列
63:           loop
64:     	 fs := fs + s.elt!.int.bxor(key_rotate!).char;    -- fs の最後にメッセージとキーの XOR で作った一文字を追加していく。
65:           end;
66:           return fs.str;
67:        end;
68:     
69:        decrypt(s:STR):STR is           -- 排他的論理和による暗号化では、復号化は暗号化と同じ。
70:           return encrypt(s);
71:        end;
72:     end; -- end of XOR
73:           
74:     partial class MESSAGE < $MESSAGE is    -- メッセージに共通する要素を部分クラスとして書き出す。
75:        stub cry:$CRYPT;                    -- 暗号化アルゴリズム。下部クラスで再定義される。
76:     
77:        send(s:STR):STR is
78:           return cry.encrypt(s);
79:        end;
80:     
81:        receive(s:STR):STR is
82:           return cry.decrypt(s);
83:        end;
84:     end; -- end MESSAGE
85:     
86:     -- Plain Message
87:     class USUAL < $MESSAGE is
88:        include MESSAGE;
89:        private const cry:PLAIN:=PLAIN::create;  -- cannot use #PLAIN here.
90:     
91:        create:SAME is
92:           return new;
93:        end;
94:     end; -- end USUAL
95:     
96:     -- Sipher Message 
97:     class IMPORTANT < $MESSAGE is
98:        include MESSAGE;
99:        private attr cry:XOR;
100:     
101:        create(key:STR):SAME is
102:           return new.init(key);
103:        end;
104:     
105:        private init(key:STR):SAME is
106:           cry:=#(key);
107:           return self;
108:        end;
109:     end; -- end IMPORTANT
110:     
111:     class MAIN is
112:     
113:        private const key:STR:= "qwertyuiop@asdfghjkl;zxcvbnm,"; -- key for XOR
114:     
115:        main(av: ARRAY{STR}) is
116:           if av.size=2 then
117:     	 plain:USUAL:= #;
118:     	 sixor:IMPORTANT:=#(key); 
119:     	 msg:STR:=av[1];                                    -- 最初の引数を暗号化する。
120:     	 plain_send:STR:=plain.send(msg); 
121:     	 plain_receive:STR:=plain.receive(plain_send);
122:     	 xor_send:STR:=sixor.send(msg);
123:     	 xor_receive:STR:=sixor.receive(xor_send);
124:     	 #OUT + "Sipher Test using \"" + msg + "\"\n\n";
125:     	 #OUT + "Plain send: " + plain_send + "\n";
126:     	 #OUT + "Planin receive: " + plain_receive + "\n\n";
127:     	 #OUT + "XOR send: " + xor_send + "\n";
128:     	 #OUT + "XOR receive: " + xor_receive + "\n\n";
129:           else
130:     	 #ERR + "Usage: crypt \'STRING\'\n";
131:           end;
132:        end;
133:     end; -- end of MAIN
コンパイルして実行すると以下のようになります。
$ sacomp crypt.sa -o crypt
$ ./crypt 'Welcome to Satehr World.'
Sipher Test using "Welcome to Satehr World."

Plain send: Welcome to Satehr World.
Planin receive: Welcome to Satehr World.

XOR send: (表示できない文字列)
XOR receive: Welcome to Satehr World.

暗号化アルゴリズムは抽象クラスになっているので、もっと強度の強い暗号を用いたいときにはコードのほかの部分を ほとんど変えることなく暗号化アルゴリズムを変更することができます。
具体的には、IMPORTANT に AES を使いたくなったら、99 行目を次のように変えるだけです。
99:        private attr cry:AES;

3. 備え付けの抽象クラス

Sather に備え付けの抽象クラスのうち主なものを下の表にまとめます。 詳しくは
The Online Sather Code Browser をみてください。詳しい説明とクラスの関係を示す図が載っています。
クラス名 インターフェース 説明
$OB 全てのクラスは $OB のサブクラスです。
$IS_EQ is_eq(e:$OB):BOOL; self と e が等しければ true を返します。
$IS_LT is_lt(e:T):BOOL; self が e より小さければ true を返します。 $IS_EQ のサブクラスです。
$IS_NIL is_nil:BOOL; self が nil なら true を返します。
$NIL nil:SAME; self を nil にします。
$STR str:STR self を文字列に変換します。ほとんど全てのクラスは $STR のサブクラスです。
$NEF{NTP} abs, plus, minus, tiems, div, ... 代数のクラスです。サブクラスに $NUMBER{NTP}, $CPX_NUMBER{ETP} があります。
$ELT elt!:$OB イテレーター elt! を定義するクラスです。$ELT{T} の親クラスです。
$ELT{T} elt!:T 実質的にイテレーター elt! を定義しています。
$CONTAINER{ETP} copy, has, size 入れものクラスです。パラメター付クラスのほとんどがこのクラスのサブクラスです。
$HASH hash ハッシュ値を計算するクラスです。ハッシュ表のキーになることができるクラスは $HASH のサブクラスです。

4. 終わりに

この章では簡単な暗号化プログラムを例にとって抽象クラスについて説明しました。 付録にコードをつけておきますので気が向いたら遊んでください。

抽象クラスについての詳しい情報は Sather 1.1 : Language Essentials をみてください。 また、 The Online Sather Code Browser を眺めると感じをつかむことができます。

次回はパラメター付クラス (Parametrized Class) について説明します。


HOME Sather を試そう download 書き込む