• djogzs
    Terima kasih sudah berkunjung-xD

MVC Sederhana untuk Pemula

Tuesday, July 3, 2012

MVC Sederhana untuk Pemula


Kali ini saya jelaskan ten­tang cara mem­buat “struk­tur” MVC seder­hana untuk menulis kode yang main­tainable dengan memecah kode men­jadi beberapa bagian ber­dasarkan fung­sinya ( separation of con­cerns ).

Saya ang­gap Anda sudah cukup meng­etahui dasar OOP dan memp­rak­tek­kan­nya, jadi saya nggak perlu men­jelaskan lagi apa itu class, instance, static, getter/setter, dsb. Saya juga nggak men­jelaskan apa itu cus­tom events dan bagaimana cara mem­buat & meng­gunakan­nya karena sudah per­nah saya jelaskan dalam artikel yang lain. Selain itu, Anda juga harus meng­erti cara men­definisikan & mem­buat cus­tom class untuk objek di library.



Di sini saya mem­buat aplikasi seder­hana ber­upa sebuah kotak yang posisinya bisa dikon­trol oleh 4 tom­bol 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 Pat­terns

Design pat­terns (DP) adalah sekum­pulan solusi generik untuk masalah-masalah yang umum ditemui oleh para developer dalam mem­buat aplikasi. Pat­tern ber­arti pola, artinya DP bukan ber­upa kode, tetapi ber­upa pan­duan yang implemen­tasinya ter­serah developer yang menggunakannya.

Info yang lebih leng­kap bisa Anda baca di wikipedia.

Model-View-Controller

MVC adalah meta-pattern , artinya MVC bukan merupakan pat­tern yang ber­diri sen­diri tapi merupakan kum­pulan dari beberapa pat­tern & dalam buku Head First Design Pat­terns , MVC dimasukkan dalam kelom­pok compound-pattern.

Pada prin­sip­nya, implemen­tasi MVC mem­bagi kode ke dalam 3 bagian yaitu:

Model seba­gai sum­ber data
View seba­gai rep­resen­tasi data dan user inter­face
Con­troller yang ber­fungsi seba­gai “otak” atau business logic yang memp­roses user input dan meng–update Model dan View ( kalau diperlukan ).
Apa keun­tungan MVC ?

Sekilas MVC kelihatan­nya merepotkan karena kita harus menulis kode lebih banyak tapi keun­tungan­nya adalah kode kita lebih main­tainable karena kita bisa meng­ubah salah satu bagian tanpa harus meng­ubah bagian yang lain. Seba­gai con­toh, misal­nya kita mem­buat aplikasi A yang memp­roses data ber­for­mat XML namun kemudian kita diharuskan meng­gunakan data ber­for­mat JSON. Dalam kasus seperti ini, kita cukup meng­ubah Model tanpa harus meng­ubah bagian yang lain.

MVC juga mem­per­mudah debug­ging karena kita bisa mem­per­kirakan bagian mana yang ber­masalah tanpa harus mem­bong­kar seluruh kode yang sudah kita buat.

Jadi secara umum, keun­tungan MVC jauh lebih besar daripada kerepotan yang ditim­bul­kan­nya. Di sam­ping itu, kalo Anda nggak mau repot menulis berbaris-baris kode, mung­kin men­jadi program­mer bukan profesi yang cocok buat Anda & sebaik­nya Anda cari peker­jaan lain.

Struk­tur dasar

Di dalam direk­tori projek, saya buat 4 buah sub-direktori/pac­kage seperti gam­bar di bawah ini.


Direk­tori Project di FlashDevelop

Ber­ikut ini diagram dari aplikasi yang saya buat.


Class Diagram

View & ViewEvent

Pac­kage view ber­isi class yang ber­hubungan dengan library sym­bol yaitu MainView dan ArrowButton. MainView ber­tugas menyiarkan ViewEvent jika salah satu tom­bol navigasi diklik. Event ini ditang­kap oleh Controller yang kemudian meng-update Model. Selain itu MainView juga menam­pilkan posisi kotak kuning.

