« 2008年02月 | メイン | 2008年04月 »



2008年03月 アーカイブ

2008年03月04日

ExtJSのフォームウィジェットとサブミットの方法

extjsform2.PNG 以前のエントリにExtJSのサブミットの方法を試行錯誤してやってみたというものがありましたが、完全に的をはずしていたので改めてポストします。
ページからページへ情報を渡すためにフォームタグにテキストエリアとか、ボタンとか色々配置して表現したりしますが、ExtJSのウィジェットでフォームパネル( Ext.form.FormPanel )というものを持っていますので、こいつを使ってみます。 examples\form にサブミット(アクション)のサンプルが無いってのはどうよ?とは思いますが、ちゃんと隅から隅まで見てません。誰かに「あるよー」なんて言われたら恥の上塗りなので、ごちゃごちゃ言わずに説明してみます。
前回説明したのは、リッチテキストのサブミットですが、フィールドをどう表現するのかは xtype で決まっているみたいだと書きました。以下は xtype のリストです。Form components を見ていただくとフォームフィールドとして簡単に表現できるコンポーネントがたくさんあります。頑張れば grid (の中身)もポストできるってのはすごいですよね。エクセルシートみたいなフォームをポスト出来たりしたらウェブのフォームと言うかほとんどデスクトップアプリケーションですね。
xtype            Class
-------------    ------------------
box              Ext.BoxComponent
button           Ext.Button
colorpalette     Ext.ColorPalette
component        Ext.Component
container        Ext.Container
cycle            Ext.CycleButton
dataview         Ext.DataView
datepicker       Ext.DatePicker
editor           Ext.Editor
editorgrid       Ext.grid.EditorGridPanel
grid             Ext.grid.GridPanel
paging           Ext.PagingToolbar
panel            Ext.Panel
progress         Ext.ProgressBar
splitbutton      Ext.SplitButton
tabpanel         Ext.TabPanel
treepanel        Ext.tree.TreePanel
viewport         Ext.ViewPort
window           Ext.Window

Toolbar components
---------------------------------------
toolbar          Ext.Toolbar
tbbutton         Ext.Toolbar.Button
tbfill           Ext.Toolbar.Fill
tbitem           Ext.Toolbar.Item
tbseparator      Ext.Toolbar.Separator
tbspacer         Ext.Toolbar.Spacer
tbsplit          Ext.Toolbar.SplitButton
tbtext           Ext.Toolbar.TextItem

Form components
---------------------------------------
form             Ext.FormPanel
checkbox         Ext.form.Checkbox
combo            Ext.form.ComboBox
datefield        Ext.form.DateField
field            Ext.form.Field
fieldset         Ext.form.FieldSet
hidden           Ext.form.Hidden
htmleditor       Ext.form.HtmlEditor
numberfield      Ext.form.NumberField
radio            Ext.form.Radio
textarea         Ext.form.TextArea
textfield        Ext.form.TextField
timefield        Ext.form.TimeField
trigger          Ext.form.TriggerField
サブミットするときに必要になるのは、送信先の URL と送信するフィールド(名)とボタンになります。(実装に依存します)この3つをソースで見ていきたいと思います。
まず、フォームは Ext.FormPanel で作って、

送信先URLは
url:'hoge.php'で指定してあげます。

フィールド名は
name:'field1'で決まります。ポスト先はこのフィールド名で値をもらうことになります。
PHPだと$_POST[ "field1" ];こんな感じです。

最後にボタンに割り当てるのがハンドラです。以前はアクションを割り当てたらできたよーみたいなことを書きました。もちろんアクションでも出来ますが、非同期で値を渡したい場合は以下のようなハンドラをボタンに割り当てるといいみたいです。
handler:function() {
    myForm.getForm().submit({ 
        success:function( form, action ) {},
        failure:function( form, action ) {}
    });
}
myForm は FormPanel のインスタンスです。 getForm() で BasicForm を返すのでそいつの submit() を使うことになります。このハンドラをボタンに割り当ててあげます。
buttons: [{
    text: '送信', handler:function() {
        myForm.getForm().submit({
            success:function(form, action) {},
            failure:function(form, action) {}
        });
    }
}]
フォームとサブミットのサンプルソースは以下になります。
Ext.onReady( function(){
    var myForm = new Ext.FormPanel({
        url:'hoge.php',
        labelWidth: 75,
        frame:true,
        title: 'テストフォーム',
        bodyStyle:'padding:5px 5px 0',
        width: 350,
        defaults: { width: 230 },

        // デフォルトのフィールドを textfield とします
        defaultType: 'textfield',

        items: [{
                fieldLabel: 'First Name',
                name: 'first',
                allowBlank:true
            },{
                fieldLabel: 'Last Name',
                name: 'last'
            },{
                fieldLabel: 'Company',
                name: 'company'
            },{
                fieldLabel: 'Email',
                name: 'email',
                // vtype:'email'でメールのバリデーションチェックがかかるようです。
                vtype:'email'
            }
        ],

        buttons: [{
            text: '送信',handler:function() {
                myForm.getForm().submit({
                    success:function( form, action ) {
                        // echo print_r($_POST, 1); on hoge.php
                        // ポストしたパラメータと値を見れます。
                        alert( action.response.responseText );
                    },
                    failure:function( form, action ) {
                        // emailのバリデーションチェックで送信できない場合
                        // hostに送信できない場合なんかはこっちにきます
                        alert( action.failureType );
                    }
                });
            }
        }]
    });
    myForm.render( document.body );

});

[ 最近のエントリーとその関連エントリー ]


[ スポンサードリンク ]

2008年03月30日

オーデュボンの祈り 著:伊坂幸太郎を読んだよ!

DSCF2328.jpg 伊坂幸太郎の「オーデュボンの祈り」を読みました。伊坂幸太郎のデビュー作とのことです。伊坂幸太郎はモーニングの巻末でもモダンタイムスってのを連載してますね。こっちは見てないんですけど。

