八葉の日記

日々、感じたことをまとめる場として利用する

SOLID原則:2つ目 オープン・クローズドの原則(OCP:Open-Closed Principle)

〇オープン・クローズドの原則(OCP:Open-Closed Principle)
1.拡張に対して開かれている
2.修正に対して閉じている

1つ目はモジュールの振る舞いを変更できること、2つ目はモジュールの振る舞いを拡張しても、
そのモジュールのソースコードやバイナリは影響を受けないことを示します。
簡単にいうと、ソースコードをいじらなくてもモジュールの振る舞いを変更できるということを
いっています。

OCPを守ってないケースから、守っているケースへ設計を修正していきながら
説明していきます。

例えば、GUIで複数画面を表示する設計を考えます。
画面の例:商品画面と商品の説明画面を表示する
f:id:konboi_kun:20171112171740p:plain
このソフトウェアには以下のような画面追加が拡張として予測できます。
f:id:konboi_kun:20171112172913p:plain

〇OCPに従わない設計
単純にクラス設計すると以下のような感じになり、コードはそれぞれに対して
createを呼ぶという感じになると思うのですが、これは予測した拡張に対して、
コードの修正が必要です。
f:id:konboi_kun:20171112172719p:plain

//すべてのWindowを表示する
void Display::Create()
{
	//Picture部分の生成
	picture.Create();

 	//Detaile部分の生成
	detaile.Create();
}

f:id:konboi_kun:20171112174833p:plain

//すべてのWindowを表示する
void Display::Create()
{
	//Picture部分の生成
	picture.Create();

 	//Detaile部分の生成
	detaile.Create();

 	//Review部分の生成 ← 画面追加の度に追加が必要
	review.Create();
}

〇OCPに従った設計
f:id:konboi_kun:20171112175255p:plain
WindowIFというInterfaceクラスを用意し、Displayはこのクラスに依存するようにします。
すると以下のようにコードすることができます。
このコードは今後どれだけWindowが追加拡張されても、修正は不要です。

//すべてのWindowを表示する
void Display::Create()
{
	typedef vector< WindowIF* > Container;
	for (Container::iterator p = container.begin();
             p != container.end();
             ++p)
        {
                (*p)->create()
        }
}

最後にですがOCPの原則を適用するにはモジュールに対しての共通性と可変性の分析が必要になってきます。
分析した可変性に対してInterfaceのような抽象を用いることで、変更に対しての修正が発生しないように
するのですが、抽象自体の意味が後々変わった場合は修正が必要になります。
これを避けるためには、しっかりとした共通性分析を可変性分析が必要になってきます。

アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技

アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技

SOLID原則:1つ目 単一責任の原則(SRP:Single Responsibility Principle)

〇まえおき

ソフトウェアの開発に携わっっている方なら、ひどいコードの保守にあたって、
心身がとても疲れた経験はあると思うし、自分が作ったコードが人を大変な目に
会わせたことはあるんじゃないかと思います。
それらのコードは作ったときはヒドイコードではなかったんですが、
その後、数年をかけて徐々にひどくなっていったんじゃないかと思っています。

「ひどくならないようにオブジェクト指向というやつを利用したのに」
ということを言ったり聞いたりすることがありますが、中々に難しいので、
オブジェクト指向の有名な原則であるSOLID原則をまとめてみようかと思います。

ちなみに難しくなる理由なんですが、最初にソフトウェアを作ったときに
予期していなかった機能をむりやり追加することがほとんどです。
だから、変更を許容する設計が必要になるのですが、そのためのコツが
SOLID原則にまとめられていると思います。


〇単一責任の原則(SRP:Single Responsibility Principle)
クラスを変更する理由は1つ以上存在してはならない。

これはクラスは1つの役割を持つように作りましょうということです。1つの役割のみ持っているなら、
変更の理由も(1つの)役割の変更になるので、自然と上記の原則は守られます。

例えば、データを取得して、画面に表示するようなソフトを作りたいとします。
乱暴にやると次のように設計できます。
f:id:konboi_kun:20171111171026p:plain

こうなると画面表示に変更が入るパターンは次の3つだと思います。
・画面表示の仕組みが変わった
 例:今までは白黒だったけど、カラーにも対応してね
・計算のルールが変わった
 例:法律、組織改革、社長の気紛れで、やり方が変わったから、
   ソフトの方も変化に追従してね
・データベースが変わった
 例:最近のはやりに合わせてRDB使おうよ。

このクラスをどれか1つの理由で変更するときは、他2つの役割に影響がないように
細心の注意をもって変更する必要があり、影響範囲の再試験が必要です。
(不具合だしてもいいなら、適当にやればいいんですが、不具合が許容される
ソフトウェアはありません。
金をとっていなくても不具合だすとクレームが来ます)

