ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptシリーズを深く理解する(7) S.O.L.I.Dの開閉五原則 OCP_javascriptスキル

JavaScriptシリーズを深く理解する(7) S.O.L.I.Dの開閉五原則 OCP_javascriptスキル

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBオリジナル
2016-05-16 17:57:031203ブラウズ

はじめに
この章で説明するのは、S.O.L.I.D の 5 つの原則である Open/Closed Principle OCP (The Open/Closed Principle) の JavaScript 言語実装の第 2 部です。
開始と終了の原則の説明は次のとおりです。
ソフトウェア エンティティ (クラス、モジュール、関数など) は拡張に対してオープンである必要がありますが、変更に対してはクローズされている必要があります。など)は、拡張に対してオープンであり、変更に対してクローズである必要があります。つまり、ソフトウェア エンティティは変更せずに拡張する必要があります。
コードをコピー
拡張にオープンとは、新しいニーズが生じたときに、既存のモデルを拡張して目標を達成できることを意味します。端的に言えば、「変更をクローズ」とは、エンティティへの変更が許可されていないことを意味します。さまざまな動作を実行する必要があるこれらのエンティティは、変更を加えずにさまざまな変更を実行できるように設計されており、その原則により、プロジェクトのメンテナンスが最小限で容易になります。コード。
英語原文: http://freshbrewedcode.com/derekgreer/2011/12/19/solid-javascript-the-openclosed-principle/
問題コード
直感的に説明するために、例を挙げてみましょう例として、下位コードは質問リストを動的に表示するコードです (開始と終了の原則は使用されません)。