主人公は以前システムエンジニアをやっていた「伊藤」という青年。28歳。舞台は「荻島」という江戸以来外界から遮断された空間です。ここは異世界だよーという舞台装置です。その荻島に佇む、人語を操り、未来が見えるカカシの優午が殺されてから、物語は転がり始めます。

このオーデュボンの祈り。なかなか夢中になりましたよ。ワタシの好きな類の物語です。つまりミステリーだと思うのですが、「これは複線ですよー」と明示的に伏線が張られる。そして、読み手はアタマのフックにそれを何気なく引っ掛けておく。が、その複線が何を示しているのかはもちろん最終章まで引っ張られます。主人公もわからないし、しょっちゅうミスリードする。読み手もあれこれ想像を膨らましたりしてみる。そして、最後の最後に電気がビビッと通電するようにして、あるいはドミノがドダダーと倒れるようにして、絵を描いてくれるわけです。まるで1つのプログラムのようです。
「その絵が、これまでの複線や物語そのものをどれだけ内包できているか」。あるいは「その絵が物語と独立して圧倒的に美しいか」なんてのがワタシのモノサシのひとつなのですが、オーデュボンの祈りは、読後、拍手喝采でしたよ。非常に面白かったです。

グダグダと設定がどうだ、複線がどうだという説明もありますが、とりあえず個性あふれる登場人物にとても惹かれます。えげつないバイオレンス担当の城山。悪意の塊の警察官です。サイテー。未来の見えるカカシの優午。未来が見えるくせに頼りないし、殺される。未来見えるんじゃないの?奥さんが殺されて頭がおかしくなっちゃった絵描きの園山。非常に切ないです。奥さんが殺されてから嘘しか言えなくなっちゃったんです。ほかにも個性的な登場人物はわんさといます。
サーカスのピエロがボールの上でバランスをとりながら前へ進んだり後ろへ下がったりと滑稽に演じますが、登場人物みんなでくんづほぐれつしながら、いっぺんにそのボールに乗っかっているかのようです。乱暴に言ってしまうとそんな物語。はまると1日で読めちゃいます。オススメですよ

[ 最近のエントリーとその関連エントリー ]


2008年03月27日

China WAS,IS,and ALWAYS WILL BE

この動画はkarate styleさんのとこで見つけたエントリなのですが、中国側から見たチベットについて、とあるカナダ系の中国人がyoutubeにポストしていたようです。(和訳はkarate styleさんのとこにあります。是非読んでいただきたいと思います。)

こんな針がミエミエの餌には釣られないクマー!とありたいものですが、この人、ずいぶんと悪意を練って動画作ってポストしたもんだなと思いました。正直ワタシ、憤りすぎてしんどかったです。どうしよう。このことについて今日は冷静にポストできなさそうなので、一晩か二晩寝かそうと思います。

"Tibet WAS,IS,and ALWAYS WILL BE a part of China"

[ 最近のエントリーとその関連エントリー ]


2008年03月24日

B型 自分の説明書 著:Jamais Jamais

DSCF2327.jpg 実は、ワタシB型なんです。
と、これを読んだところでブラウザを閉じちゃったり、mojalogにはもうこないようにお気に入りから削除したりフィードビューアからも削除しちゃったり挙句の果てにはアタシのブラウザのキャッシュからも消えてなくなってほしいと思われるほど嫌われているB型ですこんにちは(挨拶)
というわけで、「B型 自分の説明書 著:Jamais Jamais」を(少し前に)買いました。なぜか。なぜ買ったのか。といいますと冒頭部分を立ち読みしてみましたところ、
B型は自分の説明ができない。へたである。うまく伝わらない相手には説明すらしたくない
とあり、そのとおりだ!と思い1000円払って買ってきました。自分をどうやって説明するか?についてはホトホト困り果てておりまして、胃に穴があく程どうしたものかと考えあぐねいている毎日でした。ウソです。まぁそれでも自分の説明下手には困っていたのは事実です。
"説明書"とある以上、B型について説明がだらだらと書いてあるのかと思いきや、そうではなく、B型なら当てはまるであろうチェックボックスの羅列で成り立っています。ちなみにワタシは95%以上当てはまりました。ぎゃははは。こりゃいいや。1000円払ってこの本買ってくれればワタシの下手な説明で自己紹介する必要ないからね☆(どうりで嫌われるわけです)
ともあれ、まぁ読み物としてはそれなりに面白いです。子気味がいいとかトンチが利いてるとかそういったレベルで面白いです。例を挙げると、

夢を追いかけている人が好き
けどその夢の熱い語りはいらない

とかそういった内容です。ちなみにワタシ、両方チェックが入ります。B型じゃなくとも入るかと思いますが、諸手をあげてわかるわかる!といった感じです。
ということで、自分を説明するために買ってみて、確かに説明書足り得る内容でした。職場のB型の同僚や上司部下とソリが会わない人は買ってみてはいかがでしょうか。もっとソリが合わなくなるかと思います。

でもよくよく考えてみると、べつに誰かにワタシのことが知りたいと言われているわけでもないのに、自分の説明が下手だと嘆いていることに気がつきました。恥ずかしくてしょうがないので誰かタオル投げてください。(股間に向かって)

[ 最近のエントリーとその関連エントリー ]


2008年03月22日

肉まんを皮からつくったよ。

DSCF2316.jpg 昨日の予告どおり、今日は朝っぱらから肉まん作ってみました。このまえはギョーザの皮を作ったのでその続きです。肉まんやギョーザは皮から作ると手が込んだもののように思えますが、自分で作りはじめると夢中になって、嫌なことを忘れることができるのでワタシにとっては必要な没頭タイムです。食の安全に脊髄反射しているわけではありません。あ。でも食材が中国産かどうかは見るようになったし、そうだったら買わないけど。
で、食材。薄力粉って1kg100円ちょっとで買えるんですが、実際にこいつをこねて作ってみると、粉から作る食べ物は単価やっすいなーと思いました。どおりで一ヶ月1万円生活で、いろんなタレントさんが薄力粉を購入するわけですね。

