Я знаю, що пройшло вже більше десяти років з того часу, як про це запитали, але я просто п ятий раз в житті програміста виклав свої думки з цього приводу і знайшов можливе рішення, яке не знаю, чи мені все ще подобається . Я раніше не бачив цієї методології задокументованою, тому буду називати її "шаблоном приватного / публічного долара" або " $ / $" .
var ownFunctionResult = this.$("functionName"[, arg1[, arg2 ...]]);
var ownFieldValue = this._$("fieldName"[, newValue]);
var objectFunctionResult = objectX.$("functionName"[, arg1[, arg2 ...]]);
//Throws an exception. objectX._$ is not defined
var objectFieldValue = objectX._$("fieldName"[, newValue]);
Концепція використовує функцію ClassDefinition, яка повертає функцію Constructor, яка повертає об'єкт Interface . Єдиний метод інтерфейсу - це те, $
що отримує name
аргумент для виклику відповідної функції в об'єкті конструктора, а додаткові аргументи, передані після name
, передаються у виклику.
Глобально визначена допоміжна функція ClassValues
зберігає всі поля в якості об'єкта по мірі необхідності. Він визначає _$
функцію доступу до них name
. З цього випливає короткий шаблон отримання / встановлення, тож якщо value
він буде переданий, він буде використовуватися як нове значення змінної.
var ClassValues = function (values) {
return {
_$: function _$(name, value) {
if (arguments.length > 1) {
values[name] = value;
}
return values[name];
}
};
};
Глобально визначена функція Interface
приймає об'єкт і Values
об'єкт для повернення знака _interface
однієї єдиної функції, $
яка вивчає, obj
щоб знайти функцію, названу за параметром, name
і викликає її values
як об'єкт, що охоплює область . Додаткові аргументи, передані до, $
будуть передані при виклику функції.
var Interface = function (obj, values, className) {
var _interface = {
$: function $(name) {
if (typeof(obj[name]) === "function") {
return obj[name].apply(values, Array.prototype.splice.call(arguments, 1));
}
throw className + "." + name + " is not a function.";
}
};
//Give values access to the interface.
values.$ = _interface.$;
return _interface;
};
У наведеному нижче зразку ClassX
присвоюється результат ClassDefinition
, який є Constructor
функцією. Constructor
може отримати будь-яку кількість аргументів. Interface
це те, що зовнішній код отримує після виклику конструктора.
var ClassX = (function ClassDefinition () {
var Constructor = function Constructor (valA) {
return Interface(this, ClassValues({ valA: valA }), "ClassX");
};
Constructor.prototype.getValA = function getValA() {
//private value access pattern to get current value.
return this._$("valA");
};
Constructor.prototype.setValA = function setValA(valA) {
//private value access pattern to set new value.
this._$("valA", valA);
};
Constructor.prototype.isValAValid = function isValAValid(validMessage, invalidMessage) {
//interface access pattern to call object function.
var valA = this.$("getValA");
//timesAccessed was not defined in constructor but can be added later...
var timesAccessed = this._$("timesAccessed");
if (timesAccessed) {
timesAccessed = timesAccessed + 1;
} else {
timesAccessed = 1;
}
this._$("timesAccessed", timesAccessed);
if (valA) {
return "valA is " + validMessage + ".";
}
return "valA is " + invalidMessage + ".";
};
return Constructor;
}());
Немає сенсу мати непрообразовані функції Constructor
, хоча ви можете їх визначити в тілі функції конструктора. Усі функції називаються за схемою публічного долара this.$("functionName"[, param1[, param2 ...]])
. До приватних цінностей звертається за схемою приватного долара this._$("valueName"[, replacingValue]);
. Оскільки Interface
не має визначення для _$
, до значень не можуть бути доступні зовнішні об'єкти. Оскільки кожен прототипний орган функції this
встановлений на values
об'єкт у функції $
, ви отримаєте винятки, якщо ви будете викликати безпосередньо функції конструктора братів; також слід дотримуватися шаблону _ $ / $ у прототипованих функціональних органах. Нижче використання зразка.
var classX1 = new ClassX();
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
console.log("classX1.valA: " + classX1.$("getValA"));
classX1.$("setValA", "v1");
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
var classX2 = new ClassX("v2");
console.log("classX1.valA: " + classX1.$("getValA"));
console.log("classX2.valA: " + classX2.$("getValA"));
//This will throw an exception
//classX1._$("valA");
І консольний вихід.
classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2
_ $ / $ Шаблон забезпечує повну конфіденційність значень в повністю прототипів класів. Я не знаю, чи коли-небудь я буду користуватися цим, ні якщо у нього є недоліки, але ей, це була гарна загадка!