コードをコピー コードは次のとおりです:
// 質問タイプ
var AnswerType = {
Choice: 0,
Input: 1
};
// 質問エンティティ
関数 question(label, AnswerType, Choices) {
return {
label: label,
answerType:answerType,
choices:choices // ここでの選択肢はオプションのパラメータです
}
}
var view = (function () {
// 質問をレンダリングします
function renderQuestion(target, question) {
var questionWrapper = document.createElement('div');
questionWrapper.className = 'question';
var questionLabel = document.createElement('div' ) ;
questionLabel.className = 'question-label';
var label = document.createTextNode(question.label);
var = document.createElement( ' div');
answer.className = 'question-input'
// ドロップダウン メニューと入力ボックスのそれぞれに応じて異なるコードを表示します
if (question.answerType == = AnswerType.Choice) {
var input = document.createElement('select');
var len = question.choices.length;
for (var i = 0; i var option = document.createElement('option');
option.text = question.choices[i];
option.value = question.choices[i];
}
}
else if (question.answerType === AnswerType.Input) {
var input = document.createElement('input'); 'テキスト';
}
questionWrapper.appendChild(questionLabel);
target.appendChild(questionWrapper); >}
return {
// 表示するためにすべての質問リストをスキャンします
render: function (target,questions) {
for (var i = 0; i renderQuestion(ターゲット, 質問[i]);
}
})();
varquestion('過去 30 日以内に使用したタバコ製品はありますか?', AnswerType.Choice, ['はい', 'いいえ']),
question('現在使用している薬は何ですか?', AnswerType.Input)
];
var questionRegion = document.getElementById('questions');
view.render(questionRegion,questions);


上記のコードでは、ビュー オブジェクトに To が含まれています。質問リストを表示するには、質問の種類に応じて異なる表示方法が使用されます。質問には、ラベル、質問の種類、選択肢のオプション (選択タイプの場合) が含まれます。質問の種類が選択の場合は、オプションに基づいてドロップダウン メニューを生成します。質問の種類が入力の場合は、単に入力入力ボックスを表示します。
このコードには制限があります。つまり、別の質問タイプを追加する場合は、renderQuestion の条件ステートメントを再度変更する必要があり、これは明らかに開始と終了の原則に違反します。
コードのリファクタリング
このコードをリファクタリングして、新しい質問タイプが表示されたときに、ビュー オブジェクト内のコードを変更せずに、ビュー オブジェクトのレンダリング機能を拡張できるようにします。
最初に一般的な質問を作成しますCreator 関数:



コードをコピーします


コードは次のとおりです:

function questionCreator(spec, my) {
var that = {};
my.label =
my. renderInput = function () {
throw "notimplemented";
// ここでは renderInput が実装されていません。主な目的は、それぞれの問題タイプの実装コードでメソッド全体をカバーすることです
}; 🎜>that.render = function (target) {
var questionWrapper = document.createElement('div');
questionWrapper.className = 'question';
var questionLabel = document.createElement('div' );
questionLabel.className = 'question-label';
var label = document.createTextNode(spec.label);
var = my.renderInput( );
// render メソッドは同じ大まかで合理的なコードです
// 唯一の違いは上記の文です my.renderInput()
// 質問タイプが異なれば実装も異なるため
questionWrapper .appendChild(questionLabel );
questionWrapper.appendChild(answer);
return that;


このコードは 1 つの質問をレンダリングしますが、実装されていない renderInput メソッドを提供しているため、他の関数がそれをオーバーライドしてさまざまな質問タイプを使用できるようになります。



コードをコピーします


コードは次のとおりです:
function ChoiceQuestionCreator(spec) { var my = {}, that = questionCreator(spec, my); //選択タイプの RenderInput 実装my.renderInput = function () {
var input = document.createElement('select'); spec.choices.length;
for (var i = 0; i var option = document.createElement('option');
option.text = spec.choices[ i];
option.value = spec.choices[i];
入力を返します;
>}
function inputQuestionCreator( spec) {
var my = {},
that = questionCreator(spec, my)
//入力型の RenderInput 実装
my.renderInput = function () {
var input = document.createElement('input');
入力を返します;
}


choiceQuestionCreator 関数と inputQuestionCreator 関数は、それぞれドロップダウン メニューと入力ボックスの renderInput 実装に対応し、統合された questionCreator(spec, my) を内部で呼び出し、そのオブジェクト (同じタイプです)。
ビュー オブジェクトのコードは非常に固定されています。




コードをコピー


コードは次のとおりです:


var view = {
render: function(target ,questions) {
for (var i = 0; i target.appendChild(questions[i].render());
>}
}; コードをコピー


コードは次のとおりです:


varquestions = [
choiceQuestionCreator({
label: '範囲内でタバコ製品を使用しましたか?過去 30 日間?',
choices: ['Yes', 'No']
}),
inputQuestionCreator({
label: '現在使用している薬は何ですか?'

コードをコピーします


コードは次のとおりです:


var questionRegion = document.getElementById('questions');
view.render(questionRegion,questions); 🎜>
リファクタリング後の最終コード


コードをコピー コードは次のとおりです:

function questionCreator(spec, my) {
var that = {};
私 = 私 || {};
my.label = spec.label;
my.renderInput = function() {
throw "実装されていません";
};
that.render = function(target) {
var questionWrapper = document.createElement('div');
questionWrapper.className = '質問';
var questionLabel = document.createElement('div');
questionLabel.className = '質問ラベル';
var label = document.createTextNode(spec.label);
questionLabel.appendChild(label);
var 答え = my.renderInput();
questionWrapper.appendChild(questionLabel);
questionWrapper.appendChild(answer);
質問ラッパーを返す;
};
それを返してください。
}
function ChoiceQuestionCreator(spec) {
var my = {},
that = questionCreator(spec, my);
my.renderInput = function() {
var input = document.createElement('select');
var len = spec.choices.length;
for (var i = 0; i var option = document.createElement('option');
option.text = spec.choices[i];
option.value = spec.choices[i];
input.appendChild(オプション);
}
入力を返します。
};
それを返してください。
}
function inputQuestionCreator(spec) {
var my = {},
that = questionCreator(spec, my);
my.renderInput = function() {
var input = document.createElement('input');
input.type = 'テキスト';
入力を返します。
};
それを返してください。
}
var view = {
render: function(target,questions) {
for (var i = 0; i target.appendChild(質問[i].render());
}
}
};
varquestions = [
choiceQuestionCreator({
label: '過去 30 日以内にタバコ製品を使用しましたか?',
choices: ['はい', 'いいえ']
} ),
inputQuestionCreator({
label: '現在使用している薬は何ですか?'
})
];
var questionRegion = document.getElementById('questions');
view.render(questionRegion, 質問);

上の代コード里应はいくつかのテクニックポイントを使用しています、我们来一看一下:
第一、questionCreator メソッドの構築、私が使用できるモジュールパネル メソッド モードで処理问题の機能デリガット给针对を使用することができます。
次に、操作を実行するためのレンダリング実行がパッケージ化されているため、これらのプロパティを公開する必要がなくなったため、私が持っている spec プロパティを使用して、前の質問メソッドの構造関数プロパティを置き換えます。外部代码了。
第三、我们为每个问题类型创建一个对象进行各自的代码实现、但每个实现里都必须包含レンダリングプアト方法以便覆盖質問作成者renderinput代码、这就是我们常说的
再構築により、不必要な質問の種類の列 AnswerType を削除し、choiceQuestionCreator 関数の必須パラメータとして選択肢を追加することができます (以前のバージョンは選択可能なパラメータの 1 つです)。
は、
再構成後のバージョンのビューオブジェクトは、新しいオブジェクトを実行することができます。
別: C# の場合、上のコードを見た後、類似したものがいくつか実装されるかどうかはわかりませんが、上記のコード用のプロトタイプも実装可能であり、大規模な実装が可能です。自主研究一下。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。