DSCF2317.jpg というわけで肉まんですが、皮の材料は
・薄力粉200g
・お湯100cc+20cc
・砂糖15g
・塩少々
・ベーキングパウダー6g
です。これで、8個くらいは作れます。お湯にベーキングパウダーを入れてあとはただひたすら混ぜていきます。100ccで混ぜていくと多分ぼそぼそとした感じになるので、さらにすこーしずつ水を足していきます。ので20ccは混ぜながらやわらかくしていくために残しておいたほうがいいかもしれません。やわらかさは、写真を見て判断してください。結構やわこいです。
DSCF2318.jpg 具は何でもいいと思うのですが、今日作ったのは冷蔵庫にあった使えそうなものを入れたので、
・豚挽き肉
・にんじん
・ナス
・ニラ
・ネギ
・にんにく
ダンボール
を適当にいためて使いました。ニラとネギは炒めた後に入れて具にすると香りだかいです。というか、香ばしすぎになりました。あははー。食べてみたらおいしかったんですが、しいたけ、たけのこ、キャベツくらいは入れたほうがおいしくなりそうでしたよ
DSCF2325.jpg ということで、できあがりです。ニラとネギを炒めない感じで具を作るのがポイントです。勝手にオレ風にくまんのポイントを語ってみました。みんな飲み会とかで言ってみるといいと思う。



「オレの肉まんの具はさぁ、ニラとネギは炒めてないから。蒸かすだけ。マジ。」



っていうところに話を持ってくのが難しいし、そんなことを誰かに言われても、ワタシ、「ふーん」て答えると思う。あははー。「先聞くの、めんどくさそーな蘊蓄ですねー☆」とか。あははー。

[ 最近のエントリーとその関連エントリー ]


2008年03月21日

SharePointとExtJSでSharePointグループを一覧で表現してみたよ

sharePointGroup.PNG 任意のサイトのSharePointグループを引っこ抜いてリスト表示して、クリップボードにも挿入しちゃうスクリプトを組みました。ExtJSで表現する上ではサイトヒエラルキーと、所属するグループをExt.treeで表現するのがいいかなと思いましたが、gridで表現しました。そのうちtreeでもポストしたいと思います。

表現はさておきSharePointのほうの解説をします。
  1. SiteData.asmxのGetSiteでサイトURLを引っ張ってきます。
  2. GetSiteで引っ張ってきたサイトヒエラルキーのUserGroup.asmxでGetGroupCollectionFromWebを使います。これでそのサイトのグループ一覧を得ます。
  3. 最後に2.で引っ張ったグループUserGroup.asmxのGetUserCollectionFromGroupに与えて所属するユーザを引っ張ります。
  4. ExtJSのgridでレンダリングするという流れです。
ここんとこ技術のエントリばっかりだったので、明日は手作り肉まんを作る予定なのでそれをポストします。皮からこねちゃうよー。こねー!(ビールで酔ってます)
<link rel="stylesheet" type="text/css" href="<yourSitePath>/ext/resources/css/ext-all.css" />
<script type="text/javascript" src="<yourSitePath>/ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="<yourSitePath>/ext/ext-all.js"></script>
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push( "getSiteUrlList" );
function getHttpReq(){
    return window.XMLHttpRequest ? new XMLHttpRequest() : ( function() {
        try        { return new ActiveXObject( "Msxml2.XMLHTTP" );    }
        catch( e ) { return new ActiveXObject( "Microsoft.XMLHTTP" ); }
    }());
}

function getSiteUrlList() {
    var httpInst = getHttpReq();
    var renderItem = '';
    httpInst.open( "POST", "/_vti_bin/SiteData.asmx", false );
    httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
    httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetSite' );
    var postBody = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetSite xmlns="http://schemas.microsoft.com/sharepoint/soap/" /></soap:Body></soap:Envelope>';

    httpInst.onreadystatechange = function () 
    {
        if ( httpInst.readyState == 4 ){
            var xmlData  = httpInst.responseXML;
            var urlList  = xmlData.getElementsByTagName( "Url" );
            var listSize = urlList.length;
            var tempStr  = '';
            for( idx = 0; idx < listSize; idx++ ){
                tempStr = tempStr + '<option value="' + urlList[ idx ].childNodes[ 0 ].nodeValue + '">' + urlList[ idx ].childNodes[ 0 ].nodeValue + '</option>';
            }
            renderItem =  '<select id="choseSite" onchange="getSiteGroup()"><option value="">▼サイトを選んでください</option>' + tempStr + '</select>';
        }
    }
    httpInst.send( postBody );
    document.getElementById( 'siteUrlList' ).innerHTML = renderItem;
}

function getSiteGroup() {

    if( document.getElementById( 'choseSite' ).value == "" ){
        document.getElementById( 'groupList' ).innerHTML = "";
        exit();
    }
    var httpInst = getHttpReq();
    var renderItem = "";

    httpInst.open( "POST", document.getElementById( 'choseSite' ).value + "/_vti_bin/UserGroup.asmx", false );
    httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
    httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/directory/GetGroupCollectionFromWeb' );
    var postBody = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetGroupCollectionFromWeb xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" /></soap:Body></soap:Envelope>';

    httpInst.onreadystatechange = function() 
    {
        if ( httpInst.readyState == 4 ){

            xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
            xmlDoc.async = false;
            xmlDoc.loadXML( httpInst.responseText );
            rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetGroupCollectionFromWebResponse/GetGroupCollectionFromWebResult/GetGroupCollectionFromWeb/Groups/Group' );
            var tempStr = "";
            for( idx = 0; idx < rowsItem.length; idx++ ){
                tempStr = tempStr + '<option value="' + rowsItem[ idx ].getAttribute( "Name" ) + '">' + rowsItem[ idx ].getAttribute( "Name" ) + '</option>';
            }
            renderItem = '<select id="choseGroup" onchange="getGroupUser()"><option value="">▼グループを選んでください</option>' + tempStr + '</select>';
        }
    }

    httpInst.send( postBody );
    document.getElementById( 'groupList' ).innerHTML = renderItem;
}


