Наследование прототипов
Шаблон фабрика(фабричный метод) создает объекты в зависимости от контекста.
Помимо создания нужно унаследовать как прототип фабрики, так и прототип используемого конструктора. Как это грамотно реализовать? Код:
define(['TankModel', 'ShipModel'], function (Tank, Ship) {
// Factory GameModel
function GameModel() {}
// общие методы, которые наследуются всеми
GameModel.prototype.getType = function () {
console.log('this getType');
};
// фабричный метод
// type - тип конструктора
// params - данные для конструктора
GameModel.factory = function (type, params) {
var object;
// вывести ошибку, если конструктор
// для запрошенного типа отсутствует
if (typeof GameModel[type] !== 'function') {
throw {
name: 'Error',
message: type + ' не существует'
}
}
// тут нужно унаследовать содержимое фабричного прототипа
// делать это каждый раз при использовании одних и тех же конструкторов не нужно
if (typeof GameModel[type].prototype.getType !== 'function') {
GameModel[type].prototype = new GameModel();
}
// тут возвращается объект от конструктора [type]
object = new GameModel[type]();
// работа с готовым объектом:
// это метод конструктора
object.initialize(params);
// это метод фабрики
object.getType();
return object;
};
// делает танки
GameModel.tank = Tank;
// делает корабли
GameModel.ship = Ship;
return GameModel;
});
Создание объекта:
var tank = GameModel.factory('tank');
var ship = GameModel.factory('ship');
Эта фабрика не работает. Фабричные методы затираются при вызове конструктора |
Скопировал фабричные (общие) методы в свойство объекта (жду критики):
define(['TankModel', 'ShipModel'], function (Tank, Ship) {
// Factory GameModel
function GameModel() {}
// общие методы, которые наследуются всеми
GameModel.prototype.getType = function () {
console.log('this getType');
};
// фабричный метод
// type - тип конструктора
// params - данные для конструктора
GameModel.factory = function (type, params) {
var object;
// вывести ошибку, если конструктор
// для запрошенного типа отсутствует
if (typeof GameModel[type] !== 'function') {
throw {
name: 'Error',
message: type + ' не существует'
}
}
// тут возвращается объект от конструктора.
// В качестве аргумента идет прототип объект,
// который сохраняется в свойство объекта
object = new GameModel[type](GameModel.prototype);
// работа с готовым объектом:
// это метод конструктора
object.initialize(params);
// это метод фабрики
// все методы фабрики скопированы
// при инициализации объекта
// и доступны как object.gameModel['метод']()
object.gameModel.getType();
return object;
};
// делает танки
GameModel.tank = Tank;
// делает корабли
GameModel.ship = Ship;
return GameModel;
});
не думаю что это лучшее решение и это уже не наследование, а копирование. А значит требует ресурсы памяти |
Не очень удачно по моему.
object = new GameModel[type](GameModel.prototype); object.initialize(params); Как то странно подмешиваемые методы передавать как параметр конструктору, а инициализацию дергать потом отдельно. По крайней мере здесь причин для этого я не вижу. Вроде вот так как то по привычнее будет.
define(['TankModel', 'ShipModel'], function (Tank, Ship) {
function GameModel( type, params){
//Проверка на наличие конструктора
if (typeof GameModel[type] !== 'function') {
throw {
name: 'Error',
message: type + ' не существует'
}
}
var instance=new GameModel[type](params);
//если нужно то можно подмешать методы фабрики
instance.getType=GameModel.prototype.getType;
return instance;
}
//Перечислим продукты которая может создавать фабрика
GameModel.Ship=Ship;
GameModel.Tank=Tank;
//методы которые можно подмешивать
GameMode.prototype.getType=function(){
//бла бла
}
});
Или может быть даже так Добавим подмешиваемые методы сразу в прототип.
define(['TankModel', 'ShipModel'], function (Tank, Ship) {
function GameModel( type, params){
//Проверка на наличие конструктора
if (typeof GameModel[type] !== 'function') {
throw {
name: 'Error',
message: type + ' не существует'
}
}
return new GameModel[type](params);
}
//метод для добавления новых продуктов к фабрике
GameModel.add=function(name,obj){
//примеси
obj.prototype.getType=GameModel.prototype.getType;
GameModel[name]=obj;
}
//Перечислим продукты которая может создавать фабрика
GameModel.add('Ship',Ship);
GameModel.add('Tank',Tank);
//методы которые можно подмешивать
GameModel.prototype.getType=function(){
//бла бла
}
});
Последний вариант это собрать все примеси в одном специализированном объекте, но так чтобы они могли работать с экземпляром. Первый приходящий на ум способ сделать это не вмешиваясь в работу конструктора, просто сохранить ссылку на экземпляр в замыкании.
define(['TankModel', 'ShipModel'], function (Tank, Ship) {
function GameModel( type, params){
//Проверка на наличие конструктора
if (typeof GameModel[type] !== 'function') {
throw {
name: 'Error',
message: type + ' не существует'
}
}
var instance=new GameModel[type](params);
instance.GameModel=Inclusions(instance);
return instance
}
//набор включений которые добавляются фабрикой в экземпляр
function Inclusions(obj) {
return {
getType:function(){
return typeof obj;
}
}
}
});
//вместо
instance.GameModel=Inclusions();
//хватило бы и
instance.GameModel={f1:function(){}, f2:function(){}}
|
я не совсем понимаю как работает фабрика (да да пасоны я реал не понмиаю)
но как сделать цепочку прототипа обьяснить могу
function Animals (){
function Cat (){}
Cat.prototype = Object.create(Animals.prototype);
function Rabbit (){}
Rabbit.prototype = Object.create(Animals.prototype);
}
кот и кролик наследуют прототип свой и прототип фабрики |
DjDiablo, как раз то что нужно.
Выбрал 2-й вариант Спасибо! :thanks: |
доработал функцию add немного:
// метод для добавления новых продуктов к фабрике
GameModel.add = function (name, object) {
var props = GameModel.prototype
, i;
for (i in props) {
if (props.hasOwnProperty(i)) {
object.prototype[i] = props[i]
}
}
GameModel[name] = object;
};
|
к слову о красоте кода
// метод для добавления новых продуктов к фабрике
GameModel.add = function (name, object) {
var props = GameModel.prototype;
for (var i in props) if (props.hasOwnProperty(i)) {
object.prototype[i] = props[i]
}
GameModel[name] = object;
};
|
а чем мой плох? )
|
Цитата:
|
а ну, если только в этом дело...
:D |
| Часовой пояс GMT +3, время: 09:13. |