• 検索結果がありません。

レコードとオブジェクト

N/A
N/A
Protected

Academic year: 2021

シェア "レコードとオブジェクト"

Copied!
46
0
0

読み込み中.... (全文を見る)

全文

(1)
(2)

レコード

class Point attr_accessor("x", "y") end … point.rb インスタンス変数の宣言

(3)

irb(main):004:0> load("point .rb") => true irb(main):005:0> p = Point.new() => #<Point:0x40332080> irb(main):006:0> p.x = 3 => 3 irb(main):007:0> p.y = 4 => 4 irb(main):008:0> p => #<Point:0 x40332080 @y=4, @x=3> オブジェクト (Pointクラスの インスタンス) インスタンス変数への代入 インスタンス変数への代入

(4)

irb(main):013:0> p.y => 4 irb(main):014:0> sqrt(p.x**2 + p.y**2) => 5.0

• Rubyでは,レコードもオブジェクトの一種

• レコードのクラスは,インスタンス変数の宣言

のみから成る

インスタンス変数の参照

(5)

… def point_make(u,v) p = Point.new() p.x = u p.y = v p end … オブジェクト(への参照)を返す point.rb

(6)

… def point_scale(p,s) point_make(p.x*s, p.y*s) end def point_add(p,q) point_make(p.x+q.x, p.y+q.y) end … point.rb

(7)

def point_interpolate(p,q,t)

point_add(point_scale(p,1-t), point_scale(q,t)) end

def point_draw(p,a)

if 0 <= p.y+0.5 && p.y+0.5 < a.length() && 0 <= p.x+0.5 && p.x+0.5 < a[0].length() a[p.y+0.5][p.x+0.5]=1 end end point.rb 配列aの縦の長さ 配列aの横の長さ Rubyの配列の添え字が実数でも いいことを利用している 0.5は四捨五入をするため

(8)

load("./max.rb") load("./abs.rb")

def line_draw(p0,p1,a)

n=max(abs(p1.x - p0.x), abs(p1.y - p0.y)) for i in 0..n

point_draw(point_interpolate(p0,p1,i*1.0/n), a) end

end

(9)

def bezier_draw(p0,c,p1,a) n = 10 prev = p0 for i in 1..n t = i*1.0/n q0 = point_interpolate(p0, c, t) q1 = point_interpolate(c, p1, t) r = point_interpolate(q0, q1, t) line_draw(prev, r, a) prev = r end end bezier.rb

(10)

練習

• point.rb, line.rb, bezier.rb をダウンロード。

• max.rb を作るかダウンロード。

• abs.rb を作る。

• isrb を起動。

• point.rb をロード。

• bezier.rb をロード。

– line.rb もロードされる。 – max.rb と abs.rb もロードされる。

• make2d を定義(既に作ったはず)。

(11)

練習

• 以下を順に isrb のもとで実行せよ。

p0 = point_make(10,10)

p1 = point_make(90,90)

c = point_make(10,90)

a = make2d(100,100)

bezier_draw(p0,c,p1,a)

show(a)

(12)

進捗の確認

1. 前スライドが動いた。

2. 前スライドが動かない。

3. make2d を忘れた。

4. ロードができない。

5. abs.rb が作れない。

6. max.rb が作れない。

7. ダウンロードができない。

0 5 10 15 20 25 30 35 40 45 50 1 2 3 4 5 6 7 系列1 2009.12.18

(13)

もっと,レコード

class Line attr_accessor("p0", "p1") end class Bezier attr_accessor("p0", "c", "p1") end

(14)

レコードの意義

• 一まとまりの複数のデータを表す変数が1個ですむ – Pointの場合,x座標とy座標をまとめて扱える – Lineの場合,始点と終点をまとめて扱える • 4つの座標をまとめて扱えている – Bezierの場合,始点と終点,第3点をまとめて扱える • 6つの座標をまとめて扱えている • このようなデータのまとまりを値として扱える – 関数の値として返すことができる • 4つの座標を返すことは通常の関数では難しい – 内部のデータがどうなっているかを知らなくても使うことが できる • もし,Pointの座標系が極座標系だったとしても,関数の使い方に変 更を加える必要がない