function getGroupUser() {

    document.getElementById( 'groupUserList' ).innerHTML = "";
    if( document.getElementById( 'choseGroup' ).value == "" ){
        document.getElementById( 'groupUserList' ).innerHTML = "";
        return;
    }
    var httpInst = getHttpReq();
    var renderItem = document.getElementById( 'choseGroup' ).value;
    var dataAry = new Array();
    httpInst.open( "POST", document.getElementById( 'choseSite' ).value + "/_vti_bin/UserGroup.asmx", false );
    httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
    httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/directory/GetUserCollectionFromGroup' );
    var postBody = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetUserCollectionFromGroup xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"><groupName>' + renderItem + '</groupName></GetUserCollectionFromGroup></soap:Body></soap:Envelope>';

    httpInst.onreadystatechange = function() 
    {
        if ( httpInst.readyState == 4 ){

            xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
            xmlDoc.async = false;
            xmlDoc.loadXML( httpInst.responseText );
            rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetUserCollectionFromGroupResponse/GetUserCollectionFromGroupResult/GetUserCollectionFromGroup/Users/User' );
            var copytext = renderItem + "\n名前\tメール\tアカウント\n";
            for( idx = 0; idx < rowsItem.length; idx++ ){
                var fieldDataList = new Array();
                var nameValue = "";
                var emailValue = "";
                var loginNameValue = "";
                
                fieldDataList.push( ( nameValue = rowsItem[ idx ].getAttribute( "Name" ) ) );
                fieldDataList.push( ( emailValue = rowsItem[ idx ].getAttribute( "Email" ) ) );
                fieldDataList.push( ( loginNameValue = rowsItem[ idx ].getAttribute( "LoginName" ) ) );
                dataAry.push( fieldDataList );
                copytext = copytext + nameValue + "\t"+ emailValue + "\t" + loginNameValue + "\n";
            }

            document.getElementById( 'cparea' ).value = copytext;

            Ext.onReady( function(){
                var reader = new Ext.data.ArrayReader( {}, [ 
                    { name: "Name" },
                    { name: "Email" },
                    { name: "LoginName" }
                ]);
                var store = new Ext.data.Store({
                    reader: reader,
                    data: dataAry
                });

                var grid = new Ext.grid.GridPanel({
                    store: store,
                    columns: [
                        { header: "名前", width: 120, sortable: true, dataIndex: "Name" },
                        { header: "メール", width: 240, sortable: true, dataIndex: "Email" },
                        { header: "アカウント", width: 180, sortable: true, dataIndex: "LoginName" } 
                    ],
                    width: 600,
                    height: 400,
                    stripeRows: true,
                    title:renderItem,
                    viewConfig: { forceFit:true },
                    frame:true,
                    collapsible: true,
                    animCollapse: true
                });
                grid.render( 'groupUserList' );
                grid.getSelectionModel().selectFirstRow();
            });
        }
    }
    httpInst.send( postBody );
}
function CopyText( arg ){ 
    var obj = document.all && document.all( arg ) || document.getElementById && document.getElementById( arg ); 
    if ( obj.value ) { 
        var doc = document.body.createTextRange();
        doc.moveToElementText( obj ); 
        doc.execCommand( "copy" ); 
        alert( 'クリップボードにコピーしました。' );
    } else { 
        alert( 'コピーするデータがありません。' );
    } 
}

</script>
<table><tr><td>サイトURLを選んでください</td><td>
<div id="siteUrlList"><img src="<yourSitePath>/ext/resources/images/default/shared/blue-loading.gif">loading...</div></td></tr>
<tr><td>サイトに属するグループを選んでください</td><td>
<div id="groupList"><select><option value="">▼グループを選んでください</option></select></div></td></tr>
<tr><td>出力ユーザをコピーします。</td><td><input type="button" name="Copy" value="コピー" onClick='CopyText("cparea")'></td></tr>
</table>
<div id="groupUserList"></div>
<textarea style="display:none" name="cparea"></textarea>

[ 最近のエントリーとその関連エントリー ]


2008年03月17日

SharePointのライブラリをExtJSのgridウィジェットで表現してみました

sharePointWithExtJS.PNG SharePoint(moss2007)ネタが続きます。SharePointといえば、ほぼノンコーディングで何でもできますよーといったMSのグループウェアで、その柔軟性もものすごいものです。ですが、どれだけノンコーディングで色々できるといっても、カスタマイズしなければならない要求はいくらでも出てきます。でてくることは問題ないのですが、
  • どうやって
  • どこに
  • 安全に
カスタマイズする方法を考え始めるといろいろと難しい問題があります。その割には、SharePointではそういった「裏側からこうやったら」色々いじくれるよーといったエントリはまだまだ少ない気もします。ググってみてもほしい情報はなかなか転がっていません。
が、つい最近のことなのですが、山崎 愛さんのSharePoint Technical Noteを発見してから結構お世話になっております。SharePointの開発をやる方にはお勧めのエントリがたくさんありますよ。

今日は、SharePoint Desinger 2007 を使用した ASP.NET コントロールとデータビューの連携というエントリをみて、影響を受けまして、
  • 任意の
  • 複数のライブラリを
  • 同じページに
  • 非同期で
表示させる方法をポストしたいと思います。
これを実装すると上記のスクリーンショットのようになるのですが、静的なHTMLに書いてドキュメントライブラリに放り込んでもよいですし、リンク先のSharePointTechnicalNoteさんにも記述があります、SharePointデザイナから[ファイル]メニューから[新規作成]-[マスタページから作成]で作成したaspxに埋め込むと、見栄えがよいです。

使ったのは、2つのウェブサービスと、ExtJSのgridウィジェットです。このウィジェットは高速でかなり強力ですので、SharePointで持っているビューを時として凌ぐ使いやすさがあります。
スクリプトは以下のタグの直後に差し込んで使ってみてください。HTMLで書く場合はどのように表現してもOKです。
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
ExtJSは以下のスクリプトのソースに合わせて任意のドキュメントライブラリに格納してください。