Kenapa saya mem­buat ViewEvent dan nggak mem­buat Controller yang lang­sung men­dengarkan MouseEvent.CLICK yang disiarkan oleh tom­bol kon­trol ? Karena saya ingin meminimalkan coupling antara MainView dan Controller sehingga jika saya perlu meng­ubah View, selama event yang disiar­kan­nya tetap ber­tipe ViewEvent, saya nggak perlu meng­ubah Controller.

[js]
pac­kage 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 Main­View 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 fun­ction MainView() {

initButtonListener();

_model.addEventListener(Event.CHANGE, modelListener);

}

private fun­ction initButtonListener():void {
var i:int = 0;
while (i < numChildren) {
if (this.getChildAt(i) is ArrowBut­ton) {
this.getChildAt(i).addEventListener(MouseEvent.CLICK, but­tonLis­tener);
}
i++;
}

}

private fun­ction buttonListener(e:MouseEvent):void {

switch(e.currentTarget) {
case lef­tBtn:
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 fun­ction modelListener(e:Event):void {

hero.x = _model.heroPos.x;
hero.y = _model.heroPos.y;

positionTxt.text = _model.heroPos.toString();

}

}

}

[/js]

[js]
pac­kage 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 fun­ction ViewEvent(type:String) {
super(type, true);
}

over­ride public fun­ction clone():Event {
return new ViewEvent(type);
}

over­ride public fun­ction toString():String {
return formatToString(“ViewEvent”, “type”, “bubbles”, “can­celable”, “even­tPhase”);
}

}

}

[/js]

Model

Model adalah bagian dimana data ber­ada. Untuk data yang ber­sifat global, kita bisa meng­im­plemen­tasikan Singleton pat­tern. Singleton class hanya bisa diin­stan­siasi satu kali selama aplikasi ber­jalan. Umum­nya, referensi ke instance dari Singleton diak­ses dengan memang­gil static method getInstance().

Kalo kita bekerja ber­sama developer lain, kita bisa men­cegah mereka menginstansiasi/membuat objek Singleton dengan meng­gunakan inner class yaitu class yang didefinisikan diluar pac­kage tetapi masih di dalam file yang sama.

Model saya gunakan untuk menyimpan data ber­upa posisi kotak kuning. Pada saat data ber­ubah, Model akan men-dispatch Event.CHANGE yang didengarkan oleh MainView yang kemudian meng-update posisi kotak kuning.

[js]
pac­kage 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 fun­ction get heroPos():Point { return _heroPos; }

public fun­ction 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 fun­ction moveDown():void {
heroPos = new Point(heroPos.x, heroPos.y + vy);
}

public fun­ction moveUp():void {
heroPos = new Point(heroPos.x, heroPos.y — vy);
}

public fun­ction moveLeft():void {
heroPos = new Point(heroPos.x — vx, heroPos.y);
}

public fun­ction moveRight():void {
heroPos = new Point(heroPos.x + vx, heroPos.y );
}

//———————————————————– HERO BOUNDS

private var _heroBounds:Object = {};

public fun­ction get heroBounds():Object { return _heroBounds; }

public fun­ction 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 fun­ction Model(enf:SingletonEnforcer) {}
public static fun­ction getInstance():Model {
if (_instance == null) _instance = new Model(new SingletonEn­for­cer());
return _instance;
}

}

}
//INNER CLASS
class SingletonEnforcer { };

[/js]

Con­troller

Controller men­dengarkan ViewEvent yang disiarkan oleh MainView dan meng-update Model ber­dasarkan event tersebut.

[js]
pac­kage 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 fun­ction 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, viewLis­tener);
_view.addEventListener(ViewEvent.MOVE_UP, viewLis­tener);
_view.addEventListener(ViewEvent.MOVE_LEFT, viewLis­tener);
_view.addEventListener(ViewEvent.MOVE_RIGHT, viewListener);

}

public fun­ction startUp():void {
_model.heroPos = new Point(0, 0);
}

private fun­ction 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 Ang­gie Bratadinata
*/
public class Main extends MovieClip {

public var mainView:MainView;
public var controller:Controller;

public fun­ction Main() {
con­troller = new Controller(mainView);
controller.startUp();
}

}

}

[/js]

Seperti Anda lihat, menulis kode dengan struk­tur MVC nggak ter­lalu sulit, hanya sedikit ngerepotin.

0 comments:

Post a Comment

pasang