Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

classクラス設計のお話

classクラス設計のお話
by

rti 7743

on 27 September 2010

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of classクラス設計のお話

クラス設計のお話
~反論大歓迎www~ by rti の前に グローバル変数を
disる。 グローバル変数が
なぜダメか。 どこで誰が書き換えたか
よく分からないから。 ↑重要 誰が書き換えたのか
よく分からないから
追跡ができない。 誰が管理しているのか、
誰が悪いのか、
責任の所在が
はっきりしない。 そこでデータの
カプセル化/情報の隠匿。 (クラスの持つ性質の2つのうちの1つ) class Person
{
private:
  //Nameの書き換えができるのは
  //このクラスメソッドだけ
  std::string Name;
};
情報を制限する。 Name にアクセスし書き換えることが
できる機会を少なくすることで、
不用意なデータの書き換えで
プログラムがおかしくなることを防ぐ。 逆に言えば、
Name を適切に管理することは
Person クラスの責任である。 Name が変になったときは、
Personクラスが真っ先に疑われる。

そして、disられる。 Person テラカワイソス 悲しいけど、でも、
これプログラムなんだよね。 Tシャツもあるよ いいクラス設計を
考える の前に
ダメなクラスを
考える。 だめなクラスって
どんなクラス? 長いクラス 巨大なクラス .cppが1万行ある
クラスを考える。
でかい どこで誰が何を
書き換えているのか
さっぱり
わかりません。 でかすぎる これでは、
メンバ変数が
グローバル変数と化す。 自由に使えるサンプルがなかったので、
自分で作ったプログラムを結合しまくって、
巨大なクラスを作りましたwww これの逆に
短いクラスを
考える。
class Person
{
public:
Person(const std::string & inName)
: Name(inName)
{
}
std::string getName() const
{
return this->Name;
}
private:
//これを操作できるのは Personクラスだけ
std::string Name;
}; どこでNameを書き換えているか
一発で分かります。 つまり。 でかいクラスはダメなのです。
ダメな理由はグローバル変数が
ダメな理由と一緒です。
ぢゃあ
どうするればいいの? 小さいクラスをたくさん作ります。 クラス クラス クラス クラス でかい
クラス それを組み合わせて、
複雑なことを行います。 クラス クラス クラス クラス やりたいこと
クラス 呼び出す あれ?
これって関数と似てない? 反論:
これではクラス数が膨大になって、クラス数の爆発が起きませんか? namespace(C++) や
package(C#等) で
グルーピングします 私は手抜きなんで気に
しないんですけどw クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス 小さいクラスがたくさん クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス クラス グルーピング socket db html すっきり。 小さいクラスと
巨大なクラスの
見分け方は? 行数より
メンバ変数の数で
見てます。 rtiの独断と偏見にみちた基準 メンバ変数が 5個以上にぐらいで黄色信号
10個ぐらいになると赤信号 もちろん、
例外もあります。 だけど、
人間は多くのものを
把握できないものです。
class
{
private:
int Age;
std::string Name;
std::string Tel;
std::string Address;
std::string Mail;
}; メンバー変数5個 class
{
private:
int Age;
std::string Name;
std::string Tel;
std::string Address;
std::string Mail;
int Number;
int Salary;
std::string Section
std::string Title;
int Birthday;
}; メンバー変数10個 メンバ変数の爆発がダメなら、
メソッドの爆発はいいの? メソッドの爆発は
とりあえず大丈夫。 これもrti基準 ただし、
オブジェクトの状態を
変異させるメソッドには
注意が必要 setter 邪悪 setterを量産しては、
せっかく情報を隠した
意味がないです。 class Person
{
public:
Person(const std::string & inName)
: Name(inName)
{
}
std::string getName() const
{
return this->Name;
}
void setName
(const std::string & inName)
{
this->Name = inName;
}
private:
std::string Name;
}; 情報を書き換えられる
メソッドは
できるだけ少なくします。 const!! constメソッドは
自分はメンバ変数を
書き換えないと
宣言しているメソッドです。 class Person
{
public:
Person(const std::string & inName)
: Name(inName)
{
}
std::string getName() const
{
return this->Name;
}
private:
std::string Name;
}; constメソッドは、
C++で一番キュートで
セクシーな機能 キリッ これも独断と偏見ですw class Person
{
public:
Person(const std::string & inName)
: Name(inName)
{
}
std::string getName() const
{
this->Name = "書き換え";
}
private:
std::string Name;
}; コンパイルエラーになる constかわいいよconst (*゚ ∀゚)=3ムッハー! C++使っているなら
できるだけ
constメソッドを
量産しよう!! 継承について 継承は2つの意味があります。 インターフェースを定義する。 クラスの差分を追記する。 実装の継承 インターフェース継承 C#でいう abstract継承 C#でいう interface継承 C++だと
interface継承は純粋仮想クラス「だけ」で
構成したクラスという感じでしょうか。
interface継承は大歓迎 でかいクラスはよくない。
大きいことは悪いことだ。 状態を変異させるのはよくない。
constはかわいい。
かわいいは正義 状態が変異しないということは、
1000億回呼び出しても副作用がない。 class Person
{
public:
Person(const std::string & inName)
: Name(inName) , Count(0)
{
}
std::string getName() const
{
return this->Name;
}
int countUp()
{
return ++this->Count;
}
private:
std::string Name;
int Count;
}; 変異しない 変異する それぞれを1000回呼び出すと? Person person;
int i ;
for (i = 0 ;i < 1000; i++)
{
person.getName();
person.countUp();
}
Name は変更はないが、
Count は 1000になる。 なぜ
変更されるか、
変更されないかが
大事なの? そもそもの議論を思い出す。
なぜグローバル変数が悪いのか。

どこで変更されるかわからない。
変更されないというのは
その真逆ともいえる。 で、話を戻して、、 class IPlayer
{
public:
virtual void Play() = 0;
}; class NetPlayer :
public IPlayer
{
virtual void Play()
{
ネットからダウンロードする
画像と音に変換する
画像を画面に出して
  音を鳴らす。
}
}; class IPlayer
{
public:
virtual void Play() = 0;
}; class CD :
public IPlayer
{
virtual void Play()
{
CDを回転して読み込む
データから音に変換する
音を鳴らす
}
}; 共通のインターフェースで
操作することができる。 これをポリモーフィズムといって、
日本語では多様性とかいいます。 (クラスの持つ性質の2つのうちのもう1つ) interface継承は

なので
どんどんやりましょう。
大歓迎 実装の追記である
abstract継承は
注意が必要 悪いとはいいませんが、
やりすぎに注意して。 なぜか? 継承はクラスの
足し算だからです。 クラス同士を結合し、
より大きなクラスを生成します。 class Base
{
protected:
int Count;
public:
virtual int countUp()
{
this->Count += 1;
}
int getCount const()
{
return this->Count;
}
}: class SuperCount :
public Base
{
private:
int UpCount;
public:

virtual int countUp()
{
this->Count += this->UpCount;
}
int setUpCount(int inUpCount)
{
this->UpCount = inUpCount;
}
}; 継承 class SuperCount{
private:
int Count;
int UpCount;
public:
virtual int countUp()
{
this->Count += this->UpCount;
}
int getCount const()
{
return this->Count;
}
int setUpCount(int inUpCount)
{
this->UpCount = inUpCount;
}
}: 継承せずに
書くとこうなる。 巨大なクラスに
近づいてしまう。 よく考えて
継承するようにします 委譲 is-a has-a の関係と
実装の継承 is-a 同じカテゴリに含まれるような関係 「車」は「乗り物」のカテゴリ has-a 持っている、所有しているのよう関係 「車」は「車輪」をもっています 「車」 は 「乗り物」である。 is-aの関係 「車」 は 「乗り物」を持っている?? has-aの関係!? 「車」 は 「車輪」をもっている has-aの関係 「車」 は 「車輪」である??? is-aの関係?? 基本的に継承が
許されるのは、
is-aの関係のときです
has-a の時に、
継承すると
不思議なことになります has-a の時には、
委譲を行います。 //タイヤ
class Tire
{
};

//車はタイヤを4つもってる
class car
{
private:
Tire tire[4];
}; 委譲 委譲のメリット 継承ではないので
クラスの足し算が行われない。 クラスは巨大にならない 個人的に、 アンチ実装の継承 なので、委譲大好きです。 継承は数えるほどしかしませんが、
委譲は山のようにします。 これは何? 再生ボタン 動画の再生ボタンと
CDプレイヤの再生ボタンは、
同じ再生だけどやることが違う ネットからダウンロードする
画像と音に変換する
画像を画面に出して
  音を鳴らす。 CDを回転させてデータを読み込む
データから音に変換する
音を鳴らす ユーザーは同じ やることが違っても インターフェースで
操作ができる。 ボタンが押されたとき Play 小技 クラス内で確保したリソースは、
特別な理由がない限り、
デストラクタで解放する class Buffer
{
public:
Buffer()
{
this->Buffer = NULL;
}
virtual ~Buffer()
{
delete [] this->Buffer;
}
void Alloc(uint size)
{
this->Buffer = new char[size];
}
}; メモリが必要な場合は
std::vector で確保 ちなみに先ほどのようなクラスは不要ですなw char * p = new char[100];
strcpy(p , "11111111");
delete [] p: std::vector<char> p(100);
strcpy( &p[0] , "11111111"); deleteし忘れがなくなるよ!!
std::vectorのみ &p[0] したときの連続性は保証されているよ。 雑用クラスの
Utilは何かと便利。。。
雑多なモジュールを入れるクラスを
一つ作っておくと便利です。 class Util
{
public:
//単語の数を数える
static void WordCount
{
}
}; public static なのでどこからでも
インスタンス作成なしで呼べます。 Util::WordCount("/a/a/a","/"); 今までの内容と矛盾する? 状態を持ちません。
(メンバ変数を持たない) 汎用的な処理がクラスに
ばら撒かれるのを防げます。 似たような処理がたくさんできたら、
別クラスとして分離し独立させる
こともできます。 1プロジェクトに
1つはUtilクラス欲しいところ。

最初に作っとかないと
それぞれの開発者が
独自に作るので効率が悪い。 非スレッドセーフ上等 特別な理由がない限り、
スレッドセーフを
個々のクラスが
気にすることではありません。 スレッド マ



ャ コイツが
スレッドセーフにする
責任を追う クラス クラス クラス クラス クラス クラス 非スレッドセーフ 逆に、
個々のクラスが
スレッドセーフ性を
考えなければいけないような
状態は設計がおかしい スレッド マ




? クラス クラス クラス クラス クラス クラス 誰も責任を取らない。。。。
マネージャ仕事しろ!! 直接やり取り 設計が
おかしい 書き込み可能な
シングルトンは要注意 singleton を利用すれば
クラスを超えて
データを
持ち運ぶことができます int memoryLimit =
MySingleton::
getInstace()->
ReadMemoryLimit(); 便利なんですが、
これってある意味
グローバル変数ですよね。 MySingleton::
getInstace()->
SetMemoryLimit(1024); 書き込みsingletonには注意 読み込みは仕方ない。 グローバル変数の悪夢再び ここまでのまとめ カプセル化してデータを隠そう。
カプセル化はクラスの2つの特性のうち1つ。 誰が責任を取るのかを明確に ここまでのまとめ 継承にはinterfaceの継承と、
実装の継承がある。 実装の継承はクラスの足し算になる。
継承は is-a の時にやって、
has-a のときは委譲しよう。
inerfaceの継承はクラスの特性の一つ
ポリモーフィズムを実現する。
まとめ 誰がデータを
書き換える権利/責任が
あるかを明確にします。 カプセル化 ポリモーフィズ 別々のものを
同一インターフェースで、
利用できるようにします。 これだけわかれば、
あとは大丈夫!! たぶん。 えんいー\e だって便利だし。。。 全体の http://rtilabs.net/files/2010_05_31/bigclass.cpp.txt ↓ここから落としてみてね class MyClassA
{
private:
int MyWordCount()
{
}
};
class MyClassB
{
private:
int OreOreWordCount()
{
}
};
アルゴリズムの重複 クラスに
切り出すほどでもない、
同じアルゴリズムを

開発者ごと、
クラスごとに作るのは
効率が悪い。 でかいことは
悪いことだ。 組織で
別部門の人に仕事を
依頼するときに
マネージャを通すのと同じ A部門 B部門 Xさん Yさん B部門マネージャ マネージャを通す。 仕事の依頼 A部門 B部門 Xさん Yさん B部門マネージャ 直接やり取りは効率がいいが 仕事の依頼 ? マネージャがハンドルしきれない ロックの粒度を考えると、
直接やり取りしたほうがいい。
別部門への依頼も直接やり取りの方が早い。

だけど、ハンドルしきれなくなるのも不幸の始まり。

結局は、どっちを取るかは、
バランスになるのかなと。
トレードオフですね。
Full transcript