それでは簡単にソースを解説します。
まず、ライブラリ名をフォームから取得してLists.asmxのGetListウェブサービスに渡します。このウェブサービスで取得するのはリスト・ドキュメントライブラリのフィールド名です。
フィールド名はDisplayNameと、StaticNameというアトリビュートで、返ってきたXMLに入ってきます。DisplayNameはそのまま表示されるフィールド名ですが、StaticNameは裏で持っているフィールド名を一意にするidといったところでしょうか。この取得したフィールド名を次のウェブサービスに投げて実際のアイテムを刈り取っていくという作業です。
実際のアイテム取得は以前のエントリでも触れたLists.asmxのGetListItemsです。詳しくはそちらを参照していただければと思いますが、GetListで取得したStaticNameに準じてライブラリのフィールドを制御しています。ですので、基本的にはライブラリやフィールドに依存しないつくりになっています。
ExtJSのgirdはjavascriptのArrayでも表現することができます。gridで表示される値は、属性(type:日付や数値など)も考慮されていますが、今回は属性を意識したつくりにはしていません。というわけで、スクリプトを以下に記します。
<link rel="stylesheet" type="text/css" href="http://<yourSitePath>/ext/resources/css/ext-all.css" />
<script type="text/javascript" src="http://<yourSitePath>/ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://<yourSitePath>/ext/ext-all.js"></script>
<script type="text/javascript">
// onloadでレンダリングさせたい場合
// _spBodyOnLoadFunctionNames.push( "getList" );
var httpInst = window.XMLHttpRequest ? new XMLHttpRequest() : ( function() {
    try        { return new ActiveXObject( "Msxml2.XMLHTTP" );    }
    catch( e ) { return new ActiveXObject( "Microsoft.XMLHTTP" ); }
})();

function getList() 
{
    var listGuid = "";
    if( ( listGuid = document.getElementById( "listguid" ).value ) == "" ){
        return;
    }

    httpInst.open( "POST", "http://<yourSitePath>/_vti_bin/Lists.asmx", false );
    httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
    httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetList' );
    var postBody = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetList xmlns="http://schemas.microsoft.com/sharepoint/soap/"><listName>' + listGuid + '</listName></GetList></soap:Body></soap:Envelope>';

    httpInst.onreadystatechange = function()
    {
        if ( httpInst.readyState == 4 ){
            xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
            xmlDoc.async = false;
            xmlDoc.loadXML( httpInst.responseText );
            listInfo = xmlDoc.selectSingleNode( '/soap:Envelope/soap:Body/GetListResponse/GetListResult/List' );
            var urlLink = listInfo.getAttribute( "DefaultViewUrl" );
            urlLink = urlLink.replace( "AllItems.aspx", "" );
            var libTitle = listInfo.getAttribute( "Title" );

            rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetListResponse/GetListResult/List/Fields/Field' );

            var xmlStaticNm = new Array();
            var xmlDispNm = new Array();
            for( idx = 0; idx < rowsItem.length; idx++ ){
                if( rowsItem[ idx ].getAttribute( "Hidden" ) == null &&
                    rowsItem[ idx ].getAttribute( "StaticName" ) != "LinkTitleNoMenu" &&
                    rowsItem[ idx ].getAttribute( "StaticName" ) != "LinkTitle" )
                {
                    xmlStaticNm.push( rowsItem[ idx ].getAttribute( "StaticName" ));
                    xmlDispNm.push( rowsItem[ idx ].getAttribute( "DisplayName" ));
                }
            }
            getListItems( listGuid, xmlStaticNm, xmlDispNm, urlLink, libTitle );
        }
    }
    httpInst.send( postBody );
}

function getListItems( listGuid, xmlStaticNm, xmlDispNm, urlLink, libTitle )
{
    var fieldRefData = '';
    var dataAry = new Array();
    var headAry = new Array();
    var clmnAry = new Array();

    for( idx = 0; idx < xmlStaticNm.length; idx++ ){
        fieldRefData = fieldRefData + '<FieldRef Name="' + xmlStaticNm[ idx ] + '" />';
        headAry.push( { name: xmlStaticNm[ idx ] } );
        clmnAry.push( { header: xmlDispNm[ idx ], width: 90, sortable: true, dataIndex: xmlStaticNm[ idx ] } );
    }
    httpInst.open( "POST", "http://<yourSitePath>/_vti_bin/Lists.asmx", false );
    httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
    httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetListItems' );
    var postBody = '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body><GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">' + 
    '<listName>' + listGuid + '</listName>' + 
    '<viewName></viewName>' + 
    '<query><Query><Where><Gt><FieldRef Name="ID" /><Value Type="Counter">0</Value></Gt></Where></Query></query>' + 
    '<viewFields><ViewFields>' + fieldRefData + '</ViewFields></viewFields>' + 
    '<rowLimit>100</rowLimit>' + 
    '<queryOptions><QueryOptions/></queryOptions>' + 
    '<webID></webID>' + 
    '</GetListItems></soap12:Body></soap12:Envelope>';

    httpInst.onreadystatechange = function()
    {
        if ( httpInst.readyState == 4 ){
            xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
            xmlDoc.async = false;
            xmlDoc.loadXML( httpInst.responseText );

            rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/listitems/rs:data/z:row' );

            for( idx = 0; idx < rowsItem.length; idx++ ){
                var fieldDataList = new Array();
                for( sdx = 0; sdx < xmlStaticNm.length; sdx++ ){
                    var curItem = rowsItem[ idx ].getAttribute( "ows_" + xmlStaticNm[ sdx ] );
                    curItem = ( xmlStaticNm[ sdx ] == "ID" ) 
                        ? '<a href="' + urlLink + 'DispForm.aspx?ID=' + curItem + '">' + curItem + '</a>'
                        : rowsItem[ idx ].getAttribute( "ows_" + xmlStaticNm[ sdx ] );
                    fieldDataList.push( curItem );
                }
                dataAry.push( fieldDataList );
            }

            Ext.onReady( function(){

                var reader = new Ext.data.ArrayReader( {}, headAry );
                var store = new Ext.data.Store({
                    reader: reader,
                    data: dataAry
                });

                var grid = new Ext.grid.GridPanel({
                    store: store,
                    columns: clmnAry,
                    width: 540,
                    height: 200,
                    stripeRows: true,
                    title: libTitle
                });

                grid.render( 'grid-example' );
                grid.getSelectionModel().selectFirstRow();

            });
        }
    }
    httpInst.send( postBody );
}
</script>
<input type="text" id="listguid" /><input type="button" value="参照リストの追加" onclick="getList()">
<div id="grid-example"></div>

