I understand that there is a concept of Action Filters in languages like C# using ASP.NET. I would like to have this kind of pre-processing functionality in my class methods, using Javascript. Is this possible/a part of the language? Otherwise how would I implement this feature? It sounds like a language level implementation, like constructors and getters, and so I'm confused whether or not it's possible to implement such a thing.
TMI: I'm trying to create an ecommerce website with firebase auth. Right now I have implemented all the cart methods; but I would like to have some sort of auth check to allow these methods to be called, or otherwise route the user to the login page.
While I couldn't find the exact functionality of an Action Filter, JS has a neat feature called Proxy's, which can be used for the same purpose.
When you create a proxy of an object, it intercept the requests to the given object, and sort of acts like an intermediary. What I found is that you can include the processing logic of an Action Filter, such as checking if a user is authorized, inside the get and set of the handler provided to the proxy.
const baseInstance = new SomeClass(param1, param2);
const handler = {
get(target, prop) {
if(/* implement required check */) alternatePath();
else return target[prop];
},
};
const extendedInstance = new Proxy(baseInstance, handler);
This eliminates the need to modify each method of the base class, just to include that one check(or multiple checks; that can also be done). Doing so, we separate the functionalities.
Check out this neat video for more info.
Related
I'm creating a Javascript game that provides quests for the user to play through. Each quest has a number of tasks which are completed when certain requirements are met. Below is the design I originally intended to go with.
As you can see, each Task and GameEvent (simplified to Event) has a type and some data (encapsulated in a dict). When an event is sent to QuestManager, it is passed along to the active Quest objects who in turn pass it on to each Task assuming their types are the same. Each requirement in the task is then tested against the correlating data in the event. The reason why I don't do 1:1 checks is because an event may have additional data.
e.g data{item: someItem, locationFound: someLocation} != requirement{item: someItem}
This works great in terms of minimising the number of classes that need to be created. Events and tasks are generic so they can be easily created and tested against without creating a ton of sub-classes.
But this design creates a problem. Because of its generality, it is never certain what requirements should be given to a task without first finding an event of the same type and checking the data being sent to it. As the project expands, this becomes a nightmare to manage.
Instead, I could create sub-classes for both Event and Task that would cover the various types, like this:
Event -> ItemPickupEvent, MoveEvent, etc.
Task -> ItemPickupTask, ItemPickedUpAtLocationTask, MoveTask, etc.
But the data is similar between them and seems highly unnecessary.
My final thought was to create data objects to encapsulate the data being passed by certain event types, as follows:
ItemPickupData, MoveData, TalkData etc.
Events and tasks could just be given the appropriate data object. This provides better structure to the data being used. If a piece of data should not be made into a requirement, it could simply be defaulted to null.
In terms of maintainability and structural design, is this an adequate solution or is there a better way to approach this problem?
Thanks.
Because of its generality, it is never certain what requirements should be given to a task without first finding an event of the same type and checking the data being sent to it.
As I understand, the problem is that almost the same data is duplicated in the event object and task object.
For example, you have Event { 'type': 'ItemPickup', data: { 'name': 'MagicSword', 'kind': 'weapon' } }.
And then you want to add a task to pickup the magic sword and you create the Task { 'type': 'ItemPickup', data: { 'name': 'MagicSword' } }.
So this is the problem and here you need to lookup how exactly you have configured the event and put the same data into the task object.
I think the solution to move this data into separate objects should work well.
Another thing which doesn't look right is that you have type field and it hints that you need to have subclasses.
And this also would be solved if you create the data objects like ItemPickupData, MoveData, etc.
An alternative can be to have the Event itself to be this data object and have something like this (pseudocode):
class Event // base class for events with common data and methods
// the subclasses can be almost empty
class ItemPickupEvent extends Event
class MoveEvent extends Event
class Task
_requirements = [
new ItemPickupEvent('MagicSword'),
// and maybe it is even better to wrap events into "Requirment" objects,
// which can, for example, be marked as completed
new Requirement(new MoveEvent('OldForest')),
...
]
And then you could then manage requirements this way:
class Task
isComplete(event)
complete = false
// go over requirements to see if this task is complete
for requirement in this._requirments:
complete = complete && requirement->isComplete(event)
return complete
class Requirement
isComplete(event)
# check event class and properties to understand if the requirement is satisfied
if class(event) == class(this._event):
if event.isNameMatches(this._event):
this->_complete = true
return this->_complete
It can also be done without the class name check.
The idea is to have base Requirement class has special methods for each event class and rejects them by default.
Subclasses then can handle specific event types:
class Requirement
isComplete(event)
// redirect the type detection to event object
return event->isComplete(this)
isCompleteItemPickup(event)
return false
isCompleteMove(event)
return false
class ItemPickupRequirement
isCompleteItemPickup(event)
// here we know that event is ItemPickupEvent
if event.isNameMatches(this._event):
this->_complete = true
return this->_complete
class MoveRequirement
isCompleteItemPickup(event)
// here we know that event is MoveEvent
if event.isNameMatches(this._event):
this->_complete = true
return this->_complete
The isComplete method of the Requirment class is used from the Task class and it re-directs type detection to the event object.
The event object then passes itself back to the appropriate method of the requirement:
class Event
isComplete(requirement) // should be implemented in subclasses
class ItemPickupEvent
isComplete(requirement)
// here we call the specific requirement method
// now we know the exact event object type (it is ItemPickupEvent)
return requirement->isCompleteItemPickup(this)
class MoveEvent
isComplete(requirement)
return requirement->isCompleteMove(this)
The structure may look a bit complicated, but depending on the specifics, you may need the Requirement class and it's sub-classes anyway (for example, there can be generic ItemPickupRequirement and some specific PowerItemPickupRequirement).
// Main class
function App() {
this.task = new Task(this); // pass the instance of this class to Task so
// it has access to doSomething
}
App.prototype.doSomething = function () {
alert("I do something that Task() needs to be able to do!");
};
function Task(app) {
// This class needs access to App()'s doSomething method
this.appInstance = app;
this.appInstance.doSomething(); // Great, now Task can call the method
}
var app = new App();
The aim of the code above is to give Task access to one of App's methods called doSomething. The code is the current way I'd go about it and I'm posting this to see if it's the best way...
To give Task access I simply pass the whole instance of App, is this efficient or is there a better way to go about it? Is the code above general practice in going about doing something like this?
Yes, what you have is fine. It is a circular dependency, however because of JavaScript's dynamic nature there aren't really any issues.
Another way you could reference App from Task would be a Singleton pattern or something similar, but that would probably be harder to test.
jsFiddle Demo
Generally bind would be used in this scenario assuming that the Task "class" didn't also setup other facilities which were not shown here.
Bind allows for the context to be provided for a function. This could be done in app's constructor. At which point only a function task would be required to call "someMethod".
function task(){
return this["someMethod"]();
}
function App(){
task.bind(this)();
}
App.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
However, if task must be a "class", and have other responsibilities then the prototype function could be shared.
function Task(){}
function App(){}
App.prototype.someMethod = Task.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
a.task();//->"Task needed access to this"
var t = new Task();
t.someMethod();//->"Task needed access to this"
Your app instances and task instances are tightly bound. App instances have tasks and this can be fine.
A design of loosely coupled objects is more flexible and easier to extend but more complicated to initially create. One such pattern is using a mediator/publish subscriber and have app raise an event/publish message any other object function can listen to this and take action on the event.
For example: your app creates an Ajax instance and when that instance is done it raises some event (fetchedData for example). A listener could be DomDependent.updateView function but later you may want to add/remove/change the order of tasks to do after data is fetched. This can all be configured in a app.init function or per procedure in a controller that kicks of certain procedures (like log in, search, ...).
Instead of creating a whole bunch of specific functions in Ajax (fetchUserPrefs, login, search, ...) you can create one general function and have the controller add listeners or pass the next event when fetchData is complete to run the correct next function.
Here is some pseudo code:
var app = {
init:function(){
mediator.add("updateLogin",domDependent.updateView);
mediator.add("updateLogin",app.loadUserPrefs);
mediator.add("failLogin",domDependent.updateView);
},
login: function(){
mediator.trigger("loadingSometing",{type:"login"});
ajax.fetch({
onComplete:"updateLogin",//what listens to updateLogin you decided in init
onFail:"failLogin",
loginDetails:domDependent.getLogin(),
url:settings.loginUrl,
type:"post"
});
}
}
var ajax = {
fetch:function(data){
data = data || {};
//simple check for onComplete, it's mandatory
var complete = data.onComplete || app.raiseError("ajax.fetch needs onComplete");
//other code to validate data and making ajax request
onSuccess:function(resp){
//mutate data object as the mediator will pass it to
// whatever other function is called next
// you don't hard code domDependent.updateView and
// app.loadUserPrefs because fetch can be used generally and
// success may have to do completely different things after its done
// and you want to define procedures in init, not all over your code
data.response=resp;
//trigger event to do whatever needs to be done next
mediator.trigger(complete,data);
}
}
}
As you can see it gets complicated and maybe doesn't look like code you're used to but it's highly configurable.
I may have misunderstood the advantages of the mediator pattern to loose couple and if so please comment. I use it to:
Make methods more general instead of copying a lot of logic only
because what to do after it's done is different. In fetch the ajax
object just fetches, this would be the same for login or getting
user preferences, the only thing different is what function to call
next/on error when it's done.
A procedure like login involves multiple functions in multiple
objects if this function chain hard code what to do next once a
particular function is done your procedure of login is defined all
over your code. When defining it in init/config you can easily change the
order or add/remove functions in the chain.
I've run into a headache with Backbone. I have a collection of specified records, which have subrecords, for example: surgeons have scheduled procedures, procedures have equipment, some equipment has consumable needs (gasses, liquids, etc). If I have a Backbone collection surgeons, then each surgeon has a model-- but his procedures and equipment and consumables will all be plain ol' Javascript arrays and objects after being unpacked from JSON.
I suppose I could, in the SurgeonsCollection, use the parse() to make new ProcedureCollections, and in turn make new EquipmentCollections, but after a while this is turning into a hairball. To make it sensible server-side there's a single point of contact that takes one surgeon and his stuff as a POST-- so propagating the 'set' on a ConsumableModel automagically to trigger a 'save' down the hierarchy also makes the whole hierarchical approach fuzzy.
Has anyone else encountered a problem like this? How did you solve it?
This can be helpful in you case: https://github.com/PaulUithol/Backbone-relational
You specify the relations 1:1, 1:n, n:n and it will parse the JSON accordingly. It also create a global store to keep track of all records.
So, one way I solved this problem is by doing the following:
Have all models inherit from a custom BaseModel and put the following function in BaseModel:
convertToModel: function(dataType, modelType) {
if (this.get(dataType)) {
var map = { };
map[dataType] = new modelType(this.get(dataType));
this.set(map);
}
}
Override Backbone.sync and at first let the Model serialize as it normally would:
model.set(response, { silent: true });
Then check to see if the model has an onUpdate function:
if (model.onUpdate) {
model.onUpdate();
}
Then, whenever you have a model that you want to generate submodels and subcollections, implement onUpdate in the model with something like this:
onUpdate: function() {
this.convertToModel('nameOfAttribute1', SomeCustomModel1);
this.convertToModel('nameOfAttribute2', SomeCustomModel2);
}
I would separate out the different surgeons, procedures, equipment, etc. as different resources in your web service. If you only need to update the equipment for a particular procedure, you can update that one procedure.
Also, if you didn't always need all the information, I would also lazy-load data as needed, but send down fully-populated objects where needed to increase performance.
I'm not sure where to put some methods.
Let's say I want to send an email.
Which of the following options should I choose:
email = new Email("title", "adress", "body");
email.send();
or
email = new Email("title", "adress", "body");
Postman.send(email);
Because how can an email send itself? And isn't it better to have a central object that handles all emails because then he can regulate things like sending all emails at a specific time, sort mails, remove mails etc.
Also if I want to delete an user, how should I do:
user.delete();
or
administrator.delete(user);
Please share your thoughts about how to know where to put the methods.
I disagree with Arseny. An email can send itself, and that's exactly where the code should live. That's what methods are: actions that can be performed on the object.
However, note that your approaches are not mutually incompatible. An email's send action could easily just contain the code to add itself to the Postman's send queue, and if you do want to regulate the actions, that might be a good idea. But that's no reason not to have a send method for the email class.
All sensible methods that act on emails should be in the email class, for the convenience of users of your class. But email objects should not contain any fields except those related to the content of the email itself (single responsibility principle).
Therefore, I'd suggest this:
class Email
def email(postman)
postman.send(self)
end
end
In statically typed languages, the type of the postman argument should definitely be an interface.
Use the second method to have a class manager handle the objects (emails or users). This follows the single-responsibility-principle.
In Ruby I'd do this:
email = Email.deliver(recipient, subject, message)
The correspoding class would look something like this:
class Email
def self.deliver(recipient, subject, message)
# Do stuff to send mail
end
end
This is clean and easy to use.
On the delete issue: Delete the object you want to delete. So #user.delete would be best. If you want to register the administrator who deleted the user: #user.delete_by(#admin)
I agree with Daniel.
Following your first example, a lot of common widgets would also have a "collections" manager like you mentioned but they don't necessarily. A Tabs widget can show/hide one of its own tabs, without necessarily specifying a new Tab class for each individual one.
I believe functionality should be encapsulated. The example of deleting a user however, is a slightly different case. Having a delete method on the User class could do stuff like clear its own internal variables, settings, etc, but it won't delete the reference to itself. I find that delete methods are better suited for collection-based classes. I wouldn't per se put the delete method on a admin class but rather on a Users "collection" class.
function Users(){
var users = [];
this.add = function(user){
// add user code
users.push(new User(user));
}
this.remove = function(user){
// remove user code and remove it from array
}
}
I don't quite see how an object can fully add/remove itself so it makes sense to me to have that functionality at the collections level. Besides that though, I would say it should be encapsulated within the class it's meant for.
When a GUI is composed of several subcomponents that I treat as individual Views with their own Presenter and Models, is there a pattern for gluing them together? Some subcomponents are persistently on the screen while others would get swapped in and out.
What would be a good factory pattern for instantiating the respective MVP triad for a subcomponent that gets added to the GUI at runtime?
How do you glue the subcomponents with the persistent "container" part of the GUI and with each other? Would there be a "God Presenter" that ties other presenters together?
Update: I'm now shooting for something similar to Eclipse's extension mechanism. Plug-ins register themselves to a global registry for the functionality that they provide. When a functionality such as returning data or rendering a View is needed, the registry is queried and the returned functions are invoked (this is pure JavaScript, so I'm not using interfaces). I'm going with a pure-plug-in approach where everything (even the main View) is a plug-in. I might also use an Event Bus to let the various Presenters communicate agnostically.
Now my more specific question becomes, when a plug-in is about to contribute a View, how should I go about initializing the MVP triad and getting the View rendered into a parent container (outside the module). I probably need to let the View render itself into a container passed from outside and inject the View and Model (if needed) into the Presenter. An alternative would be for the View to return a component that can be placed inside a container, but this would be against my tentative ideal of keeping everything that is GUI-framework-specific inside View implementations. I prefer if the factory/glue mechanism can be framework-agnostic.
OK I'll stop yammering now and wait for some feedback, and then perhaps add more clarifications on where exactly I'm stuck...
I think the design pattern you're about is mediator.
I've written a javascript framework that consisted of a mediator.
It works like this:
You create a global instance of the
mediator,
register objects under
certain names,
use the mediator in your implementation to call methods
from registered objects within any of
the objects.
If something isn't present - no errors fly around.
If there are multiple instances - they all get the call.
This is the basic code for that:
(An extract of my code. I will make a jquery plugin including that in a while. If you're willing to use it push me to do it faster ;) )
function Mediator(){
function log(a){
try {console.log(a);} catch(e){
try {opera.postError(a);} catch(e){
//alert(a);
}
}
}
var __reg={}; // { "what": [object, ...], ... } //registers an object
//what=key that will identify, obj=an object
this._register = function(what,obj){
if(__reg[what]===undefined){
__reg[what]=[];
}
__reg[what].push(obj);
} //unregisters multiple objects and deletes a key
this._unregisterAll = function(what){
if(__reg[what]===undefined){log('Overlord:_unregisterAll - no registers'); return false; }
__reg[what]=null;
return true;
}
//unregisters a single element key
this._unregister = function(what){
if(this._countRegisters()==1){
__reg[what]=null;
return true;
} else { log('Overlord:_unregister - no registers'); return false; }
}
//unregisters last added element
this._unregisterLast = function(what){
var cnt=this._countRegisters(what);
if(cnt==0) { log('Overlord:_unregisterLast - no registers'); return false; }
if(cnt==1) {
__reg[what]=null;
return true;
} else {
__reg[what][cnt-1]=null;
return true;
}
}
//returns number of registered items
this._countRegisters = function(what){
try{
return __reg[what].length;
} catch(e){log(e);
return 0;
}
} //calls a method from all objects registered under 'what' with an array of parameters. returns true if there was at least one successful call
this._call = function(what,method,params){
var occured=false;
for(var i in __reg[what]) {
try {
__reg[what][i][method](params);
occured=true;
} catch(e) {log(e);//auto reakcja
}
}
return occured;
}
//does the call, but also returns an array of values retuurned by function
this._returnAll = function(what,method,params){
var re=[];
for(var i in __reg[what]){
try {
re.push(__reg[what][i][method](params));
} catch(e) {log(e);//auto reakcja
}
}
return re;
}
//runs a method from first object for a given key
this._returnFirst = function(what,method,params){
try {
return __reg[what][0][method](params);
} catch(e) {log(e);//auto reakcja
return null;
}
}
}
I guess that "keeping the GUI-framework-specific inside View implementations" is an overall application-level design choice, rather than an absolute must (at least when you think to "view implementation" as "plugin view implementation").
You could - for example - have a very thin view layer at plugin level, and implement a super-view layer within the parent that calls the plugins: thinking to a system of plugins that all add a column to a table, you could well have the bulk of the view code at parent level ("table") and have your plugins to just pass little more than raw data: you would avoid to repeat yourself and would make your code more flexible and maintainable.
On the other hand, if your plugins provide very different types of functionality that never interact directly (for example if they are the different subsystems of a flight simulator) you will want to keep everything that is related to views at plugin level, so that the parent object would not have to even know what a given plugin deals with, but just place it's returned value somewhere in the GUI.
Other factors that would probably influence your choice are the language and framework (if any) that you are using: in my personal experience, design patterns tend to be far from language-agnostic, as each language (and framework) has its own strengths / weaknesses which make certain choices obvious and certain others very difficult to implement.
Just my 2ยข to the discussion, anyhow! :)
For now, I'm going with this approach:
An extender (an extension implementation that a plug-in exposes) that is contributing a GUI component has a getTriad (will come up with a better name later) method that instantiates, wires and returns a MVP triad. The View has a getComponent method that renders and returns a framework-specific GUI element container that can be added to a parent container (the framework-specific details of which are encapsulated within the parent Views). I'm not letting the View render itself into a container but instead letting the parent View render the child into itself. I think this is better in terms of ensuring child Views don't directly mess with parent Views.