MVC
Sederhana untuk Pemula
Kali
ini saya jelaskan tentang cara membuat “struktur”
MVC sederhana untuk menulis kode yang maintainable dengan
memecah kode menjadi beberapa bagian berdasarkan fungsinya
( separation of concerns ).
Saya
anggap Anda sudah cukup mengetahui dasar OOP dan
mempraktekkannya, jadi saya nggak perlu
menjelaskan lagi apa itu class, instance, static, getter/setter,
dsb. Saya juga nggak menjelaskan apa itu custom events dan
bagaimana cara membuat & menggunakannya karena
sudah pernah saya jelaskan dalam artikel yang lain. Selain itu,
Anda juga harus mengerti cara mendefinisikan & membuat
custom class untuk objek di library.
Di
sini saya membuat aplikasi sederhana berupa sebuah
kotak yang posisinya bisa dikontrol oleh 4 tombol seperti
berikut:
[kml_flashembed
fversion=“9.0.124″
movie=“http://masputih.com/files/SimpleMVC.swf”
targetclass=“flashmovie” publishmethod=“static” width=“320”
height=“400”]
[/kml_flashembed]
Design
Patterns
Design
patterns (DP) adalah sekumpulan solusi generik untuk
masalah-masalah yang umum ditemui oleh para developer dalam membuat
aplikasi. Pattern berarti pola, artinya DP bukan berupa
kode, tetapi berupa panduan yang implementasinya
terserah developer yang menggunakannya.
Info
yang lebih lengkap bisa Anda baca di wikipedia.
Model-View-Controller
MVC
adalah meta-pattern , artinya MVC bukan merupakan pattern yang
berdiri sendiri tapi merupakan kumpulan dari beberapa
pattern & dalam buku Head First Design Patterns , MVC
dimasukkan dalam kelompok compound-pattern.
Pada
prinsipnya, implementasi MVC membagi kode ke
dalam 3 bagian yaitu:
Model
sebagai sumber data
View
sebagai representasi data dan user interface
Controller
yang berfungsi sebagai “otak” atau business logic yang
memproses user input dan meng–update Model dan View ( kalau
diperlukan ).
Apa
keuntungan MVC ?
Sekilas
MVC kelihatannya merepotkan karena kita harus menulis kode lebih
banyak tapi keuntungannya adalah kode kita lebih
maintainable karena kita bisa mengubah salah satu bagian
tanpa harus mengubah bagian yang lain. Sebagai contoh,
misalnya kita membuat aplikasi A yang memproses data
berformat XML namun kemudian kita diharuskan menggunakan
data berformat JSON. Dalam kasus seperti ini, kita cukup
mengubah Model tanpa harus mengubah bagian yang lain.
MVC
juga mempermudah debugging karena kita bisa
memperkirakan bagian mana yang bermasalah tanpa harus
membongkar seluruh kode yang sudah kita buat.
Jadi
secara umum, keuntungan MVC jauh lebih besar daripada kerepotan
yang ditimbulkannya. Di samping itu, kalo Anda
nggak mau repot menulis berbaris-baris kode, mungkin menjadi
programmer bukan profesi yang cocok buat Anda & sebaiknya
Anda cari pekerjaan lain.
Struktur dasar
Di
dalam direktori projek, saya buat 4 buah sub-direktori/package
seperti gambar di bawah ini.
Direktori
Project di FlashDevelop
Berikut
ini diagram dari aplikasi yang saya buat.
Class
Diagram
View
& ViewEvent
Package
view berisi class yang berhubungan dengan library symbol
yaitu MainView dan ArrowButton. MainView bertugas menyiarkan
ViewEvent jika salah satu tombol navigasi diklik. Event ini
ditangkap oleh Controller yang kemudian meng-update Model.
Selain itu MainView juga menampilkan posisi kotak kuning.
Kenapa
saya membuat ViewEvent dan nggak membuat Controller yang
langsung mendengarkan MouseEvent.CLICK yang disiarkan oleh
tombol kontrol ? Karena saya ingin meminimalkan coupling
antara MainView dan Controller sehingga jika saya perlu mengubah
View, selama event yang disiarkannya tetap bertipe
ViewEvent, saya nggak perlu mengubah Controller.
[js]
package
simplemvc.view {
import
flash.display.MovieClip;
import
flash.events.Event;
import
flash.events.MouseEvent;
import
flash.geom.Point;
import
flash.text.TextField;
import
simplemvc.events.ViewEvent;
import
simplemvc.model.Model;
/**
*
…
*
@author Muhammad iqbal
*/
public
class MainView extends MovieClip {
//timeline
objects
public
var hero:MovieClip;
public
var board:MovieClip;
public
var leftBtn:ArrowButton;
public
var rightBtn:ArrowButton;
public
var upBtn:ArrowButton;
public
var downBtn:ArrowButton;
public
var positionTxt:TextField;
private
var _model:Model = Model.getInstance();
//———————————————————–
INIT
public
function MainView() {
initButtonListener();
_model.addEventListener(Event.CHANGE,
modelListener);
}
private
function initButtonListener():void {
var
i:int = 0;
while
(i < numChildren) {
if
(this.getChildAt(i) is ArrowButton) {
this.getChildAt(i).addEventListener(MouseEvent.CLICK,
buttonListener);
}
i++;
}
}
private
function buttonListener(e:MouseEvent):void {
switch(e.currentTarget)
{
case
leftBtn:
dispatchEvent(new
ViewEvent(ViewEvent.MOVE_LEFT));
break;
case
rightBtn:
dispatchEvent(new
ViewEvent(ViewEvent.MOVE_RIGHT));
break;
case
upBtn:
dispatchEvent(new
ViewEvent(ViewEvent.MOVE_UP));
break;
case
downBtn:
dispatchEvent(new
ViewEvent(ViewEvent.MOVE_DOWN));
break;
}
}
private
function modelListener(e:Event):void {
hero.x
= _model.heroPos.x;
hero.y
= _model.heroPos.y;
positionTxt.text
= _model.heroPos.toString();
}
}
}
[/js]
[js]
package
simplemvc.events {
import
flash.events.Event;
/**
*
…
*
@author Muhammad iqbal
*/
public
class ViewEvent extends Event {
public
static const MOVE_LEFT:String = “moveLeft”;
public
static const MOVE_RIGHT:String = “moveRight”;
public
static const MOVE_UP:String = “moveUp”;
public
static const MOVE_DOWN:String = “moveDown”;
public
function ViewEvent(type:String) {
super(type,
true);
}
override
public function clone():Event {
return
new ViewEvent(type);
}
override
public function toString():String {
return
formatToString(“ViewEvent”, “type”, “bubbles”,
“cancelable”, “eventPhase”);
}
}
}
[/js]
Model
Model
adalah bagian dimana data berada. Untuk data yang bersifat
global, kita bisa mengimplementasikan Singleton
pattern. Singleton class hanya bisa diinstansiasi satu
kali selama aplikasi berjalan. Umumnya, referensi ke
instance dari Singleton diakses dengan memanggil static
method getInstance().
Kalo
kita bekerja bersama developer lain, kita bisa mencegah
mereka menginstansiasi/membuat objek Singleton dengan menggunakan
inner class yaitu class yang didefinisikan diluar package tetapi
masih di dalam file yang sama.
Model
saya gunakan untuk menyimpan data berupa posisi kotak kuning.
Pada saat data berubah, Model akan men-dispatch Event.CHANGE
yang didengarkan oleh MainView yang kemudian meng-update posisi kotak
kuning.
[js]
package
simplemvc.model {
import
flash.events.Event;
import
flash.events.EventDispatcher;
import
flash.geom.Point;
/**
*
…
*
@author Muhammad iqbal
*/
public
class Model extends EventDispatcher {
public
var heroHeight:Number = 0;
public
var heroWidth:Number = 0;
//———————————————————–
HERO VELOCITY
public
var vx:Number = 10;
public
var vy:Number = 10;
//———————————————————–
HERO POSITION
private
var _heroPos:Point = new Point();
public
function get heroPos():Point { return _heroPos; }
public
function set heroPos(value:Point):void {
if
(value.x >= heroBounds.xMin && value.x <=
heroBounds.xMax &&
value.y
>= heroBounds.yMin && value.y <= heroBounds.yMax ) {
_heroPos
= value;
dispatchEvent(new
Event(Event.CHANGE));
}
}
public
function moveDown():void {
heroPos
= new Point(heroPos.x, heroPos.y + vy);
}
public
function moveUp():void {
heroPos
= new Point(heroPos.x, heroPos.y — vy);
}
public
function moveLeft():void {
heroPos
= new Point(heroPos.x — vx, heroPos.y);
}
public
function moveRight():void {
heroPos
= new Point(heroPos.x + vx, heroPos.y );
}
//———————————————————–
HERO BOUNDS
private
var _heroBounds:Object = {};
public
function get heroBounds():Object { return _heroBounds; }
public
function set heroBounds(value:Object):void {
//trace(value);
_heroBounds.xMin
= value.x;
_heroBounds.xMax
= value.x + value.width — heroWidth;
_heroBounds.yMin
= value.y;
_heroBounds.yMax
= value.y + value.height — heroHeight;
}
//———————————————————–
INIT
private
static var _instance:Model;
public
function Model(enf:SingletonEnforcer) {}
public
static function getInstance():Model {
if
(_instance == null) _instance = new Model(new SingletonEnforcer());
return
_instance;
}
}
}
//INNER
CLASS
class
SingletonEnforcer { };
[/js]
Controller
Controller
mendengarkan ViewEvent yang disiarkan oleh MainView dan
meng-update Model berdasarkan event tersebut.
[js]
package
simplemvc.controller {
import
flash.events.Event;
import
flash.geom.Point;
import
simplemvc.model.Model;
import
simplemvc.view.*;
import
simplemvc.events.*;
/**
*
…
*
@author Muhammad iqbal
*/
public
class Controller {
private
var _model:Model = Model.getInstance();
private
var _view:MainView;
//———————————————————–
INIT
public
function Controller(view:MainView) {
_view
= view;
_model.heroHeight
= _view.hero.height;
_model.heroWidth
= _view.hero.width;
_model.heroBounds
= _view.board.getBounds(_view);
_view.addEventListener(ViewEvent.MOVE_DOWN,
viewListener);
_view.addEventListener(ViewEvent.MOVE_UP,
viewListener);
_view.addEventListener(ViewEvent.MOVE_LEFT,
viewListener);
_view.addEventListener(ViewEvent.MOVE_RIGHT,
viewListener);
}
public
function startUp():void {
_model.heroPos
= new Point(0, 0);
}
private
function viewListener(e:ViewEvent):void {
switch(e.type)
{
case
ViewEvent.MOVE_DOWN:
_model.moveDown();
break;
case
ViewEvent.MOVE_LEFT:
_model.moveLeft();
break;
case
ViewEvent.MOVE_RIGHT:
_model.moveRight();
break;
case
ViewEvent.MOVE_UP:
_model.moveUp();
break;
}
}
}
}
[/js]
Document/Main
Class
[js]
package
{
import
flash.display.MovieClip;
import
simplemvc.controller.Controller;
import
simplemvc.view.MainView;
/**
*
…
*
@author Anggie Bratadinata
*/
public
class Main extends MovieClip {
public
var mainView:MainView;
public
var controller:Controller;
public
function Main() {
controller
= new Controller(mainView);
controller.startUp();
}
}
}
[/js]
Seperti
Anda lihat, menulis kode dengan struktur MVC nggak terlalu
sulit, hanya sedikit ngerepotin.
0 comments:
Post a Comment