もし、元からクラス設計がSRPの原則に従っていたならば、面倒な影響範囲調査と
再試験の気苦労がなくなっていたはずです。


アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技

アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技

placement new(確保済みアドレスを指定する)について

placement newという通常のnewと異なるメモリアロケート方法があり、
通常のnewに比べて、以下の利点がある。
・メモリアロケートの時間が短縮される
・メモリアロケートの例外が発生しないように制御できる

■使い方
通常のnewと違い明示的にデストラクタを呼ぶ必要があります。

#include <cstdlib>
#include <cstdio>

#include <iostream>

class Sample
{
	char a[256];
};

int main()
{
	//①メモリアロケート
	char* p_memory = new char[1024];

	//②オブジェクトの初期化
	Sample* p = new(p_memory) Sample();

	//③オブジェクトの破壊
	p->~Sample();

	//④メモリ解放
	sth::operator delete(p, p);

	return 0;
}


最後に利点について補足します
・メモリアロケートの時間が短縮される
 通常newの処理はざっくりいうと、使用できるメモリを探す→オブジェクトへ割り当る→コンストラクタで初期化
 初めの、使用できるメモリを探す処理は結構ややこしく、メモリの断片化を防ぐために効率よくメモリ配置が行わ
 れるため、時間がかかります。

 確保済みアドレスを指定する場合は、①のメモリアロケートを事前に行うことで、
 その後の処理時間を短縮できます。 

・メモリアロケートの例外が発生しないように制御できる
 ①のメモリアロケートを事前に行い成功すると、②の処理で失敗することはない。
 (失敗する理由がない、また、C++14から例外投げないことが明示されたと思います)

 このことからシステム設計段階で各モジュールが利用できるメモリサイズを決めて置くと、
 以下のことができます。
 ・システム起動時にメモリ確保
  →普通成功する。万が一失敗した場合は、システム自体起動しない。
 ・実行中のnewの処理でplacement newを使用していると、実行時にエラーが
  発生しない。
  →メモリアロケート失敗時のめんどくさい例外処理を考えなくてよい

これを戦闘機のシステムのように実行時エラーが許されない(実行時エラー起こしたら墜落します)
ものに適用すると、リスクが減らせるから推奨されるようです。

確かF35から適用されたコーディングルールには適用されていたかと思う。
http://www.stroustrup.com/JSF-AV-rules.pdf

改行文字の有無判定と修正

与えられた文字列に対して、改行文字の有無を判断し、

改行文字がない場合は改行文字を追加するという関数を

作りたい。

 

★の部分で詰まる改行文字を追加しないといけないけどどうすればできる?

string使うとかはなし、古いコードでデバッグ文字に改行有無が混在しているため。

可能ならば、コンパイル時に処理が終了して、実行速度に影響がないと嬉しい

 

 

template<typename T, int N>
T*
SAMPLE(T(&x)[N])
{
 if (x[N - 2] == '\n')
 {
  return x;
 }

 //constの場合はここでconstを外す
 types<T>::type y[N + 1] = { 0 };
 strcpy_s(y, N, x);
 y[N - 1] = '\n';

 return y;★
}

int main()
{
for (int i = 0; i<10; i++) {

::Sleep(1000);
::OutputDebugString(TEXT(SAMPLE("Hello!")));

}
return 0;
}

データベースについて

仕事で1年目にデータベースを使っていたけど、復習のために再勉強。

■主キー

DB上のデータのタプル(データ構造を示す組のこと→行ともいう)を一意に示すことができるキーをいう。複数の列(属性)で構成されうこともある。

・一意静制約

・非NULL制約

 

■候補キー

主キー候補となるキーを示し、行を一意に識別できる最小のキーの組をいう。

NULLでもいい。

 

■スーパーキー

行が一意に識別できるキーをいう。というか左記の条件を満たす属性の組み合わせは多すぎるから業務でつかったことなし。

例えば、属性が①~③まであって主キーが①ならスーパーキーは以下となる。

・①、①②、①③、①②③

 

 

UMTP L2合格しました

UMTP L2 合格しました。

以下の参考書の意味が分かっていれば合格できます。あとは黒本で過去問を2回位とけばいける感じ。

 

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

 

 

UMLについて モデリング

 ■モデリングの種類

・ビジネスモデリング

システム化対象の業務(ビジネス)をモデル化する。主に業務の流れをモデル化には、アクテビティ図、業務用語からの関連データ抽出には、クラス図が利用される。

 

・要求分析モデリング

システムに対する要求をモデル化する。システムに対するユースケースごとの分析が主なため、ユースケースシナリオとユースケース図でモデリングされる。

 

・分析モデリング

ユーザー視点でシステム対象分野を分析してモデル化する。

 

・設計モデリング

実装者視点でシステム対象分野を分析してモデル化する。