第6回 データ構造とアルゴリズムの結合

第6回
データ構造とアルゴリズムの結合
~手続き指向からオブジェクト指向へ[Ⅱ]~
学習目標

データ構造とアルゴリズムを結合させたク
ラスを使ったプログラムが書ける


データ構造とアルゴリズムが結合することの
利点を説明できる
クラスのデータをカプセル化することができる


データをカプセル化することの利点を説明できる
クラス図が読める
6.1 アルゴリズムと
データ構造の結合




6.1.1 仕様変更に伴うMainプログラムの変
更
6.1.2 問題の本質
6.1.3 データ構造とアルゴリズムの結合
6.1.4 データ構造とアルゴリズムを結合し
たプログラムを書く
6.1.1 仕様変更



①配列リストによる商品種類プログラム
②実装方法変更
③またまた実装変更!?
①配列リスト②連結リスト

①第4回で実装した配列版
ItemTypeListクラス


今回はItemTypeArrayListクラスとします
②第5回で実装した連結リスト版
ItemTypeListクラス

今回はItemTypeLinkedListクラスとします
③戻したら動かなくなった
//例題6-3:また仕様変更
public class Example6_3 {
//取り扱う商品種類を追加するプログラム
public static void main(String[] args) {
例題6-3
(Example6_3.java)
//商品種類配列リストを生成する
ItemTypeArrayList itemTypeList = new ItemTypeArrayList();
//商品種類を保存するための配列を定義する
ItemType[] itemTypeArray = new ItemType[100];
//商品種類を追加する
for(int i=0;i<100;i++){
itemTypeList.add(itemTypeArray,new ItemType(i,"コーラ",120));
}
//商品種類リストを表示する
itemTypeList.display(itemTypeArray);
}
}
どこがまずいのか
考えてみよう
実はItemTypeListが原因
例題4-5
(Example4_5.java)
/**
* 商品種類を追加する
*/
public void add(ItemType[] targetArray,ItemType addItemType){
//商品種類が入っていない箱を探す
for(int i=0;i<10;i++){
if(targetArray[i] == null){//入っていない
targetArray[i] = addItemType;//書き込む
break;
}
}
}
6.1.2 問題の本質

ケアレスミスを防ぐことはできない


人間が書くものだから
ケアレスミスをした時に原因を発見できるプログ
ラムを書くほうが重要

他人に分かるように書く



クラスは意味のカタマリに
プログラムは意味を明確に
問題の本質を探ってみよう


①クラスの役割分担から
②意味が明確なプログラムという面から
①クラスの役割分担

Exampleにバグがあると思ったら、
ItemTypeListに原因があった

役割分担がうまくいってない
①クラスの役割分担
配列版
配列を持ってる
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
Example
連結リスト版
ItemTypeList
連結リストを
持ってる
22(id)
23(id)
コーラ
ソーダ
102番地
Example
null
配列操作
アルゴリズムを
持ってる
add()
insert()
連結リスト操作
アルゴリズムを
持ってる
add()
insert()
ItemTypeList
②意味が明確なプログラム

現状のプログラムは、データ構造(配列)を気にしすぎる

より意味が明確なプログラムのほうが、意図した動作を期待しや
すい
//メインクラス
public class Example6_3 {
//取り扱う商品種類を追加するプログラム
public static void main(String[] args) {
//商品種類配列リストを生成する
ItemTypeArrayList itemTypeList = new ItemTypeArrayList();
//商品種類を保存するための配列を定義する
ItemType[] itemTypeArray = new ItemType[100];
現在のプログラム
「配列」に
「商品種類」を追加する
//商品種類を追加する
for(int i=0;i<100;i++){
itemTypeList.add(itemTypeArray,new ItemType(i,"コーラ",120));
}
本来の意味(目的)
//商品種類リストを表示する
itemTypeList.display(itemTypeArray);
}
}
「商品種類リスト」に
「商品種類」を追加する
②意味が明確なプログラム
配列操作
アルゴリズム
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
ItemTypeArrayList
add()
insert()
Example
22(id)
23(id)
コーラ
ソーダ
102番地
null
なにを
やりたいん
ItemTypeLinkedList
だっけ?
連結リスト操作
アルゴリズム
add()
insert()
6.1.3 データ構造と
アルゴリズムの結合

2つ合わせて初めて意味がある
配列を使うには
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
連結リストを使うには
22(id)
23(id)
コーラ
ソーダ
102番地
null
配列用アルゴリズム
add()
delete()
search()
display()
連結リスト用アルゴリズム
add()
delete()
search()
display()
6.1.3 アルゴリズム
とデータ構造の結合

データ構造とアルゴリズムを結合して
「意味のカタマリ」を作る

