2010年11月27日土曜日

第16章 Mediatorパターン : 相手は相談役1人だけ



今回はMediatorパターン。Mediatorは仲介者で、オブジェクト間の連携を一手に担ってくれます。
下例のようなGUIプログラミングによく使われるそうです。MVCモデルに通じますね。



今回はGUIが絡んでいるので、JavaScriptで書いてみました。
JavaScriptはほぼ初挑戦なので、変な実装とかあったら指摘もらえると助かります。
(JavaScriptのOOPってこんなにしんどいんですか?)


実行結果


GuestLogin
Username: 
Password: 


ソースコード
// id="my_content" のelementがあると仮定している

function onLoad(){
    var container = document.getElementById("my_content");
    var loginform = new LoginForm();
    loginform.appendInto(container);
}


// class declaration
function ColleagueInputButton(){ // implements Colleague Interface
    this.initialize.apply(this, arguments);
}
ColleagueInputButton.prototype = {
     initialize:
        function(caption){
            this.content = document.createElement('input');
            this.content.setAttribute('type', 'button');
            this.content.setAttribute('value', caption);
        }
    ,appendInto:
        function(parentContainer){
            parentContainer.appendChild(this.content);
        }
    ,setMediator: // Colleague Interface method
        function(mediator){
            this.content.onclick = mediator.onClick;
        }
    ,setColleagueEnabled: // Colleague Interface method
        function(enabled){
            this.content.disabled = !enabled;
        }
};


// class declaration
function ColleagueInputTextField(){ // implements Colleague Interface
    this.initialize.apply(this, arguments);
}
ColleagueInputTextField.prototype = {
     initialize:
        function(text, columns, passwordtype){
            this.content = document.createElement('input');
            if(passwordtype){
                this.content.setAttribute('type', 'password');
            }else{
                this.content.setAttribute('type', 'text');
            }
            this.content.setAttribute('value', text);
            this.content.setAttribute('size', columns);
        }
    ,appendInto:
        function(parentContainer){
            parentContainer.appendChild(this.content);
        }
    ,getText:
        function(){
            return this.content.value;
        }
    ,setText:
        function(text){
            this.content.value = text;
            this.content.onchange();
        }
    ,setMediator: // Colleague Interface method
        function(mediator){
            this.content.onchange = mediator.colleagueChanged;
        }
    ,setColleagueEnabled: // Colleague Interface method
        function(enabled){
            this.content.disabled = !enabled;
            if(enabled){
                this.content.setAttribute('style', 'background-color: #FFF;');
            }else{
                this.content.setAttribute('style', 'background-color: #EEE;');
            }
        }
};


// class declaration
function ColleagueInputRadioButton(){ // implements Colleague Interface
    this.initialize.apply(this, arguments);
}
ColleagueInputRadioButton.prototype = {
     initialize:
        function(caption, groupname, state){
            this.content = document.createElement('input');
            this.content.setAttribute('type', 'radio');
            this.content.setAttribute('name', groupname);
            this.content.defaultChecked = state;
        }
    ,appendInto:
        function(parentContainer){
            parentContainer.appendChild(this.content);
        }
    ,isChecked:
        function(){
            return this.content.checked;
        }
    ,setMediator: // Colleague Interface method
        function(mediator){
            this.content.onchange = mediator.colleagueChanged;
        }
    ,setColleagueEnabled: // Colleague Interface method
        function(enabled){
            this.content.disabled = !enabled;
        }
};


// class declaration
function LoginForm(){ // implements Mediator Interface
    this.radioGuest = null;
    this.radioLogin = null;
    this.textUser = null;
    this.textPass = null;
    this.buttonOK = null;
    this.buttonCancel = null;
    this.initialize.apply(this, arguments);
}
LoginForm.prototype = {
     initialize:
        function(){
            self = this;
            this.content = document.createElement('form');
            this.createColleagues();

            this.radioGuest.appendInto(this.content);
            span = document.createElement('span');
            span.innerHTML = "Guest";
            this.content.appendChild(span);
            this.radioLogin.appendInto(this.content);
            span = document.createElement('span');
            span.innerHTML = "Login";
            this.content.appendChild(span);
            this.content.appendChild(document.createElement('br'));

            span = document.createElement('span');
            span.innerHTML = "Username: ";
            this.content.appendChild(span);
            this.textUser.appendInto(this.content);
            this.content.appendChild(document.createElement('br'));
            span = document.createElement('span');
            span.innerHTML = "Password: ";
            this.content.appendChild(span);
            this.textPass.appendInto(this.content);
            this.content.appendChild(document.createElement('br'));

            this.buttonOK.appendInto(this.content);
            this.buttonCancel.appendInto(this.content);

            this.colleagueChanged();
        }
    ,appendInto:
        function(parentContainer){
            parentContainer.appendChild(this.content);
        }
    ,createColleagues: // Mediator Interface method
        function(){
            this.radioGuest = new ColleagueInputRadioButton("Guest", "usertype", true);
            this.radioLogin = new ColleagueInputRadioButton("Login", "usertype", false);
            this.textUser = new ColleagueInputTextField("", 10);
            this.textPass = new ColleagueInputTextField("", 10, true);
            this.buttonOK = new ColleagueInputButton("OK");
            this.buttonCancel = new ColleagueInputButton("Cancel");
            this.radioGuest.setMediator(this);
            this.radioLogin.setMediator(this);
            this.textUser.setMediator(this);
            this.textPass.setMediator(this);
            this.buttonOK.setMediator(this);
            this.buttonCancel.setMediator(this);
        }
    ,colleagueChanged: // Mediator Interface method
        function(){
            if(self.radioGuest.isChecked() === true){
                self.textUser.setColleagueEnabled(false);
                self.textPass.setColleagueEnabled(false);
                self.buttonOK.setColleagueEnabled(true);
            }else{
                self.textUser.setColleagueEnabled(true);
                // and also needs to check textUser&textPass
                if(self.textUser.getText().length === 0){
                    self.textPass.setColleagueEnabled(false);
                    self.buttonOK.setColleagueEnabled(false);
                }else{
                    self.textPass.setColleagueEnabled(true);
                    if(self.textPass.getText().length === 0){
                        self.buttonOK.setColleagueEnabled(false);
                    }else{
                        self.buttonOK.setColleagueEnabled(true);
                    }
                }
            }
        }
    ,onClick:
        function(){
            if(this.value === "Cancel"){
                self.textUser.setText("");
                self.textPass.setText("");
            }
            else{
                if(self.radioGuest.isChecked() === true){
                    alert("Hello, Guest!");
                }else{
                    alert("Hello, "+self.textUser.getText()+"!\nYour pass is "+self.textPass.getText()+", right??");
                }
            }
        }
};

window.onload = onLoad;

0 件のコメント:

コメントを投稿