(15)

しかし,レコードのままだと…

• クラス(レコードの種類)ごとに操作を定義

Pointクラス Lineクラス Bezierクラス point_draw line_draw bezier_draw

• これらが混在している場合,

if figureがPointクラスのオブジェクト point_draw(figure,a) else if figureがLineクラスのオブジェクト line_draw(figure,a) else if figureがBezierクラスのオブジェクト bezier_draw(figure,a)

(16)

オブジェクト指向では

• オブジェクト(ここではレコードのこと)に自分

に対する操作の仕方を覚えさせる

– Point のレコードに,スカラー倍,ベクトル和など の操作を覚えさせる – 自分の操作法を知っているレコードをオブジェクト と呼ぶ – それぞれの Point オブジェクトが操作法を抱え込 むのは大変なので,Point オブジェクトを,Point クラスにまとめ,「親分」のPoint クラスがPoint オ ブジェクトの作り方や操作法を一括管理する

(17)

レコードからオブジェクトへ

オブジェクト 内部データ構造 + 処理手続き レコードの変数 にアクセスするのと 同じ形での質問や 動作の依頼 それに対する応答 隠蔽されている(カプセル化) 実は,オブジェクトのクラスがこれ らを知っている 個々のオブジェクトは自分の具体 的な値を知っている メッセージとも言う

(18)

クラス

class Point attr_accessor("x", "y") def initialize(u,v) self.x = u self.y = v end def scale(s) Point.new(self.x * s, self.y * s) end def add(q)

Point.new(self.x + q.x, self.y + q.y) end end scaleメソッド 初期化メソッド 自分自身の x @x でもよい oo-point.rb 自分の操作法を メソッドと呼ぶ

(19)

irb(main):005:0> p = Point .new(3,4) => #<Point:0x7ffa3ed8 @x=3, @y=4> irb(main):006:0> p.x => 3 irb(main):007:0> q = p.scale(2) => #<Point:0x7ffa3e84 @x=6, @y=8> irb(main):008:0> p.add(q) => #<Point:0x7ff9b0f8 @x=9, @y=12> irb(main):009:0> p.add(q).scale(0.5) => #<Point:0x7ff94ca8 @x=4.5, @y=6.0> 初期化メソッドの引数 新しいオブジェクト 新しいオブジェクト 新しい オブジェクト

(20)

Pointクラスに以下のメソッドを追加。 def move(x,y) self.x = x self.y = y end irb(main):002:0> p = Point.new(3,4) => #<Point:0x7ffa32bc @y=4, @x=3> irb(main):003:0> p.move(4,6) => 6 irb(main):004:0> p => #<Point:0x7ffa32bc @y=6, @x=4> 以下のようにmoveメソッドだけ 後から定義することも可能 class Point def move(x,y) self.x = x self.y = y end end

(21)

class Line attr_accessor("p0", "p1") def initialize(q,r) self.p0 = q self.p1 = r end def draw(a) n = max(abs(self.p1.x - self.p0.x), abs(self.p1.y - self.p0.y)) for i in 0..n p = self.p0.interpolate(self.p1, i*1.0/n) p.draw(a) end end … oo-line.rb

(22)

多相性

def drawall(elements,a)

for i in 0..elements.length()-1

elements[i].draw(a)

end

a

end

elements[i] のクラスが何であれ, そのdrawメソッドが呼ばれる drawall.rb

(23)

… def drawmoon() p0=Point.new(0,85) p2=Point.new(99,85) f=[Line.new(p0,p2), Bezier.new(p0,Point.new(50,60),p2), Circle.new(Point.new(66,20),20)] a=make2d(100,100) drawall(f,a) show(a) end drawall.rb

(24)

練習