2つ合わせて初めて「リスト」という意味がある
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
配列操作
アルゴリズム
add()
insert()
ItemTypeArrayList
Javaでのプログラム(配列)
//商品種類リスト配列実装クラス
public class ItemTypeArrayList {
例題6-4
(Example6_4.java)
public ItemType[] itemTypeArray;//商品種類を保存する配列
//商品種類を追加するメソッド
public void add(ItemType addItemType){
//商品種類が入っていない箱を探す
for(int i=0;i<10;i++){
if(itemTypeArray[i] == null){//入っていない
itemTypeArray[i] = addItemType;//書き込む
break;
}
}
}
}
データ構造
と
それを操作する
アルゴリズム
Javaでのプログラム(連結リスト)
//商品種類リスト連結リスト実装クラス
public class ItemTypeLinkedList {
public LinkObject first;//連結リスト始点
public LinkObject last;//連結リスト終点
//商品種類を追加するメソッド
public void add(ItemType addItemType){
LinkObject addLink = new LinkObject();
addLink.data = addItemType;
if(first == null){//連結リストが空のとき
first = addLink;
last = addLink;
}else{//連結リストが空でないとき
last.next = addLink;
last = addLink;
}
}
}
例題6-5
(Example6_5.java)
データ構造
と
それを操作する
アルゴリズム
データ構造と
アルゴリズムを結合する利点

議論してみましょう
①うまい役割分担

役割分担を考え、各オブジェクトが責任を
持ち、うまくコミュニケーションできるように
するのがオブジェクト指向設計の基本です
商品種類の管理役
命令役
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
配列操作
アルゴリズム
Example
ItemTypeArrayList
add()
insert()
②意味が明確なプログラム
//商品種類配列リストを生成する
ItemTypeArrayList itemTypeList = new ItemTypeArrayList();
//商品種類を保存するための配列を定義する
ItemType[] itemTypeArray = new ItemType[100];
//商品種類を追加する
itemTypeList.add(itemTypeArray,new ItemType(1001,"コーラ",120));
//商品種類リストを表示する
itemTypeList.display(itemTypeArray);
例題6-4
(Example6_4.java)
//商品種類リストオブジェクトをインスタンス化する
Main()
ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
//商品種類を追加する
itemTypeArrayList.add(new ItemType(1001,"コーラ"));
//商品種類リストを表示する
itemTypeArrayList.display();
より意味が明確な
プログラムに
②意味が明確なプログラム
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
Example
1001
追加
1001
追加
配列操作
アルゴリズム
ItemTypeArrayList
add()
insert()
連結リスト操作
ItemTypeLinkedList アルゴリズム
22(id)
23(id)
コーラ
ソーダ
102番地
null
add()
insert()
②意味が明確なプログラム

「商品種類」を「リスト」に追加するという意
味の明確なプログラムが書ける
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
Example
配列操作
アルゴリズム
1001
追加
ItemTypeArrayList
add()
insert()
バグの発見が容易


人間は意味のカタマリに注目して、物事を考える
責任分担をして、「意味のカタマリ」を作り、意味の明確な
プログラムを書くことが重要、可読性も上がる
1001
Example
追加
ItemTypeArrayList
??
オマエが悪い!
6.2 カプセル化



6.2.1 不正な操作
6.2.2 不正な操作を防ぐ
6.2.3 Javaにおけるカプセル化


①Javaで使えるアクセス修飾子
6.2.4 商品種類クラスのカプセル化
6.2.1 不正な操作

以下の例は、誤ったItemTypeArrayListの
使い方です
//商品種類リストオブジェクトをインスタンス化する
ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
//商品種類を追加する
itemTypeArrayList.add(new ItemType(1001,"コーラ"));
itemTypeArrayList.add(new ItemType(1002,"ソーダ"));
itemTypeArrayList.itemTypeArray[0] = null;
これでもプログラムは動いてしまいます!
不正な
ItemTypeArrayListの使い方
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
正規の操作
Example
不正な操作
Example
1001
追加
add()
insert() ItemTypeArrayList
1055
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
add()
insert() ItemTypeArrayList
不正はバグの原因

ItemTypeArrayListは、直接配列をいじら
れるようには作られていません

間にnull等が入ると、おかしな動作をしてしま
います
意味が明確なaddメソッドを利用して欲しい
6.2.2 不正な操作を防ぐ

データの「カプセル化」をして、オブジェクト
の外から参照できないようにします

参照できるのはメソッドだけ
ItemTypeArrayList
add()
insert()
-1 -1 -1 -1 -1 -1
[0] [1] [2] [3] [4] [5]
6.2.3 Javaにおけるカプセル化

「public」だったアクセス修飾子を「private」に
変えます //商品種類リスト配列実装クラス
public class ItemTypeArrayList {
private ItemType[] itemTypeArray;//商品種類を保存する配列
//商品種類を追加するメソッド
public void add(ItemType addItemType){
//商品種類が入っていない箱を探す
for(int i=0;i<10;i++){
if(itemTypeArray[i] == null){//入っていない
itemTypeArray[i] = addItemType;//書き込む
break;
}
}
}
}
不正できなくなる
//商品種類リストオブジェクトをインスタンス化する
ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
//商品種類を追加する
itemTypeArrayList.add(new ItemType(1001,"コーラ"));
itemTypeArrayList.add(new ItemType(1002,"ソーダ"));
itemTypeArrayList.itemTypeArray[0] = null;
アクセス修飾子「private」がついていれば、
コンパイルエラーとなります
①Javaで使えるアクセス修飾子