[ 最近のエントリーとその関連エントリー ]


2008年03月16日

つくろう!逆転裁判でガチで吹いたスレタイ集つくったよ!

逆転裁判は一時期かなり嵌ったのですが、この「つくろう!逆転裁判」にあてはめるネタは何が面白いかなーと思って、とりあえずガチで吹いたスレタイ集を使ってみました。最後は結構カオスです。あはは。
via : つくろう!逆転裁判

[ 最近のエントリーとその関連エントリー ]


2008年03月14日

やる夫がデザインパターンをやるようです 第6回

≪第5回第7回≫

ヒントなんて中途半端なこと言わずに答えそのものを聞けばよかったお。。。
  ::::::::  ::    ::     :::::  ::  :::
  ::::::  ::   ____   :::::  ::::  :::
  ::::::  :::: /  :::  \ :::   :::   ::
  ::::  ::::/   ::     \::  :::  ::
 ::::  /:::    ─    ─ \ ::  ::
 :::  |  ::   .(○)  (○)  | :  ::::
  :::   \     (__人__)  ,/ :  :::
  ::  ノ      ` ⌒´   \ :   :::
  /´               ヽ  :::
 |    l              \:::
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))






     いっそのこと、こんな会社潰してしまえばいいお。
         ___
       /::::::::::::::::\
      /:::::─三三─\ 
    /:::::::::(○)三(○).\
/⌒)⌒)⌒.:::::::::: (__人__) :::::: \   /⌒)⌒)⌒)
| / / /..    ` ⌒´    | (⌒)/ / / /,,-''ヽ、
| :::::::::::(⌒)          /  ゝ ::::::.,,-''"    \
|     ノ           \  /_,-'"        \
ヽ    /             ヽ /\           \
 |    |        __   //\\           \
             /|[]::::::|_ / \/\\         /
           ./| ̄ ̄ ̄ ̄ //\ \/  \      //    ___
         |  |:::「「「「「「 / \/\  /\\   /:::/   ./| 
       _..|  |:::LLLLL//\ \/  \/\\/::::::/  /  | ロ  .|l
      / llllll|  |:::「「「「 / \/\  /\ .\/ ./::::::::/  / ./ .