• oo-point.rb をダウンロード。

• Point クラスにdrawメソッドを追加せよ。

– すなわち、oo-point.rb のPoint クラスの中に、 def draw(a) … end を追加。 – point.rb の point_draw を参考に。 • p を self に…

(25)

練習(続き)

• さらに、interpolate メソッドを追加せよ。

– 以下のように追加すればよい。 def interpolate(q,t) self.scale(1-t).add(q.scale(t)) end

(26)

練習(続き)

• oo-line.rb をダウンロード。

• oo-bezier.rb をダウンロード。

• oo-circle.rb を萩谷のページからダウンロー

ド。

• drawall.rb をダウンロード。

• isrb を起動し必要なファイルをロード。

• drawmoon() を実行せよ

– 必要なクラス(Point, Line, Bezier, Circle)のファ イルをロードする。

(27)

進捗状況の確認

1. drawmoon が動いた。

2. drawmoon が動かない。

3. ロードができない。

4. interpolate メソッドを追加できない。

5. draw メソッドを追加できない。

6. draw メソッドを作れない。

7. ダウンロードができない。

0 5 10 15 20 25 30 35 40 45 50 1 2 3 4 5 6 7 系列1 2009.12.18

(28)

練習

• これまでの図形クラス(Point, Line, Bezier,

Circle)に、次のメソッドを追加せよ。

trans(dx, dy)

x 軸と y 軸方向に、それぞれ

dx と dy の分だけ平行移動する。

copy()

自分のコピーを返す。

(29)

練習(続き)

• たとえば、Point クラスでは

def trans(dx, dy)

self.x = self.x+dx

self.y = self.y+dy

end

def copy()

Point.new(self.x, self.y)

end

(30)

練習(続き)

• Circle クラスのオブジェクトをコピーするには

中心の点(Point クラスのオブジェクト)をコピ

ー(Point クラスの copy)して、そのコピーと

同じ半径を使って Circle クラスのオブジェクト

を新たに作ればよい。

– 萩谷のページの oo-circle.rb には、copy と trans が定義されてしまっておりました。

• 次スライドの drawmoon2() を動かすには、

Point クラスと Circle クラスに copy と trans

を定義すればよい。

(31)

練習(続き)

def drawmoon2() p0=Point.new(0,85) p1=Point.new(99,85) c0 = Circle.new(Point.new(66,20),20) c1 = c0.copy() c1.trans(10,-10) f=[Line.new(p0,p1), Bezier.new(p0,Point.new(50,60),p1), c0,c1] a=make2d(100,100) drawall(f,a) show(a) end

(32)

練習(続き)

• Bezier クラスは Line クラスを継承している。

• trans メソッドを定義するときには、これを利

用することができる。

– 「継承」のスライドを参照せよ。 – 利用しなくてもよい。

(33)

練習(続き)

def drawmoon3() p0=Point.new(0,85) p2=Point.new(49,85) l0 = Line.new(p0,p2) b0 = Bezier.new(p0,Point.new(25,60),p2) l1 = l0.copy() b1 = b0.copy() l1.trans(45,-10) b1.trans(45,-10) f=[l0,b0,l1,b1,Circle.new(Point.new(66,20),20)] a=make2d(100,100) drawall(f,a) show(a) end

(34)

レポート

• 課題

– Bezier クラスの定義 – drawmoon3() を実行した結果の画像

• 提出先

[email protected]

• Subject:欄は、

is-kadai としてください。

• 〆切:

1月14日(過ぎても受け付けます)

• この課題は成績に含めません。

(35)

課題

• 図形のグループを実現する Group クラスを

定義せよ。

class Group attr_accessor("set") def initialize(set) self.set = set end … – initialize メソッドの引数はオブジェクトの配列

(36)

課題(続き)

• Group クラスにも draw, trans, copy を定義せよ。

