Encapsulation means that nothing is exposed that does not absolutely need to be exposed, right?
The way my menu navigation system is currently set up, there are MenuItems – which are just little shells that I can stuff graphics data into and make them into uniform width and height. Then there are MenuItemManagers, these hold a MenuItem and add/manager eventListeners (and their associated functions). Then there are MenuManagers, these take MenuItemManagers and build a menu out of them and then append and manage that menu to a given Sprite. Finally I have a MenuDecorator, which you shove a given MenuManager into and staple it to things, as needed.
But I realized it is probably breaking encapsulation to have MenuItemManagers managing what happens when a MenuItem is clicked – because they are then telling the GUI.Artist class what to paint. But if I instead take all of the behaviors I want from my menus (not to mention other graphics) and shove them into Artist… it will become huge.
So I am certain that there is a better ‘pattern’ or design method that I should be using. But being a nub I don’t seem to see one.
Actual code is this. Interfaces:
public interface AbstractMenuItem
{
function get label() : Sprite
function set label(v:Sprite) : void
function get width() : Number
function set width(v:Number) : void
function get height() : Number
function set height(v:Number) : void
}
public interface AbstractMenuItemManager
{
function execute() : void
function get menuItem() : AbstractMenuItem
function set menuItem(v:AbstractMenuItem) : void
}
public interface AbstractMenuManager
{
function apply(v:Sprite) : void
function hide() : void
function get menuItemList() : Vector.<AbstractMenuItemManager>
function set menuItemList(v:Vector.<AbstractMenuItemManager>) : void
function get spacing() : Number
function set spacing(v:Number) : void
}
Classes
public class ConcreteMenuItem implements AbstractMenuItem
{
private var _label:Sprite;
private var _width:Number;
private var _height:Number;
public function ConcreteMenuItem(label:Sprite, width:Number, height:Number)
{
_label = label;
_width = width;
_height = height;
_label.width = _width;
_label.height = _height;
}
public static function Blank() : ConcreteMenuItem
{
var label:Sprite = new Sprite();
return new ConcreteMenuItem(label, 30, 20);
}
/* INTERFACE GUI.managers.AbstractMenuItem */
public function get label():Sprite
{
return _label;
}
public function set label(value:Sprite):void
{
_label = value;
}
public function get width():Number
{
return _width;
}
public function set width(value:Number):void
{
_width = value;
}
public function get height():Number
{
return _height;
}
public function set height(value:Number):void
{
_height = value;
}
}
public class ConcreteMenuItemManager implements AbstractMenuItemManager
{
private var _menuItem:AbstractMenuItem;
public function ConcreteMenuItemManager(menuItem:AbstractMenuItem)
{
_menuItem = menuItem;
_menuItem.label.addEventListener(MouseEvent.CLICK, execute);
}
public static function Default(menuItem:AbstractMenuItem) : ConcreteMenuItemManager
{
return new ConcreteMenuItemManager(menuItem);
}
/* INTERFACE GUI.managers.AbstractMenuItemManager */
public function execute():void
{
// Call to GUI.Artist, tell it to draw a new GUI.schemes.screen.*
}
public function get menuItem():AbstractMenuItem
{
return _menuItem;
}
public function set menuItem(value:AbstractMenuItem):void
{
_menuItem = value;
}
}
public class DropDownMenuManager implements AbstractMenuManager
{
private var _menuItemList:Vector.<AbstractMenuItemManager>
private var _spacing:Number;
public function DropDownMenuManager(menuItemList:Vector.<AbstractMenuItemManager>, spacing:Number)
{
_menuItemList = menuItemList;
_spacing = spacing;
}
public static function Empty() : DropDownMenuManager
{
var menuItemList:Vector.<AbstractMenuItemManager> = new Vector.<AbstractMenuItemManager>();
var menuItemManager:AbstractMenuItemManager = ConcreteMenuItemManager.Default(ConcreteMenuItem.Blank());
return new DropDownMenuManager(menuItemList, 5);
}
/* INTERFACE GUI.managers.AbstractMenuManager */
public function apply(target:Sprite) : void
{
for (var i:int = 0; i < _menuItemList.length; i ++)
{
target.addChild(_menuItemList[i].menuItem.label);
_menuItemList[i].menuItem.label.x = target.x;
_menuItemList[i].menuItem.label.y = target.y + (i * _menuItemList[i].menuItem.height) + _spacing;
}
}
public function hide():void
{
for (var i:int = 0; i < menuItemList.length ; i++)
{
if (_menuItemList[i].menuItem.label.visible == true)
{
_menuItemList[i].menuItem.label.visible = false;
}
else
{
_menuItemList[i].menuItem.label.visible = true;
}
}
}
public function get menuItemList():Vector.<AbstractMenuItemManager>
{
return _menuItemList;
}
public function set menuItemList(value:Vector.<AbstractMenuItemManager>):void
{
_menuItemList = value;
}
public function get spacing() : Number
{
return _spacing;
}
public function set spacing(v:Number) : void
{
_spacing = spacing;
}
}
public class MenuDecorator
{
private var _menu:AbstractMenuManager;
public function MenuDecorator(menu:AbstractMenuManager)
{
_menu = menu;
}
public static function Empty() : MenuDecorator
{
return new MenuDecorator(DropDownMenuManager.Empty());
}
public function apply(target:Sprite) : void
{
_menu.apply(target);
}
}
Thanks very much for any help or insights you can provide.