org.puremvc.java.patterns.facade.Facade Maven / Gradle / Ivy
Show all versions of PureMVC Show documentation
//
// PureMVC Java Standard
//
// Copyright(c) 2019 Saad Shams
// Your reuse is governed by the Creative Commons Attribution 3.0 License
//
package org.puremvc.java.patterns.facade;
import org.puremvc.java.core.Controller;
import org.puremvc.java.core.Model;
import org.puremvc.java.core.View;
import org.puremvc.java.interfaces.*;
import org.puremvc.java.patterns.observer.Notification;
import java.util.function.Supplier;
/**
* A base Singleton IFacade
implementation.
*
* In PureMVC, the Facade
class assumes these
* responsibilities:
*
*
* - Initializing the
Model
, View
* and Controller
Singletons.
* - Providing all the methods defined by the
IModel,
* IView, & IController
interfaces.
* - Providing the ability to override the specific
Model
,
* View
and Controller
Singletons created.
* - Providing a single point of contact to the application for
* registering
Commands
and notifying Observers
*
*
* Example usage:
*
* {@code
* import org.puremvc.as3.patterns.facade.Facade;
*
* import com.me.myapp.model.*;
* import com.me.myapp.view.*;
* import com.me.myapp.controller.*;
*
* public class MyFacade extends Facade
* {
* // Notification constants. The Facade is the ideal
* // location for these constants, since any part
* // of the application participating in PureMVC
* // Observer Notification will know the Facade.
* public static final String GO_COMMAND = "go";
*
* // Override Singleton Factory method
* public synchronized static IFacade getInstance(Supplier facadeSupplier) {
* if(instance == null) instance = facadeSupplier.get();
* return instance;
* }
*
* // optional initialization hook for Facade
* public void initializeFacade() {
* super.initializeFacade();
* // do any special subclass initialization here
* }
*
* // optional initialization hook for Controller
* public void initializeController() {
* // call super to use the PureMVC Controller Singleton.
* super.initializeController();
*
* // Otherwise, if you're implmenting your own
* // IController, then instead do:
* // if ( controller != null ) return;
* // controller = MyAppController.getInstance(() -> new MyAppController());
*
* // do any special subclass initialization here
* // such as registering Commands
* registerCommand( GO_COMMAND, () -> new com.me.myapp.controller.GoCommand() )
* }
*
* // optional initialization hook for Model
* public void initializeModel() {
* // call super to use the PureMVC Model Singleton.
* super.initializeModel();
*
* // Otherwise, if you're implmenting your own
* // IModel, then instead do:
* // if ( model != null ) return;
* // model = MyAppModel.getInstance(() -> new MyAppModel());
*
* // do any special subclass initialization here
* // such as creating and registering Model proxys
* // that don't require a facade reference at
* // construction time, such as fixed type lists
* // that never need to send Notifications.
* registerProxy( new USStateNamesProxy() );
*
* // CAREFUL: Can't reference Facade instance in constructor
* // of new Proxys from here, since this step is part of
* // Facade construction! Usually, Proxys needing to send
* // notifications are registered elsewhere in the app
* // for this reason.
* }
*
* // optional initialization hook for View
* public void initializeView() {
* // call super to use the PureMVC View Singleton.
* super.initializeView();
*
* // Otherwise, if you're implmenting your own
* // IView, then instead do:
* // if ( view != null ) return;
* // view = MyAppView.getInstance(() -> new MyAppView());
*
* // do any special subclass initialization here
* // such as creating and registering Mediators
* // that do not need a Facade reference at construction
* // time.
* registerMediator( new LoginMediator() );
*
* // CAREFUL: Can't reference Facade instance in constructor
* // of new Mediators from here, since this is a step
* // in Facade construction! Usually, all Mediators need
* // receive notifications, and are registered elsewhere in
* // the app for this reason.
* }
* }
* }
*
*
* @see Model Model
* @see View View
* @see Controller Controller
* @see org.puremvc.java.patterns.observer.Notification Notification
* @see org.puremvc.java.patterns.mediator.Mediator Mediator
* @see org.puremvc.java.patterns.proxy.Proxy Proxy
* @see org.puremvc.java.patterns.command.SimpleCommand SimpleCommand
* @see org.puremvc.java.patterns.command.MacroCommand MacroCommand
*/
public class Facade implements IFacade {
// Private references to Model, View and Controlle
protected IController controller;
protected IModel model;
protected IView view;
// The Singleton Facade instance.
protected static IFacade instance;
// Message Constants
protected final String SINGLETON_MSG = "Facade Singleton already constructed!";
/**
* Constructor.
*
* This IFacade
implementation is a Singleton,
* so you should not call the constructor
* directly, but instead call the static Singleton
* Factory method Facade.getInstance()
*
* @throws Error Error if Singleton instance has already been constructed
*
*/
public Facade() {
if(instance != null) throw new Error(SINGLETON_MSG);
instance = this;
initializeFacade();
}
/**
* Initialize the Singleton Facade
instance.
*
* Called automatically by the constructor. Override in your
* subclass to do any subclass specific initializations. Be
* sure to call super.initializeFacade()
, though.
*/
protected void initializeFacade() {
initializeModel();
initializeController();
initializeView();
}
/**
* Facade Singleton Factory method
*
* @param facadeSupplier facade Supplier Function
* @return the Singleton instance of the Facade
*/
public synchronized static IFacade getInstance(Supplier facadeSupplier) {
if(instance == null) instance = facadeSupplier.get();
return instance;
}
/**
* Initialize the Controller
.
*
* Called by the initializeFacade
method.
* Override this method in your subclass of Facade
* if one or both of the following are true:
*
*
* - You wish to initialize a different
IController
.
* - You have
Commands
to register with the Controller
at startup.
*
*
* If you don't want to initialize a different IController
,
* call super.initializeController()
at the beginning of your
* method, then register Command
s.
*/
protected void initializeController() {
if(controller != null) return;
controller = Controller.getInstance(() -> new Controller());
}
/**
* Initialize the Model
.
*
* Called by the initializeFacade
method.
* Override this method in your subclass of Facade
* if one or both of the following are true:
*
*
* - You wish to initialize a different
IModel
.
* - You have
Proxy
s to register with the Model that do not
* retrieve a reference to the Facade at construction time.
*
*
* If you don't want to initialize a different IModel
,
* call super.initializeModel()
at the beginning of your
* method, then register Proxy
s.
*
* Note: This method is rarely overridden; in practice you are more
* likely to use a Command
to create and register Proxy
s
* with the Model
, since Proxy
s with mutable data will likely
* need to send INotification
s and thus will likely want to fetch a reference to
* the Facade
during their construction.
*/
protected void initializeModel() {
if(model != null) return;
model = Model.getInstance(() -> new Model());
}
/**
* Initialize the View
.
*
* Called by the initializeFacade
method.
* Override this method in your subclass of Facade
* if one or both of the following are true:
*
*
* - You wish to initialize a different
IView
.
* - You have
Observers
to register with the View
*
*
* If you don't want to initialize a different IView
,
* call super.initializeView()
at the beginning of your
* method, then register IMediator
instances.
*
* Note: This method is rarely overridden; in practice you are more
* likely to use a Command
to create and register Mediator
s
* with the View
, since IMediator
instances will need to send
* INotification
s and thus will likely want to fetch a reference
* to the Facade
during their construction.
*/
protected void initializeView() {
if(view != null) return;
view = View.getInstance(() -> new View());
}
/**
* Register an ICommand
with the Controller
by Notification name.
*
* @param notificationName the name of the INotification
to associate the ICommand
with
* @param commandSupplier a reference to the Supplier Function of the ICommand
*/
public void registerCommand(String notificationName, Supplier commandSupplier) {
controller.registerCommand(notificationName, commandSupplier);
}
/**
* Remove a previously registered ICommand
to INotification
mapping from the Controller.
*
* @param notificationName the name of the INotification
to remove the ICommand
mapping for
*/
public void removeCommand(String notificationName) {
controller.removeCommand(notificationName);
}
/**
* Check if a Command is registered for a given Notification
*
* @param notificationName notification name
* @return whether a Command is currently registered for the given notificationName
.
*/
public boolean hasCommand(String notificationName) {
return controller.hasCommand(notificationName);
}
/**
* Register an IProxy
with the Model
by name.
*
* @param proxy the IProxy
instance to be registered with the Model
.
*/
public void registerProxy(IProxy proxy) {
model.registerProxy(proxy);
}
/**
* Retrieve an IProxy
from the Model
by name.
*
* @param proxyName the name of the proxy to be retrieved.
* @return the IProxy
instance previously registered with the given proxyName
.
*/
public IProxy retrieveProxy(String proxyName) {
return model.retrieveProxy(proxyName);
}
/**
* Remove an IProxy
from the Model
by name.
*
* @param proxyName the IProxy
to remove from the Model
.
* @return the IProxy
that was removed from the Model
*/
public IProxy removeProxy(String proxyName) {
return model.removeProxy(proxyName);
}
/**
* Check if a Proxy is registered
*
* @param proxyName proxy name
* @return whether a Proxy is currently registered with the given proxyName
.
*/
public boolean hasProxy(String proxyName) {
return model.hasProxy(proxyName);
}
/**
* Register a IMediator
with the View
.
*
* @param mediator a reference to the IMediator
*/
public void registerMediator(IMediator mediator) {
view.registerMediator(mediator);
}
/**
* Retrieve an IMediator
from the View
.
*
* @param mediatorName mediator name
* @return the IMediator
previously registered with the given mediatorName
.
*/
public IMediator retrieveMediator(String mediatorName) {
return view.retrieveMediator(mediatorName);
}
/**
* Remove an IMediator
from the View
.
*
* @param mediatorName name of the IMediator
to be removed.
* @return the IMediator
that was removed from the View
*/
public IMediator removeMediator(String mediatorName) {
return view.removeMediator(mediatorName);
}
/**
* Check if a Mediator is registered or not
*
* @param mediatorName mediator name
* @return whether a Mediator is registered with the given mediatorName
.
*/
public boolean hasMediator(String mediatorName) {
return view.hasMediator(mediatorName);
}
/**
* Create and send an INotification
.
*
* Keeps us from having to construct new notification
* instances in our implementation code.
*
* @param notificationName the name of the notiification to send
* @param body the body of the notification
* @param type the type of the notification
*/
public void sendNotification(String notificationName, Object body, String type) {
notifyObservers(new Notification(notificationName, body, type));
}
/**
* Create and send an INotification
.
*
* Keeps us from having to construct new notification
* instances in our implementation code.
*
* @param notificationName the name of the notiification to send
* @param body the body of the notification
*/
public void sendNotification(String notificationName, Object body) {
sendNotification(notificationName, body, null);
}
/**
* Create and send an INotification
.
*
* Keeps us from having to construct new notification
* instances in our implementation code.
*
* @param notificationName the name of the notiification to send
*/
public void sendNotification(String notificationName) {
sendNotification(notificationName, null, null);
}
/**
* Notify Observer
s.
*
* This method is left public mostly for backward
* compatibility, and to allow you to send custom
* notification classes using the facade.
*
* Usually you should just call sendNotification
* and pass the parameters, never having to
* construct the notification yourself.
*
* @param notification the INotification
to have the View
notify Observers
of.
*/
public void notifyObservers(INotification notification) {
view.notifyObservers(notification);
}
}