• テストとして、drawmoon の配列を使って Group クラスの オブジェクトを作り、表示してみよ。 p0=Point.new(0,85) p2=Point.new(99,85) f=[Line.new(p0,p2), Bezier.new(p0,Point.new(50,60),p2), Circle.new(Point.new(66,20),20)] g=Group.new(f) a=make2d(100,100) g.draw(a) show(a)

(37)

課題(最後)

• Group クラスのオブジェクトのコピーを作った

り、 並行移動したりして、適当な絵を描いて

表示せよ。

• 同じオブジェクトのコピーをたくさん作って並べた りできる(はず)。 • Group クラスのオブジェクトをさらに集めてグル ープにすることも可能である(はず)。

(38)

レポート

• 課題

– Group クラスの定義 – 絵を描くプログラムとその画像

• 提出先

[email protected]

• Subject:欄は、

is-kadai としてください。

• 〆切:

1月末日(過ぎても受け付けます)

(39)

継承

class Bezier < Line

attr_accessor("p0", "c", "p1") def initialize(q,r,s) super(q,s) self.c = r end … def turn(theta) super(theta) self.c = self.c.rotate(theta) end end Lineクラスを継承 Lineクラスの初期化メソッドを呼び出す Lineクラスのturnメソッドを呼び出す oo-bezier.rb

(40)
(41)
(42)
(43)
(44)

オブジェクト,クラス,インスタンス変数,メソッド

• オブジェクト – コンピュータのなかで「もの」に対応する"もの" • クラス – 同じようなオブジェクトをまとめたもの – プログラミングでは先にクラスを定義しておき,必要に応じ てクラスに属するオブジェクトを生成する – 生成したオブジェクトを,クラスのインスタンスという • インスタンス変数 – オブジェクトなかでデータを表す要素 – レコードではフィールド,「もの」の視点では属性に対応 • インスタンスメソッド – オブジェクトの操作を行うためのメソッド メッセージのやり取りはメソッドの呼び出しで代用 メッセージの内容は引数に対応

(45)

カプセル化,継承,多相性

• カプセル化 – 「もの」を表すデータとメソッドをまとめ,決められたインス タンスメソッドを通してのみインスタンス変数にアクセスを させ,インスタンス変数に直接触らせないこと • 継承 – 他のクラスのインスタンス変数やメソッドを受け継いで新 しいクラスを作ること – 新しいクラスをサブクラス,元のクラスをスーパークラスと 呼ぶ • 多相性 – 同じ名前のインスタンスメソッドを呼び出しても,適用され たオブジェクトによって異なるメソッドを呼び出すこと – 実行時にメソッドを探す動的結合で実現する

(46)

オブジェクト指向プログラミング言語

• オブジェクト指向の要素をどのように言語としてまと めるかは,プログラム言語設計者の腕のみせどころ であり,いろいろなバリエーションがある • ここではRubyでの書き方を紹介する • 一つの言語で書き方を覚えておけば,他のバリエー ションも短時間で使いこなすことができるようになる だろう • バリエーションについては第10章で少し紹介する

参照

関連したドキュメント

点から見たときに、 債務者に、 複数債権者の有する債権額を考慮することなく弁済することを可能にしているものとしては、

の 立病院との連携が必要で、 立病院のケース ー ーに訪問看護の を らせ、利用者の をしてもらえるよう 報活動をする。 の ・看護 ・ケア

□ ゼミに関することですが、ゼ ミシンポの説明ではプレゼ ンの練習を主にするとのこ とで、教授もプレゼンの練習

● 生徒のキリスト教に関する理解の向上を目的とした活動を今年度も引き続き

まず、本校のコンピュータの設置状況からお話します。本校は生徒がクラスにつき20人ほど ですが、クラス全員が

● 生徒のキリスト教に関する理解の向上を目的とした活動を今年度も引き続き

 講義後の時点において、性感染症に対する知識をもっと早く習得しておきたかったと思うか、その場

※4: 国際規格 IEC60034-30 及び JIS C 4034-30 で規定されている効率クラスを満たすモータで、IE3