ドア・イン・ザ・フェイス・テクニックは罪悪感を利用して要求を呑ませる心理テクニックの一つです。
ドア・イン・ザ・フェイス・テクニックは本来の要求より高い要求をあえて行い、相手にわざと断らせて罪悪感を持たせます。そして、すかさず本来の要求を行うというテクニックです。
例えば、仕事の依頼を受ける金額を決めるときに最初はあえてふっかけた金額を提示します。相手が「ちょっとそれはないですよぉ」となったら「じゃぁ今回は特別に・・・」とか何とか言って本来の金額(やや色をつけてもよい)を提示します。
2010年5月31日月曜日
フット・イン・ザ・ドア・テクニック
フット・イン・ザ・ドア・テクニックは相手に要求を段階的に呑ませるための心理テクニックの一つです。
フット・イン・ザ・ドア・テクニックは依頼の難易度を最初は小さくして相手が依頼を受け入れたら徐々に依頼の難易度をを上げていくというテクニックです。
例えば誰かに一万円借りようとするとき、いきなり一万円を要求するのではなく、まず相手が貸してくれそうな3000円を要求して、相手が要求を受け入れたら何かしらの理由をつけて一万円を要求します。
相手はお金を貸すという要求をすでに呑んでいるので拒む自由が有る程度奪われてしまっているのです。
フット・イン・ザ・ドア・テクニックは依頼の難易度を最初は小さくして相手が依頼を受け入れたら徐々に依頼の難易度をを上げていくというテクニックです。
例えば誰かに一万円借りようとするとき、いきなり一万円を要求するのではなく、まず相手が貸してくれそうな3000円を要求して、相手が要求を受け入れたら何かしらの理由をつけて一万円を要求します。
相手はお金を貸すという要求をすでに呑んでいるので拒む自由が有る程度奪われてしまっているのです。
2010年5月29日土曜日
目線の向きで相手の心を読む
今回紹介するのはいわゆる読心術ってやつで心理学の一つです。
心理学の知識があると仕事場でもプラーベートでも心理戦で優位に立てる場合があるので知っていて損はないと思います。
目線の向きで相手の心を読むというのは、ある人が考えごとをしたり、何かを思い出だそうとしたりしている時に内容に応じて目線が変わってくるというものです。
左上
過去に見た光景、体験などを思い出そうとしている。
右上
今までにないこと、新しいことを想像している(嘘や作り話を考えている)
左下
聴覚に関することをイメージしている(曲のタイトル、メロディを思い出している)
右下
身体の動き関することをイメージしている(スポーツ、運動などをしている自分を思い出している)
ちなみにこれは人によっては逆になる場合(左利き等)があるようです。
心理学の知識があると仕事場でもプラーベートでも心理戦で優位に立てる場合があるので知っていて損はないと思います。
目線の向きで相手の心を読むというのは、ある人が考えごとをしたり、何かを思い出だそうとしたりしている時に内容に応じて目線が変わってくるというものです。
左上
過去に見た光景、体験などを思い出そうとしている。
右上
今までにないこと、新しいことを想像している(嘘や作り話を考えている)
左下
聴覚に関することをイメージしている(曲のタイトル、メロディを思い出している)
右下
身体の動き関することをイメージしている(スポーツ、運動などをしている自分を思い出している)
ちなみにこれは人によっては逆になる場合(左利き等)があるようです。
フロー状態について
何かに夢中になって気がついたら「あれ、もうこんな時間か」てなことが結構あったりするんですが、この夢中になってる状態のことをフロー状態とかゾーン状態とか言うそうです。
フロー状態はすごく集中力が高まっているので生産性がかなり高い状態にあります。
しかし、ちょっとした外部からの刺激でこのフロー状態は解けてしまい再びフロー状態になるには15分以上の時間が必要なのだそうです。
仕事中に質問したりすると質問された人がフロー状態にいた場合、フロー状態が解けて生産性が下がってしまい更にフロー状態に再び入る為に15分以上の時間を無駄にしていまいます。
だから、うかつに質問したりしない方がいいんです。
私自身このフロー状態って、その通りだなと思っていて聞いた方が早いなと思っても極力しないで自分で調べるようにしています。
こんな話を仕事場でしたら、なんか鼻で笑われてちょっと悔しかったです。
フロー状態はすごく集中力が高まっているので生産性がかなり高い状態にあります。
しかし、ちょっとした外部からの刺激でこのフロー状態は解けてしまい再びフロー状態になるには15分以上の時間が必要なのだそうです。
仕事中に質問したりすると質問された人がフロー状態にいた場合、フロー状態が解けて生産性が下がってしまい更にフロー状態に再び入る為に15分以上の時間を無駄にしていまいます。
だから、うかつに質問したりしない方がいいんです。
私自身このフロー状態って、その通りだなと思っていて聞いた方が早いなと思っても極力しないで自分で調べるようにしています。
こんな話を仕事場でしたら、なんか鼻で笑われてちょっと悔しかったです。
2010年5月28日金曜日
集約とコンポジションの違い
今日は集約とコンポジションの違いについて書きます。
集約もコンポジションもUMLのクラス図で使われる言葉で、両方ともHAS-Aの関係を表します。記号で書くと
さて、本題です。
集約もコンポジションもUMLのクラス図で使われる言葉で、両方ともHAS-Aの関係を表します。記号で書くと
- ◆-がコンポジション
- ◇-が集約
さて、本題です。
- 集約はClassA型の変数が消滅してもClassB型のメンバー変数は消滅しない
- コンポジションはClassA型の変数が消滅したらClassB型のメンバー変数も消滅する
class ClassA {
// field
ClassB b;
};
これはコンポジションです。class ClassA {
// field
ClassB* b;
// destructor
~ClassA() {
delete b;
}
};
これもコンポジションです。class ClassA {
// field
ClassB* b;
// destructor
~ClassA() {
// do nothing...
}
};
これは集約です。
2010年5月26日水曜日
C++でTemplateMethodパターン
TemplateMethodパターンはスーパークラス(ベースクラス)でロジックの概要設計あるいは共通部分を実装し、詳細ロジックあるいは非共通部分をサブクラスで提供するパターンです。
大げさに言うとスーパークラスでプチフレームワークを実装するようなイメージです。
TemplateMethodパターンのメリットは
- サブクラスで共通なロジックをスーパークラスで共通化できる。
- ロジックの骨組みが明確になっている為、コードが把握し安い且つメンテナンスコストが軽減されやすい。
それではクラス図をご覧ください。
ちょっとメソッドとか多いですけど簡単な継承関係です。
このクラス図で重要なのは
で、Characterクラスのmove()がテンプレートメソッドに相当します。- move()
- canMove()
- canMoveEach()
- moveEach()
次にソースを見てみましょう、用意するのは次のファイルです今回からクラスのcppファイルを用意しない方が見やすいかなと思って.hだけ用意しました。
- main.cpp
- Character.h
- Monster.h
Character.h
#ifndef _CHARACTER_H_ #define _CHARACTER_H_ #includemove()のなかでmove可能ならばmoveするという大まかなロジックを実装しています。class Character { //---------------------------------- // field //---------------------------------- private: int HP; int MP; //---------------------------------- // property //---------------------------------- public: const int getHP() { return this->HP; } Character& setHP(const int _hp) { this->HP = _hp; return *this; } const int getMP() { return this->MP; } Character& setMP(const int _mp) { this->MP = _mp; return *this; } //---------------------------------- // method //---------------------------------- public: Character() : HP(100), MP(100) { // do nothing... } virtual ~Character() { // do nothing... } void move() { // テンプレートメソッド // move可能判定 if (this->canMove()) { // move this->moveEach(); } } private: virtual const bool canMove() { // HPが0ならmove不可 if (this->getHP() <= 0) { return false; } return this->canMoveEach(); } protected: virtual const bool canMoveEach() = 0; virtual void moveEach() = 0; }; #endif
Monster.h
#ifndef _MONSTER_H_
#define _MONSTER_H_
#include "Character.h"
class Monster : public Character
{
//----------------------------------
// method
//----------------------------------
protected:
virtual ~Monster() {
// do nothing...
}
virtual const bool canMoveEach() {
printf("canMoveEach\n");
return true;
}
virtual void moveEach() {
printf("moveEach\n");
}
};
#endif
Monster独自のcanMove()、move()をcanMoveEach()、moveEach()で実装しています。Eachっていう名前の付け方は一般的ではない気がします。main.cpp
#include#include "Monster.h" void main(void) { // Monster生成 Character* character = new Monster(); // move character->move(); // HPに0を設定 character->setHP(0); // move character->move(); delete character; printf("hit any key...\n"); while(getchar() == EOF) {} }
引数の命名規則はアンダーバー「_」+キャメルケース
今更ですけど、メソッド(関数)の引数の命名規則はアンダーバー「_」+キャメルケースを使用しています。
キャメルケースというのは各単語や要素語の先頭の文字を大文字で表記する手法のことです。
例)camelCase、guitarSpec...
そして引数の先頭にアンダーバー「_」を付与しています。アンダーバーを付ける利点は
例)_camelCase、_guitarSpec...
キャメルケースというのは各単語や要素語の先頭の文字を大文字で表記する手法のことです。
例)camelCase、guitarSpec...
そして引数の先頭にアンダーバー「_」を付与しています。アンダーバーを付ける利点は
- 引数であることが一目でわかる。
- クラスのメンバ変数やメソッド内の変数と名前がかぶることが無くなるため名前を考えるのに困らない。
例)_camelCase、_guitarSpec...
2010年5月25日火曜日
C++でクラスメンバ変数を参照型にする
今日はC++でクラスのメンバ変数を参照型にする方法を紹介します。
その方法とは?!
コンストラクタ初期化子を使うとクラスメンバの生成と同時に値を代入したり、メンバのコンストラクタに引数を与えることができます。
これを利用して参照型の変数を初期化することが可能です。
サンプルコードを用意しました。
時間がなくてこんな例しか作れませんでした。
その方法とは?!
- コンストラクタ初期化子を使用する
コンストラクタ初期化子を使うとクラスメンバの生成と同時に値を代入したり、メンバのコンストラクタに引数を与えることができます。
これを利用して参照型の変数を初期化することが可能です。
サンプルコードを用意しました。
#include#include "Monster.h" void main(void) { int hp = 111; int mp = 222; // Monster生成 Monster monster(hp, mp); // 参照している変数の値を変更 hp = 100; mp = 100; // 表示 printf("HP:%d\n", monster.HP); printf("MP:%d\n", monster.MP); printf("hit any key...\n"); while(getchar() == EOF){} }
#ifndef _MONSTER_H_ #define _MONSTER_H_ #includeソースコードの内容については余りつっこまないでください(汗class Monster { //---------------------------------- // field //---------------------------------- public: int& HP; // メンバ変数が参照型 int& MP; // メンバ変数が参照型 //---------------------------------- // method //---------------------------------- public: // constructor Monster(int& _hp, int& _mp) : // コロンをわすれずに! HP(_hp), // 初期化子 MP(_mp) // 初期化子 { // do nothing... } }; #endif
時間がなくてこんな例しか作れませんでした。
2010年5月24日月曜日
C++のエラー:error C2143: 構文エラー : ';' が 'namespace' の前にありません。
今日出たエラーです。
エラーの原因はクラス宣言の括弧の後ろにセミコロン「;」が抜けているだけだったのですが、エラーが出てる場所は全然違う場所で結構迷走しました。
エラーの原因はクラス宣言の括弧の後ろにセミコロン「;」が抜けているだけだったのですが、エラーが出てる場所は全然違う場所で結構迷走しました。
#ifndef _MONSTER_H_
#define _MONSTER_H_
#include "Character.h"
class Monster : public Character
{
//----------------------------------
// method
//----------------------------------
virtual const bool canMoveEach() {
return true;
}
virtual void moveEach() {
}
}//←ココ
#endif
2010年5月23日日曜日
C++でオブジェクトのクラス名(型名)文字列を実行時に取得する
今日はC++でオブジェクトのクラス名を実行時に取得する方法を紹介します。
紹介するといってもtypeid()という関数を使用するだけです。typeid()はtypeinfo.hで定義されているのでincludeする必要があります。
typeid()の引数には変数オブジェクトや型名(クラス名)を直接指定することが出来ます。
またtypeid()の戻り値同士を比較したりも出来ます。
サンプルコードを用意しました。
main.cpp
AbstractClass.h
ConcreteClass.h
紹介するといってもtypeid()という関数を使用するだけです。typeid()はtypeinfo.hで定義されているのでincludeする必要があります。
typeid()の引数には変数オブジェクトや型名(クラス名)を直接指定することが出来ます。
またtypeid()の戻り値同士を比較したりも出来ます。
サンプルコードを用意しました。
main.cpp
#include#include #include "ConcreteClass.h" void main(void) { // ConcreteClassオブジェクト生成 AbstractClass* obj = new ConcreteClass(); // 型名取得 const type_info& id = typeid(*obj); printf("%s\n", id.name()); // method()の呼び出し obj->method(); // 型を直接指定し型名を取得し比較 if (typeid(ConcreteClass) == id) { printf("true\n"); } delete obj; printf("hit any key...\n"); while(getchar() == EOF) {} }
AbstractClass.h
#ifndef _ABSTRACT_CLASS_H_ #define _ABSTRACT_CLASS_H_ #include#include class AbstractClass { //---------------------------------- // method //---------------------------------- public: void method() { // 型情報の取得 const type_info& id = typeid(*this); // 表示 printf("AbstractClass-typeid:%s\n", id.name()); // subMethod()の呼び出し this->subMethod(); } protected: virtual void subMethod() = 0; }; #endif
ConcreteClass.h
#ifndef _CONCRETE_CLASS_H_ #define _CONCRETE_CLASS_H_ #include#include #include "AbstractClass.h" class ConcreteClass : public AbstractClass { //---------------------------------- // method //---------------------------------- public: ConcreteClass() { // do nothing... } virtual ~ConcreteClass() { // do nothing... } protected: virtual void subMethod() { // 型情報の取得 const type_info& id = typeid(*this); // 表示 printf("ConcreteClass-type_id:%s\n", id.name()); } }; #endif
2010年5月21日金曜日
IE(Internet Explorer)でキャッシュを無視して更新する
ブラウザ(IE、Firefoxで確認)でCtrl+F5を押下するとキャッシュ内容を無視して 更新してくれるということを今日知りました。
今まではURLの最後に使用しないURLパラメータを毎回つけたりしていたのですがそんな手間も今日でおさらばです、やったー♪
サーバサイドのプログラムを作成して、ページを更新しても修正内容が更新されないってのは良くある話ですよね。これはブラウザがすでに読み込んだページ内容を保存(キャッシュ)していてそれを表示しているからで、そのことによって次のようなメリットがあります。
それを回避するためにURLパラメータを変更してキャッシュ情報とは違いますよとブラウザにウソついてページを更新してもらっていました。
URLパラメータってのは
今まではURLの最後に使用しないURLパラメータを毎回つけたりしていたのですがそんな手間も今日でおさらばです、やったー♪
サーバサイドのプログラムを作成して、ページを更新しても修正内容が更新されないってのは良くある話ですよね。これはブラウザがすでに読み込んだページ内容を保存(キャッシュ)していてそれを表示しているからで、そのことによって次のようなメリットがあります。
- サーバーからページ内容を読み込むよりも速く内容を表示できる。
- サーバーからの読み込みないためネットワークの負荷を軽減できる。
それを回避するためにURLパラメータを変更してキャッシュ情報とは違いますよとブラウザにウソついてページを更新してもらっていました。
URLパラメータってのは
- http://www.blogger.com/post-edit.g?blogID=1053615194817097162
WSHで(JScript)IEを操作する
WSHでIE(InternetExplorer)も操作できるようなので簡単な検索操作をスクリプトにやらせてみました。
メソッドやプロパティ等はMSDNのリファレンスを参考にしました。
VBAを使いなさいってことなのかな。。。
メソッドやプロパティ等はMSDNのリファレンスを参考にしました。
// IEオブジェクト生成&IE機動
var objIE = WScript.CreateObject("InternetExplorer.Application", "IE_");
// 可視状態にする
objIE.Visible = true;
// 検索ページの表示
objIE.GoSearch();
// シェルオブジェクト生成
var objShell = WScript.CreateObject("WScript.Shell");
// ページが表示されるまで待つ
WScript.Sleep(5000);
// キー送信
objShell.Sendkeys("Google");
// Enterキー送信
objShell.Sendkeys("{ENTER}");
//function IE_DownloadComplete() {
// objShell.Sendkeys("Google");
// objShell.Sendkeys("{ENTER}");
//}
検索ページが読み込まれたことをイベントで受け取ろうとしたのですがうまくできませんでした、JScriptだとつかえないイベントが結構あるようです。VBAを使いなさいってことなのかな。。。
2010年5月20日木曜日
WSH(JScript)におけるカレントディレクトリについて、その2
先日スクリプトファイルを直接実行した時とファイルやフォルダをドラッグアンドドロップした時とでは、カレントディレクトリが変わるっていう記事を書きましたが、WScript.ScriptFullNameを使用すればスクリプトファイルのあるフォルダを取得できますね。
まぁ、カレントディレクトリ==スクリプトが置いてあるフォルダとか思っていた私がウマシカさんでしたw
スクリプトフォルダを取得する関数を作ってみました。
まぁ、カレントディレクトリ==スクリプトが置いてあるフォルダとか思っていた私がウマシカさんでしたw
スクリプトフォルダを取得する関数を作ってみました。
WScript.echo(this.getScriptFolder());
// スクリプトフォルダの取得
function getScriptFolder() {
return WScript.ScriptFullName.replace("\\" + WScript.ScriptName, "");
}
2010年5月18日火曜日
WSH(JScript)でフォルダ配下の全ての動画ファイルの再生時間を取得する
最近WSHの記事ばっかりでしたけどこんなの作ってました。
主な機能
主な機能
- 動画ファイルの再生時間を取得する。
- サブフォルダも含めたフォルダ内の全ての動画ファイルの再生時間を取得する。
- logファイルに出力する。
try {
var main = new main(WScript.Arguments);
main.exec();
}
catch(e) {
WScript.echo(e);
WScript.Quit();
}
function main (_args) {
// Windows Media Playerコントロールオブジェクト生成
this.objWMP = WScript.createObject("WMPlayer.OCX");
// FileSystemObject生成
this.objFileSys = WScript.CreateObject("Scripting.FileSystemObject");
// ShellObject生成
this.objShell = WScript.createObject("WScript.Shell");
// 引数の取得
this.objArgs = _args;
if (this.objArgs.UnNamed.count <= 0) {
throw "ファイル叉はフォルダをドラッグ&ドロップするか\nコマンドラインから引数としてファイル又はフォルダパスを指定してください。";
}
//---------------------------------
// exec()
//---------------------------------
this.exec = function() {
// logファイルの生成(上書きモード)
var logFileName = "PlayTimeLog.txt";
var objLogFile = this.objFileSys.OpenTextFile(logFileName, 2, true);
var fileCnt = 0;
// 全ての名前なし引数について処理する
var unNamedArgs = this.objArgs.UnNamed;
var enu = new Enumerator(unNamedArgs);
for (; enu.atEnd() == false; enu.moveNext()) {
try {
var arg = enu.item();
fileCnt = this.logPlayTime(objLogFile, arg);
}
catch(e) {
objLogFile.WriteLine(e);
}
}
// サマリー情報の書き込み
objLogFile.WriteLine("----------------------------------------");
objLogFile.WriteLine(fileCnt + "件のファイルを処理しました。");
// logファイルのクローズ
objLogFile.Close();
// 完了メッセーの表示
WScript.echo(
"mission completed\n"
+ "作業結果は\n"
+ this.objShell.CurrentDirectory
+ "\\" + logFileName + "\n"
+ "参照"
);
}
//---------------------------------
// サブフォルダも含めて動画ファイルの再生時間をlogファイルに書き込む
//---------------------------------
this.logPlayTime = function (_objLogFile, _path) {
var fileCnt = 0;
// パスがフォルダの場合
if (this.objFileSys.FolderExists(_path)) {
// フォルダオブジェクトの生成
var objFolder = this.objFileSys.GetFolder(_path);
// サブフォルダ一覧取得
var subFolders = objFolder.SubFolders;
// 全てのフォルダについて自分を呼び出す
var enuSubFolders = new Enumerator(subFolders);
for (;enuSubFolders.atEnd() == false; enuSubFolders.moveNext()) {
fileCnt += this.logPlayTime(_objLogFile, enuSubFolders.item().Path);
}
// ファイル一覧取得
var files = objFolder.Files
// 全てのファイルについて自分を呼び出す
var enuFiles = new Enumerator(files);
for (; enuFiles.atEnd() == false; enuFiles.moveNext()) {
fileCnt += this.logPlayTime(_objLogFile, enuFiles.item().Path);
}
}
// パスがファイルの場合
else if (this.objFileSys.FileExists(_path)) {
// ファイルオブジェクトの生成
var objFile = this.objFileSys.GetFile(_path);
// 再生時間の取得
var time = this.getPlayTime(objFile.Path);
// logファイルに書き込み
_objLogFile.WriteLine(objFile.Name + "\t" + time);
// ファイル数をインクリメント
fileCnt++;
}
else {
objLogFile.WriteLine("error:" + _path + "は存在しません");
}
return fileCnt;
}
//---------------------------------
// 動画再生時間の取得
//---------------------------------
this.getPlayTime = function(_filePath) {
// 動画ファイルの読み込み
this.objWMP.URL = _filePath;
// ファイル準備中状態の間待つ
while (this.objWMP.playState == 9) {
WScript.Sleep(500);
}
// 再生時間取得
return this.objWMP.currentMedia.durationString;
}
}
ソースコード長いw
2010年5月17日月曜日
WSHにおけるカレントディレクトリについて
WSHのスクリプトファイルを直接実行した時とファイルやフォルダをドラッグアンドドロップした時とでは、カレントディレクトリが変わるようです。
ファイルやフォルダをドラッグアンドドロップしたときはカレントディレクトリが「Documents and Settings」配下のログインユーザディレクトリ配下になります。
下記に検証用のスクリプトを用意しました。
ファイルやフォルダをドラッグアンドドロップしたときはカレントディレクトリが「Documents and Settings」配下のログインユーザディレクトリ配下になります。
下記に検証用のスクリプトを用意しました。
var shell = WScript.createObject("WScript.Shell");
WScript.echo(shell.CurrentDirectory);
WSH(JScript)でDictionaryを使ってみる
今日はWSH(JScript)のDictionaryを紹介します。
var datas = {
a:"aa",
b:"bb",
c:"cc"
};
// 辞書(Dictionary)の生成
var objDict = WScript.createObject("Scripting.Dictionary");
for (var key in datas) {
// 要素の追加
objDict.add(key, datas[key]);
}
//--------------------------------------
// プロパティ
//--------------------------------------
// 要素数の取得
var cnt = objDict.Count;
WScript.echo("要素数の取得:" + cnt);
// 要素の取得
WScript.echo("要素の取得1:" + objDict.Item("a"));
WScript.echo("要素の取得2:" + objDict("a"));
// キーを変更する
objDict.Key("a") = "A";
WScript.echo("\"A\"の値:" + objDict.Item("A"));
//--------------------------------------
// メソッド
//--------------------------------------
// キーの存在判定
if (objDict.Exists("A")) {
WScript.echo("\"A\"は存在します");
}
// Enumeratorを使用した反復
var enuDict = new Enumerator(objDict);
var strItems = "";
for (; enuDict.atEnd() == false; enuDict.moveNext()) {
strItems += objDict(enuDict.item()) + ",";
}
WScript.echo(strItems);
// キーを指定して削除
objDict.Remove("b");
objDict.RemoveAll();
WScript.echo("要素数:" + objDict.Count);
紹介しておいてなんですが、機能が微妙な上にJScript(JavaScript)は連装配列が使えるのでDictionaryは使わないかもしれません。
2010年5月16日日曜日
JavaScript(JScript)で連装配列を反復する(なめる)
今日はJavaScript(JScript)で連装配列を反復する方法を紹介します。
var array = new Array();
array["a"] = "aa";
array["b"] = "bb";
for (var key in array) {
// WScript.echo(array[key]); // WSHの場合
alert(array[key]);
}
2010年5月15日土曜日
WSH(JScript)で動画の再生時間を取得する
今日はWSH(JScript)で動画の再生時間を取得する方法を紹介します。
try {
// Windows Media Playerコントロールオブジェクト生成
var objWMP = WScript.createObject("WMPlayer.OCX");
// 動画ファイルの読み込み
objWMP.URL = ".\\aaa.wmv";
// ファイル準備中状態の間待つ
while (objWMP.playState == 9) {
WScript.Sleep(500);
}
// 再生時間取得と表示
WScript.echo(objWMP.currentMedia.durationString);
}
catch(e) {
WScript.echo(e);
WScript.Quit();
}
「aaa.wmv」というファイルの再生時間を表示しています。
2010年5月14日金曜日
WSH(JScript)でコレクションを反復する
今日はWSH(JScript)でコレクションを反復する方法を紹介します。
今回 紹介する方法は
例として指定フォルダのファイル一覧を表示するコードを記述します。
今回 紹介する方法は
- Enumratorを使用して反復する
例として指定フォルダのファイル一覧を表示するコードを記述します。
try {
// FileSystemObject生成
var objFileSys = WScript.CreateObject("Scripting.FileSystemObject");
// ファイル一覧(コレクション)取得
var folder = objFileSys.GetFolder("C:");
var files = folder.Files;
// Enumeratorを使用してファイル一覧を反復する
var str = "";
var iter = new Enumerator(files);
for (;iter.atEnd() == false; iter.moveNext()) {
str += iter.item().Name + "\n";
}
// ファイル一覧表示
WScript.echo(str);
}
catch (e) {
WScript.echo(e);
WScript.quit();
}
2010年5月13日木曜日
構造体(struct)の宣言方法にかんする小技
今日はC、C++で構造体を宣言する際の小技を紹介します。小技にもほどがあるって感じなんですけど変数を定義する際にstructっていちいちつけなくても良くなる方法です。
下記がコードです。
下記がコードです。
#includetypedefを使用してデータ型に新しい名前を付けることが出来るのですが、Weaponは宣言を直接typedefしています。struct Character { char name[32]; int HP; int MP; }; typedef struct { char name[32]; int attack; }Weapon; void main (void) { struct Character character; // struct が必要 Weapon knife; // struct が不要 printf("hit any key..."); while(getchar() == EOF){} }
2010年5月12日水曜日
とりあえずconst!
ってぐらい変数にはconst付けてます。ん?だめ?
理由としては
具体的に説明すると、
C#でも使えたらいいのにって思うのは私だけ?
理由としては
- コンパイラにバグを見つけさせる為
具体的に説明すると、
const int value = 1;
if(value = 1) // ← ==のつもり
こんなのとかconst CHoge hoge;
hoge.clear(); // ←本当はclearしてはダメ
とかコンパイルエラーになります。C#でも使えたらいいのにって思うのは私だけ?
2010年5月10日月曜日
C,C++で配列を反復する(なめる)
今日はC,C++で配列を反復する方法を2つ紹介します。
- 配列の要素数を使用して反復する。
- 番兵を使用して反復する。
#includevoid main(void) { //---------------------------------- // サイズを求めて反復に使用する //---------------------------------- const char* strArray[] = { "1", "2", "3", }; const int length = sizeof(strArray) / sizeof(strArray[0]); // 配列のサイズ算出 printf("length:%d\n", length); for (int i = 0; i < length; i++) { // length未満の間ループ printf("%s\n", strArray[i]); } printf("--------\n"); //---------------------------------- // 番兵を立てる //---------------------------------- const char* strArray2[] = { "a", "b", NULL, // 番兵 }; for (int i = 0; strArray2[i]; i++) { // false(NULL)以外の間ループ printf("%s\n", strArray2[i]); } printf("hit any key...\n"); while(getchar() == EOF){} }
2010年5月9日日曜日
コンストラクタで仮想関数を呼び出す(C++)
C++ではコンストラクタで仮想関数を呼び出しても意図した動作にならないんですよね、どんな動きになるかといいますと、オーバーライドした関数ではなく基底クラス(親クラス)の仮想関数が呼び出されてしまいます。
検証用のコードを用意しましたのでまずはクラス図を見てみましょう。
単純な継承関係のクラスを二つ用意しました。init()は仮想関数になっています。
つぎにソースを見てみましょう、用意したのは次のファイルです。
次にCharacterMonster.hです。
最後にmain.cppです。
ということでコンストラクタで仮想関数を呼び出しても意図した動作になりませんでした。
ちなみにinit()を純粋仮想関数にした場合は実体がないためリンクエラーとなります。
なのでinit()メソッドをいつも用意するようにしているのですけどinit()を呼び出すのを忘れたりもするんですよね、ケースバイケースなのかなぁ?。
検証用のコードを用意しましたのでまずはクラス図を見てみましょう。
単純な継承関係のクラスを二つ用意しました。init()は仮想関数になっています。
つぎにソースを見てみましょう、用意したのは次のファイルです。
- main.cpp
- Character.h
- CharacterMonster.h
#ifndef _CHARACTER_H_ #define _CHARACTER_H_ #includeclass Character { public: // constructor Character() { this->init(); } // destructor ~Character() { // do nothing... } protected: virtual void init() { // 仮想関数で定義 printf("init Character\n"); } }; #endif
次にCharacterMonster.hです。
#ifndef _CHARACTER_MONSTER_H_
#define _CHARACTER_MONSTER_H_
#include "Character.h"
class CharacterMonster : public Character
{
public:
// constructor
CharacterMonster() {
// do nothing...
}
// destructor
virtual ~CharacterMonster() {
// do nothing...
}
protected:
virtual void init() { // オーバーライド
printf("init Character Monster\n");
}
};
#endif
最後にmain.cppです。
#include "CharacterMonster.h" #includeinit()はオーバーライドされているのでこのプログラムを実行すると「init Character Monster」が表示されると思いきや「init Character」が表示されてしまいます。void main(void) { Character* character = new CharacterMonster(); delete character; printf("hit any key..."); while(getchar() == EOF){} }
ということでコンストラクタで仮想関数を呼び出しても意図した動作になりませんでした。
ちなみにinit()を純粋仮想関数にした場合は実体がないためリンクエラーとなります。
なのでinit()メソッドをいつも用意するようにしているのですけどinit()を呼び出すのを忘れたりもするんですよね、ケースバイケースなのかなぁ?。
C++でStrategyパターン
Strategyパターンはアルゴリズム(振る舞い)をカプセル化(クラス化)するパターンです。
Singletonパターンのメリットは
見ました?なんか複雑だからってあんまり見てないでしょ?
ちゃんとクリックして拡大して見てくださいね。
このクラス図で重要なのは
つぎにソースを見てみましょう、用意するのは次のファイルです。
②現在の行動アルゴリズムです。
③Monsterに行動指示を出します。
次にMonster.cppです。
次にMonsterStrategy.hです。
②Monsterの行動アルゴリズムが記述されているメソッドです。タイプ毎にアルゴリズムは違うので純粋仮想関数にしています。
次にMonsterStrategy.cppです。
次に
MonsterStrategyFreedom.h
MonsterStrategyFreedom.cpp
MonsterStrategyGangan.h
MonsterStrategyGangan.cpp
をまとめて記述します。
②オーバーライドしたmove()メソッドです。
最後にmain.cppです。
以上でStrategyパターンの説明は終わりです。クラス数は少し多いですがそんなに難しいパターンではないはずです。
ソースコードはコピペで動かせるハズですので是非試してみてください。
Singletonパターンのメリットは
- 振る舞いを簡単に交換することが出来る。
- 振る舞いを動的に交換することが出来る。
まずは次のクラス図をご覧ください
ちゃんとクリックして拡大して見てくださいね。
このクラス図で重要なのは
- MonsterStrategyクラス
つぎにソースを見てみましょう、用意するのは次のファイルです。
- main.cpp
- Monster.h
- Monster.cpp
- MonsterStrategy.h
- MonsterStrategy.cpp
- MonsterStrategyFreedom.h
- MonsterStrategyFreedom.cpp
- MonsterStrategyGangan.h
- MonsterStrategyGangan.cpp
#ifndef _MONSTER_H_
#define _MONSTER_H_
#include "MonsterStrategy.h"
class Monster
{
//----------------------------------
// constant
//----------------------------------
#define STRATEGY_MAX_NUM 8
//----------------------------------
// field
//----------------------------------
private:
MonsterStrategy* m_strategyDictionary[STRATEGY_MAX_NUM]; // ①
MonsterStrategy::Type m_currentStrategyType; // ②
//----------------------------------
// property
//----------------------------------
public:
const MonsterStrategy::Type getCurrentStrategyType();
Monster& setCurrentStrategyType(const MonsterStrategy::Type _type);
private:
MonsterStrategy** getStrategyDictionary();
const bool addStrategy(const MonsterStrategy::Type _type);
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
Monster();
// destructor
~Monster();
// initialize
const bool init();
// move
Monster& move(); // ③
private:
// operator(=)
Monster& operator=(const Monster& _monster);
};
#endif
①Monsterの行動アルゴリズム辞書です。今回は配列を使用していますがDictionary系クラスを私用するのが良いでしょう。②現在の行動アルゴリズムです。
③Monsterに行動指示を出します。
次にMonster.cppです。
#include "Monster.h" #include "MonsterStrategyFreedom.h" #include "MonsterStrategyGangan.h" #include①配列のサイズを求めています。//----------------------------------- // property //----------------------------------- const MonsterStrategy::Type Monster::getCurrentStrategyType() { return this->m_currentStrategyType; } Monster& Monster::setCurrentStrategyType(const MonsterStrategy::Type _type) { printf("strategy %d -> %d\n", this->getCurrentStrategyType(), _type); this->m_currentStrategyType = _type; return *this; } MonsterStrategy** Monster::getStrategyDictionary() { return this->m_strategyDictionary; } const bool Monster::addStrategy(const MonsterStrategy::Type _type) { if (STRATEGY_MAX_NUM <= _type) { throw "error strategy max num"; } MonsterStrategy** strategyDictionary = this->getStrategyDictionary(); if (strategyDictionary[_type] != NULL) { // already exist return false; } switch (_type) { case MonsterStrategy::ST_FREEDOM: strategyDictionary[_type] = new MonsterStrategyFreedom(); break; case MonsterStrategy::ST_GANGAN: strategyDictionary[_type] = new MonsterStrategyGangan(); break; default: throw "invalid type"; break; } return true; } //----------------------------------- // method //----------------------------------- // constructor Monster::Monster() : m_currentStrategyType(MonsterStrategy::ST_FREEDOM) { // do nothing... } // destructor Monster::~Monster() { MonsterStrategy** strategyDictionary = this->getStrategyDictionary(); for (int i = 0; i < STRATEGY_MAX_NUM; i++) { delete strategyDictionary[i]; } } // initialize const bool Monster::init() { MonsterStrategy** strategyDictionary = this->getStrategyDictionary(); for (int i = 0; i < STRATEGY_MAX_NUM; i++) { strategyDictionary[i] = NULL; } const MonsterStrategy::Type strategyTypeArray[] = { MonsterStrategy::ST_FREEDOM, MonsterStrategy::ST_GANGAN, }; const int size = sizeof(strategyTypeArray) / sizeof(MonsterStrategy::Type); // ① for (int i = 0; i < size; i++) { this->addStrategy(strategyTypeArray[i]); } return true; } // move Monster& Monster::move() { MonsterStrategy** strategyDictionary = this->getStrategyDictionary(); strategyDictionary[this->getCurrentStrategyType()]->move(*this); return *this; }
次にMonsterStrategy.hです。
#ifndef _MONSTER_STRATEGY_H_
#define _MONSTER_STRATEGY_H_
class Monster;
class MonsterStrategy
{
public:
//----------------------------------
// constant
//----------------------------------
enum Type {
ST_FREEDOM = 0, // 自由
ST_GANGAN, // がんがん行こうぜ
}; // ①
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategy();
// destructor
virtual ~MonsterStrategy();
// move
virtual void move(Monster& _monster) = 0; // ②
private:
// operator(=)
MonsterStrategy& operator=(const MonsterStrategy& _monsterStrategy);
};
#endif
①Monsterの行動アルゴリズムのタイプです。②Monsterの行動アルゴリズムが記述されているメソッドです。タイプ毎にアルゴリズムは違うので純粋仮想関数にしています。
次にMonsterStrategy.cppです。
#include "MonsterStrategy.h" #include特に何も実装はなしです。//---------------------------------- // mothod //---------------------------------- // constructor MonsterStrategy::MonsterStrategy() { // do nothing... } // destructor MonsterStrategy::~MonsterStrategy() { // do nothing... }
次に
MonsterStrategyFreedom.h
MonsterStrategyFreedom.cpp
MonsterStrategyGangan.h
MonsterStrategyGangan.cpp
をまとめて記述します。
#ifndef _MONSTER_STRATEGY_FREEDOM_H_
#define _MONSTER_STRATEGY_FREEDOM_H_
#include "MonsterStrategy.h"
class Monster;
class MonsterStrategyFreedom : public MonsterStrategy // ①
{
public:
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategyFreedom();
// destructor
~MonsterStrategyFreedom();
// move
void move(Monster& _monster); // ②
private:
// operator(=)
MonsterStrategyFreedom& operator=(const MonsterStrategyFreedom& _monsterStrategyFreedom);
};
#endif
#include "MonsterStrategyFreedom.h" #include "MonsterStrategy.h" #include "Monster.h" #include//---------------------------------- // mothod //---------------------------------- // constructor MonsterStrategyFreedom::MonsterStrategyFreedom() { // do nothing... } // destructor MonsterStrategyFreedom::~MonsterStrategyFreedom() { // do nothing... } // move void MonsterStrategyFreedom::move(Monster& _monster) { printf("freedom\n"); }
#ifndef _MONSTER_STRATEGY_GANGAN_H_
#define _MONSTER_STRATEGY_GANGAN_H_
#include "MonsterStrategy.h"
class Monster;
class MonsterStrategyGangan : public MonsterStrategy // ①
{
public:
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategyGangan();
// destructor
~MonsterStrategyGangan();
// move
void move(Monster& _monster); // ②
private:
// operator(=)
MonsterStrategyGangan& operator=(const MonsterStrategyGangan& _monsterStrategyGangan);
};
#endif
#include "MonsterStrategyGangan.h" #include "MonsterStrategy.h" #include "Monster.h" #include①MonsterStrategyを継承しています。//---------------------------------- // mothod //---------------------------------- // constructor MonsterStrategyGangan::MonsterStrategyGangan() { // do nothing... } // destructor MonsterStrategyGangan::~MonsterStrategyGangan() { // do nothing... } // move void MonsterStrategyGangan::move(Monster& _monster) { printf("inochi\n"); }
②オーバーライドしたmove()メソッドです。
最後にmain.cppです。
#include "Monster.h" #includevoid main(void) { Monster monster; // モンスター生成 monster.init(); // 初期化 monster.move(); // move monster.setCurrentStrategyType(MonsterStrategy::ST_GANGAN); // 戦略変更 monster.move(); // move printf("hit any key..."); while(getchar() == EOF){} }
以上でStrategyパターンの説明は終わりです。クラス数は少し多いですがそんなに難しいパターンではないはずです。
ソースコードはコピペで動かせるハズですので是非試してみてください。
2010年5月8日土曜日
C++のエラー:error C2360: 'hoge' の初期化が 'case' ラベルによって行われませんでした
今日出たエラーなんですけどswitch文のcase内で変数定義と初期化を同時に行おうとしたらでました。
コードは
解決方法はcaseに{}をつけるだけです。
どうしてダメなのかはよく分りません、C言語の仕様なのかな?
コードは
switch (_type) {
case 1:
const int hoge = 1; // これがダメらしい
break;
}
こんな感じです。昔同じエラーを経験したことがあったのですぐ解決しました。解決方法はcaseに{}をつけるだけです。
switch (_type) {
case 1: { // ←ココ
const int hoge = 1;
break;
} // ←ココ
}
修正するとこんなかんじです。どうしてダメなのかはよく分りません、C言語の仕様なのかな?
2010年5月6日木曜日
テストケースの上げ方について
今日はテストケースのデータを上げる際に気をつけていることを簡単に書きます。
1.数値のゼロ、文字のブランク
これらの値はプログラマが考慮していない場合が多いのでケースに上げています。
2.境界値
有効な範囲の境界となる値です。例えば3~6が有効な値だった場合、
3.意地悪な値
「1.」と同じような考え方ですが、何とかしてバグを見つけてやる、こんな値は考慮してないだろう、どうだー!?っていう値を考えますw。
以上です。(たった3つかよ!何か忘れている気がしなくもないですが・・・
箇条書きにするとたった3つですが、この3つが頭に入っていれば十分な品質が確保出来るんじゃないでしょうか?
1.数値のゼロ、文字のブランク
これらの値はプログラマが考慮していない場合が多いのでケースに上げています。
2.境界値
有効な範囲の境界となる値です。例えば3~6が有効な値だった場合、
- 正常ケースで3と6
- 異常ケースで2と7
3.意地悪な値
「1.」と同じような考え方ですが、何とかしてバグを見つけてやる、こんな値は考慮してないだろう、どうだー!?っていう値を考えますw。
以上です。(たった3つかよ!何か忘れている気がしなくもないですが・・・
箇条書きにするとたった3つですが、この3つが頭に入っていれば十分な品質が確保出来るんじゃないでしょうか?
2010年5月5日水曜日
2010年5月4日火曜日
JavaScriptで「問い合わせ内容を入力してください。」を実装する
タイトルだけだよよく分らないかもしれませんが、
まずはJavaScriptのコードです。
下のテキストボックスにフォーカスがあたると「問い合わせ内容を入力してください」が消えます。
- テキスト入力エリアにあらかじめ「問い合わせ内容を入力してください」の文言を表示しておく。
- テキスト入力エリアにフォーカスがあたる。
- 「問い合わせ内容を入力してください」の文言が消える。
まずはJavaScriptのコードです。
つづいてHTMLのコードです。
下のテキストボックスにフォーカスがあたると「問い合わせ内容を入力してください」が消えます。
2010年5月2日日曜日
2010年5月1日土曜日
C++でenumにtoStringを実装してみる
今日は、C++でenumにtoString()を実装してみたいと思います。
え!?、出来るのかって?クラスでカプセル化するだけですがなにか・・・?
ってことでクラス図です。
状態(State)を管理するenumを適当に宣言してクラスのメンバ変数としてます。
んでもってtoString()メソッドを宣言してあります。
つぎにソースを見てみましょう、用意するのは次のファイルです。
つぎに、EState.cppです。
最後にmain.cppです。
以上ですが、たかがtoString()の為だけにこれだけのコードを書かないと行けないC++ってやっぱり生産性が低いのかな・・・?
え!?、出来るのかって?クラスでカプセル化するだけですがなにか・・・?
ってことでクラス図です。
状態(State)を管理するenumを適当に宣言してクラスのメンバ変数としてます。
んでもってtoString()メソッドを宣言してあります。
つぎにソースを見てみましょう、用意するのは次のファイルです。
- main.cpp
- EState.h
- EState.cpp
#ifndef _E_STATE_H_
#define _E_STATE_H_
enum State { // ①
WAIT_INIT = 0,
IDLE,
PLAY,
PAUSE,
};
class EState {
//----------------------------------
// フィールド
//----------------------------------
private:
State m_state; // 状態
//----------------------------------
// プロパティ
//----------------------------------
private: // ②
// 状態取得
const State getState() const ;
// 状態設定
EState& setState(const State _state);
//----------------------------------
// メソッド
//----------------------------------
public:
// コンストラクタ
EState();
EState(const EState& _state); // ③
EState(const State _state);
// デストラクタ
~EState();
// operator
operator State() const; // ④
EState& operator=(const EState& _state); // ⑤
// toString
const char* toString() const; // ⑥
};
#endif
①enumを宣言しています。②状態のgetter、setterですがインタフェースを減らすためにprivateにしてあります。
③コピーコンストラクタです。④キャストoperatorです。これによりEStateからStateへの代入を可能にしています。後ろにconstが着いているのはconst化された変数からも呼び出せるようにです。
⑤代入operatorです。⑥toString()メソッドです。
つぎに、EState.cppです。
#include "EState.h"
//----------------------------------
// プロパティ
//----------------------------------
// 状態取得
const State EState::getState() const
{
return this->m_state;
}
// 状態設定
EState& EState::setState(const State _state)
{
this->m_state = _state;
return *this;
}
//----------------------------------
// メソッド
//----------------------------------
// コンストラクタ
EState::EState() :
m_state(WAIT_INIT) // ①
{
// do nothing...
}
EState::EState(const EState& _state) :
m_state(WAIT_INIT) // ①
{
*this = _state;
}
EState::EState(const State _state) :
m_state(WAIT_INIT) // ①
{
this->m_state = _state;
}
// デストラクタ
EState::~EState()
{
// do nothing...
}
// operator
EState::operator State() const
{
return this->m_state;
}
EState& EState::operator=(const EState& _state)
{
this->m_state = _state.m_state;
return *this;
}
// toString
const char* EState::toString() const
{
static const char* strArray[] = {
"WAIT_INIT",
"IDLE",
"PLAY",
"PAUSE",
};
return strArray[this->getState()]; // ②
} ①初期化指定子で初期状態を設定しています。②対応する文字列を返却しています。なにげないコードですがデータとロジックを分けることによってバグが少なくメンテナンスが容易になっています。
最後にmain.cppです。
#include①実装したEStateクラスを使用してstateを定義しています。#include "EState.h" void main(void) { const EState state; // ① printf("state:%s\n", state.toString()); // ② const State tempState = state; // ③ printf("hit any key..."); while(getchar() == EOF){} }
②toString()メソッドを呼び出して出力しています。
③キャストoperatorを実装しているのでEState型からState型への代入も可能です。以上ですが、たかがtoString()の為だけにこれだけのコードを書かないと行けないC++ってやっぱり生産性が低いのかな・・・?
登録:
コメント (Atom)