public


private


そのクラス内でのみ参照可能
protected


すべてのクラスから参照可能
そのクラスとそのサブクラスでのみ参照可能
何もつけない

パッケージ内でのみ参照可能
アクセス修飾子を
理解できたか、簡単なテスト
/**
* アクセス修飾子を解説するためのクラス
*/
public class Access{
public int dataA;
private int dataB;
private int getDataA(){
return dataA;
}
public int getDataB(){
return dataB;
}
}
答え
外部クラス
getDataA メソッド
dataA
dataB
getDataB メソッド
G
Access クラス
6.2.4
商品種類クラスのカプセル化

現状のItemTypeクラス
//商品種類のクラス
public class ItemType{
int id; // 商品番号
String name; // 商品名
//コンストラクタ
public ItemType(int initId, String initName){
id = initId;
name = initName;
}
}
保守性を高くした
ItemTypeクラス
//商品種類のクラス
public class ItemType{
private int id; // 商品番号
private String name; // 商品名
例題6-6
(Example6_6.java)
商品番号と商品名への
直な参照を禁止します。
//コンストラクタ
public ItemType(int initId, String initName){
id = initId;
name = initName;
}
//商品番号を得るメソッド
public int getId(){
return id;
}
//名前を得るメソッド
public String getName(){
return name;
}
}
変わりに、publicで
それらを得ることができる
メソッドを用意します。
これで、商品番号と商品名はコンストラクタで
一旦設定されたら、外部から変更できなくなりました。
外部から設定変更を許すとき
//商品種類のクラス
public class ItemType{
private int id; // 商品番号
private String name; // 商品名
//コンストラクタ省略
//商品番号を得るメソッド
public int getId(){
return id;
}
//名前を得るメソッド
public String getName(){
return name;
}
//名前を設定するメソッド
public void setName(String newName){
name = newName;
}
}
変更を許す属性にのみ
publicな変更メソッドを
用意します
何故設定と取得を分けるの?
//商品種類
public class ItemType{
private String name; // 商品名
//商品種類のクラス
public class ItemType{
public String name; // 商品名
}
//名前を得る
public String getName(){
return name;
}
VS
//名前を設定する
public void setName(String newName){
name = newName;
}
}
利用する時を
考えよう
itemType.name = "コーラ";
System.out(itemType.name)
itemType.setName("コーラ")
System.out(itemType.getName())
利用するクラスから見れば

ItemTypeListの変更
コンパイル
エラー
取得?設定?
System.out.println(itemTypeArray[i].name+"は販売中です");
System.out.println(itemTypeArray[i].getName()+"は販売中です");
意味が明らか
設定と取得を分ける理由

クラスを利用する側から見れば


取得なのか設定なのか明確なプログラムが書
ける
クラスから見れば、




取得はできるけど設定はできない変数
設定されたら困る変数
取得した時だけログをとりたい場合
設定した時だけログをとりたい場合
6.3
クラスの構造を図解する


6.3.1 クラス図とは
6.3.2 記法



①クラスを表現する
②クラス間の関係を表現する
6.3.3 今回までのクラス図
6.3.1 クラス図とは

Example,ItemType,ItemTypeListなど、ク
ラスの構成が複雑化してきました
見やすいように図解する方法
クラス図
クラス図

クラス図はクラス構造を分かりやすくする
ためのものです
ItemTypeArrayList
Main
+ main()
1
add()
delete()
search()
display()
+
1 +
+
+
1
0..n
ItemTypeLinkedList
1
1 +
+
+
+
add()
delete()
search()
display()
+next LinkObject
1
ItemType
- id
- name
0..n + getId()
+ getName()
記法①クラス
ItemType
可視性
public+
private -
- id
- name
+ getId()
+ getName()
クラス名
変数
メソッド
記法②関係

「関係」は、Javaで参照を持っていることを
意味し、線で結びます

ListクラスはItemTypeを変数(配列)で参照し
ているので関係があります
ItemType
ItemTypeArrayList
+
+
+
+
add()
delete()
search()
display()
- id
- name
1
+ getId()
0..n + getName()
多重度

単なる関係だけではインスタンスを何個参
照しているのか分からないので、多重度を
つかいます
ItemType
ItemTypeArrayList
クラス
+
+
+
+
オブジェクト
add()
delete()
search()
display()
- id
- name
1
+ getId()
0..n + getName()
1対nの関係
itemType
ArrayList
1001
コーラ1002
ソーダ
1003
お茶
今回までのクラス図
ItemTypeArrayList
Main
+ main()
1
+
1 +
+
+
add()
delete()
search()
display()
1
0..n
ItemTypeLinkedList
1
1 +
+
+
+
add()
delete()
search()
display()
+next LinkObject
1
ItemType
- id
- name
0..n + getId()
+ getName()