__     llllll|  |:::LLL.//\ \/  \/\  /::::::::/   | /  .| ロ
          |  |:::「./ .\/\  /\ \/ /::::::::/⌒ヽ、| ||/ ..|
          |  |:::l//\ \/  \/\_, -― 、  ''"⌒ヽ,_
                (⌒ヽ、_,ノ⌒Y"    Y     .....⌒)
            (⌒ヽー゙ ....::(   ..::.......  .__人.....::::::::








    /_ノ   ヽ_\  でも今まで働いた分がもったいないから
   /( ●) ( ●)\ 次のボーナスもらってから潰すことにするお。
 / ::::::⌒(__人__)⌒:::::\
 |        ̄      |
 \              / 






          とりあえず今日はアーキテクトに言われたとおり
          java.ioをみてみるお
           ____ 
        /⌒  ⌒\ 
.      /( ●)  (●)\ 
     / ::::::⌒(__人__)⌒::::: \ 
    |      |r┬-|     |  
     \       `ー'´     / 
    ノ            \ 
  /´               ヽ                 カ 
 |    l   l||l 从人 l||l      l||l 从人 l||l   カ    タ 
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.     タ 
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒)) 
     ┌┬┬┐┌┬┬┬┐┌┬┬┬┐┌┬┬┬┐ 
  ,. - ''"| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ρ ̄`l 
   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ノ ̄ 
やる夫が見つけてきたのはjavaのファイル出力の基本的なソースでした。
Writer bw = new BufferedWriter(
の部分を
BufferedWriter bw = new BufferedWriter(
と書いていないだけ、少しは何かをつかんでいるのかもしれません。
import java.io.*;

public class HelloWorldFileWriter {
    public static void main( String[] args ) {
        try {
            Writer bw = new BufferedWriter( 
                            new OutputStreamWriter( 
                                new FileOutputStream( "yaruo.txt" ) ) );
            String msg = "やる夫で学ぶデザインパターン";
            bw.write( msg );
            bw.close();
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }
}
<やる夫>
バッファードライターが使いやすいから使いたいだけなのに、
インスタンスの生成までに世話が焼けるクラスだお。。。
         ____
       /      \
      /  ─    ─\
    /    (●)  (●) \
    |       (__人__)    | ________
     \      ` ⌒´   ,/ .| |          |
    ノ           \ | |          |
  /´                 | |          |
 |    l                | |          |
 ヽ    -一ー_~、⌒)^),-、   | |_________|
  ヽ ____,ノγ⌒ヽ)ニニ- ̄   | |  | 



<アーキテクト>
お前の書いたソースをみると、
Writer bw = new BufferedWriter( new FileWriter( "yaruo.txt" ) );
でもいいわけだが、まぁいい例を持ってきたな。
お前のやってるその行為はまさに「拡張」と言えるんじゃないのか?
javadocにも、「FileWriter や OutputStreamWriter のような Writer から直接 write() オペレーションを呼び出すのは効率が悪いので、BufferedWriter でラップすることをお勧めします」とあるだろう
        / ̄ ̄\
      /       \ 
      |::::::        | 
     . |:::::::::::     | 
       |::::::::::::::    |          ....,:::´, .
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´ 




             ____ 
           /      \ 
          / ─    ─ \    いや、まったく
        /   (●)  (●)  \ そんなつもりはないですお
        |      (__人__)     | 
         \     ` ⌒´    ,/ 
 r、     r、/          ヘ 
 ヽヾ 三 |:l1             ヽ 
  \>ヽ/ |` }            | | 
   ヘ lノ `'ソ             | | 
    /´  /             |. | 
    \. ィ                |  | 
        |                |  |  




   / ̄ ̄\  ( ;;;;( 
 / _ノ  ヽ\ ) ;;;;) 
 |  ( ○) (○)/;;/   
. |   (__人__) l;;,    
  |    ∩ ノ)━・'/   
.  |   /  ノ´ } そこは肯定しとかないとはなしがすすまんだろ
.  ヽ  / /    }   常識的に考えて・・・ 
   ヽ/ /   ノ 
それでは、上記を踏まえて話をニコニコクロニクルの武器クラスに戻して考えて見ます。まず、
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
で装備する武器を表現します。さらに強化アイテムを手に入れてみます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();

// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );
ほかのアイテムでさらに強化してみます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();

// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );

// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
両腕に腕輪をはめることだってできます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();

// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );

// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );

// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );

// 勇者のアイテム こん棒  指輪  腕輪  腕輪 攻撃力 18
System.out.println( "勇者のアイテム" + wpInst.getDescription() + "攻撃力" + wpInst.getPower() );

/*

// 勇者はこん棒に指輪に腕輪を2つ手に入れた!こん棒が強化された!
Weapon wpInst = new Bracelet( new Bracelet( new Ring( new Club() ) ) );

*/
decoratorDsgnPtn.PNG 見ると、武器クラスを強化アイテムでラップしていることがわかります。図にすると右記のようになるのですが、まず、外側のBraceletからgetPower()を呼んで、ネストしたBraceletに処理を委譲しgetPower()を呼びます。こん棒までたどり着いて最終的に返ってきたgetPowerは(加算されるものとして)武器が強化されたということを表現できるわけです。

このようなクラスの装飾をデコレータパターンと言います。
  • デコレータは、装飾するインスタンス(ここでは武器クラスですね)と同じスーパータイプ(Weapon)を持ちます。
  • 複数の(同じデコレータクラスでも)デコレータを使用してインスタンスをラップすることができます。(アーキテクトの心配はなくなりました)
  • デコレータは装飾するインスタンスに処理を委譲する前後どちらか、または前後両方で独自の振舞いを追加して委譲することができます。
Decoratorパターンの定義はまたまた腹に落ちてこない文言なのですが、
Decoratorパターンはオブジェクトに付加的な振舞いを動的に与えます。デコレータはサブクラス化の代替となる、柔軟な機能拡張手段を提供します。(硬直した継承の爆発ではない方法で、柔軟な機能拡張ができます)
<アーキテクト>
          そういうことだから
          武器クラスをデザインしなおしてみろ
                 __ 
                /   \ 
              /ノ   ヽ_\
             | (●) (●)| 
              |  (__人__)  .|  
              l  ` ⌒´  | 
              {         |    
               {       /    
          ,-、   ヽ     ノ、   
         / ノ/ ̄/ ` ー ─ '/ ヽ, 
        /  L_         _( { r-、 ヽ 
           _,,二)     〔― ‐}     | 
           >_,フ      }二 コ\   Li 








<やる夫>
          ____         _ _ _ _ _ _ _ _ _ _ _ 
       /_ノ  ヽ、_\      ( 説明されてもよくわかんないから
.     / (● ) (● )\   ( あまえて誤魔化してみるお。。。
    ///////(__人__)///\   ◯  
    |              | 。O  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄ 
     \           / 
    ノ            \ 
  /´               ヽ 
 |    l              \ 
 ヽ    -一'''''' 








          またまたー。あと500回は同じ説明を
          してもらわないと理解できるような内容じゃないお!
   / ̄ ̄\           ___ 
 /   /  \        /⌒  ⌒\ 
 |    ( ○)(○)  プニ   (● )  (● ) \ 
. |     (__人_(ニ~`ヽ、 /:::⌒(__人__)⌒::::: \ 
  |     ` ⌒´(((_⊂>ヽ|     |r┬-|      | 
.  |         }    \ \   `ー'´      / 
.  ヽ        }      ゝ-|          ヽ 
   ヽ     ノ        \        ヽ   \






     ____
    / ⌒  ⌒  \  チラッ
  ./( ―) ( ●)  \ 
  /::⌒(_人_)⌒:::::  | これは政治なのだお。。。
  |    ー       .| フヒヒ
  \          / 






        / ̄ ̄\   (こいつに付き合ってると
      /       \  俺の心が先に折れてしまいそうだ)
      |::::::        | 
     . |:::::::::::     | 
       |::::::::::::::    |          ....,:::´, .
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´ 
というわけで、デコレータパターンのサンプルソースを以下に記しておきたいと思います。
import java.io.*;

public class HelloWorldFileWriter {
    public static void main( String[] args ) {
        // 勇者はこん棒を手に入れた!
        Weapon wpInst = new Club();

        // 勇者は指輪を手に入れた!こん棒が強化された!
        wpInst = new Ring( wpInst );

        // 勇者は腕輪を手に入れた!こん棒が強化された!
        wpInst = new Bracelet( wpInst );

        // 勇者は腕輪を手に入れた!こん棒が強化された!
        wpInst = new Bracelet( wpInst );

        // 勇者のアイテム こん棒  指輪  腕輪  腕輪 攻撃力 18
        System.out.println( "勇者のアイテム" + wpInst.getDescription() + " 攻撃力 " + wpInst.getPower() );
    }
}


abstract class Weapon {
    String description = "";
    public String getDescription(){
        return description;
    }
    public abstract int getPower();

}

// デコレータ抽象クラス
abstract class YaruoDecorator extends Weapon {
    public abstract String getDescription();
}

// 具象コンポーネント(装飾される側)
class Club extends Weapon {
    public Club(){
        description = " こん棒 ";
    }
    public int getPower(){
        return 10;
    }
}

// デコレータクラス指輪
class Ring extends YaruoDecorator {
    Weapon mWeaponInst;
    
    public Ring( Weapon inst ){
        this.mWeaponInst = inst;
    }
    public String getDescription(){
        return mWeaponInst.getDescription() + " 指輪 ";
    }
    public int getPower(){
        return 2 + mWeaponInst.getPower();
    }
}

// デコレータクラス腕輪
class Bracelet extends YaruoDecorator {
    Weapon mWeaponInst;
    
    public Bracelet( Weapon inst ){
        this.mWeaponInst = inst;
    }
    public String getDescription(){
        return mWeaponInst.getDescription() + " 腕輪 ";
    }
    public int getPower(){
        return 3 + mWeaponInst.getPower();
    }
}
≪第5回第7回≫


[ 最近のエントリーとその関連エントリー ]


2008年03月12日

やる夫がデザインパターンをやるようです 第5回

≪第4回第6回≫

前回のやる夫で学ぶデザインパターンでは、勇者が冒険の中で獲得する、「武器」による攻撃力の強化だけでなく、アクセサリの追加装備により攻撃力のさらなる強化を実現するための追加仕様を、やる夫が検討しました。

検討その1.継承を爆発させた。
検討その2.必要最低限な「武器」クラスを用意して、「強化アイテム」をスーパークラスのメンバ変数で表現。

やる夫が見直した検討その2.のデザインは、武器クラスの拡張には柔軟に対応できますが、強化アイテムの追加や削除、変更が入った場合に柔軟に対応することができません。
class Weapon {
    String description;
    
    // 強化アイテムのブール値
    boolean isBracelet;
    boolean isMantle;
    boolean isHairOrnament;
    boolean isRing;

    getDescription();
    getPower();

    hasBracelet();
    setBracelet();

    hasMantle();
    setMantle();

    hasHairOrnament();
    setHairOrnament();

    hasRing();
    setRing();
}
前回、アーキテクトが気にしていたのは、「同じアイテムを2つ持った場合、その分の武器の強化をどのように実現するか?」ですが、上記のデザインを見ると、強化アイテム1つ1つをメンバに割り当てているのでアイテムが増えたり、強化値が変更される度にこのクラスを検討しなおす必要があります。
・・・「同じ強化アイテムを2つ以上重ねがけできる」仕様はどうすんだ?
          ____
       / \  /\  キリッ
.     / (ー)  (ー)\
    /   ⌒(__人__)⌒ \
    |      |r┬-|    |
     \     `ー'´   /
    ノ            \
  /´               ヽ
 |    l              \
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))

          ____
        /_ノ  ヽ、_\ だっておwwwww
 ミ ミ ミ  o゚((●)) ((●))゚o      ミ ミ ミ
/⌒)⌒)⌒. ::::::⌒(__人__)⌒:::\   /⌒)⌒)⌒)
| / / /     |r┬-|    | (⌒)/ / / //
| :::::::::::(⌒)    | |  |   /  ゝ  :::::::::::/
|     ノ     | |  |   \  /  )  /
ヽ    /     `ー'´      ヽ /    /
 |    |   l||l 从人 l||l      l||l 从人 l||l
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))


     |  |   |   |
     _||_||__||  ||
    (__/   `ー――
   (___/  r
    (_レノ)\   ___
    (__/__/

       ____
     /⌒  ⌒\ ホジホジ
   /( ○)  (○)\
  /::::::⌒(__人__)⌒::::: \  そんな仕様にするから
  |    mj |ー'´      | ゲームバランスが取れなくなっtt
  \  〈__ノ       /
    ノ  ノ 
仕様そのものに納得できずに実装するプログラマは少なくないかと思いますが、やる夫も「あー。今vip保守してっから仕様書そこに置いとけお」なんていえる立場ではありません。実装という観点でも問題があるということをまず理解する必要があります。

<やる夫>
    _/⌒  ⌒\_
  /:●))(__人__)((● \ せめてヒントがほしいお
  |     |r┬-|     |
  \      `ー'┃     / 




<アーキテクト>
   / ̄ ̄\
 /   _ノ  \
 |    ( ●)(●)
. |     (__人__) ちっ
  |     ` ⌒´ノ 最初から素直にそう言えや
.  |         }
.  ヽ        }
   ヽ     ノ        \
   /    く  \        \
   |     \   \         \
    |    |ヽ、二⌒)、          \ 




     ____
    / ⌒  ⌒  \ (アーキテクトさんがいないと何もできないお!)
  ./( ―) ( ●)  \ ウチのアーキは意外と扱いやすいお。。
  /::⌒(_人_)⌒:::::  |
  |    ー       .|
  \          / 




   / ̄ ̄\
 /   _ノ  \
 |    ( ○)(○)
. |     (__人__)ほう。
  |     ` ⌒´ノ
.  |         }
.  ヽ        }  
   ヽ       ____
   /       / ⌒  ⌒  \ フヒ・・・?
   | .   ./( ○) ( ○)  \
.   |     /::⌒(_人_)⌒:::::  |
.        |    ー       .|
        \          / 





とりあえずてめぇの腹は把握した。
が、仕事は仕事だ。

以前、ストラテジーパターンで学んだことは何だ?
変化する処理をカプセル化するということだな。
今回てめぇが学ぶべきことは「拡張」の扱い方だ。
武器クラスをアイテムクラスで拡張するという風に考えてみろ。
それも既存のコードを修正せずに振舞いを拡張するんだ。

つまり、ニコニコクロニクル1.0で作成した武器クラスに修正を入れずにアイテムクラスで拡張する方法を考えてみろ。すると、「そうせざるを得ない」あることがわかる。
ヒントはjava.ioにある。
        / ̄ ̄\
      /       \
      |::::::        | 
     . |:::::::::::     | 
       |::::::::::::::    |          ....,:::´, .
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´ 





    _/⌒  ⌒\_
  /:○))(__人__)((○ \ わかりましたお。
  |     |r┬-|     |
  \      `ー'┃     / 
というわけで、アーキテクトが言うには、やる夫が今回学ぶべきことは「拡張」のようでした。

「こういうことだから、こんなデザインパターンになったよー。」という話の進め方をしたいのですが、なかなか上手くいきませんね。ワタシも正しく理解しているわけではないところがたくさんありますが、次回第6回でデザインパターンに収束してみたいと思います。

≪第4回第6回≫


[ 最近のエントリーとその関連エントリー ]