PDA

View Full Version : Observer Pattern



javaphantom
چهارشنبه 08 اسفند 1386, 14:43 عصر
کسی در مورد این pattern شناخیت داره و همچنین delegate ؟

javaphantom
پنج شنبه 09 اسفند 1386, 00:00 صبح
از تمامی دوستانی که کمکم کردن متشکرم. من خود بالاخره کشفش کردم که داستان این pattern چی هست؟ دوستدارم که یک توضیح مختصر هم در مورد آن بدم که اگر کسی احیانا خواست اونم بدونه.

یک رابطه یک به چند بین یک object با چند object دیگر بطوری که اگر در object اولی تغییری ایجاد شد در باقی object هام عمل update صورت بگیره.

تو محیطهای گرافیکی شاید بارها و بارها این عمل رو از طریق یک event و fire کردن باقی method ها در کلاسهای دیگر این کار رو انجام داده باشید. من برای اینکه بیشتر مفهموم کار رو بفمید یک مثال می زنم که فرض کنید ما می خواهیم در محیط text یا همان consul یک event بسازیم. سه تا objet داریم که وقتی روی اولی عملی صورت می گیره دوتای دیگر هم تغییرات روشون انجام می شه و خودشون رو بروز می کنند.
می شه اینطوری تعبیر کرد که ما یک objectی می خواهیم به نام Observer (مراقب) که مراقب این باشه که هنگامی که روی object مورد نظر تغییر انجام شد روی باقی تغییرات رو اعمال کنه. لازم به ذکر که Object ی که مد نظر است و قرار که تغییرات روی آن انجام بگیرد همان Object ی است که به آن Observable گفته می شود.
حال می ریم سراغ فایلهای کتابخانه جاوا یا همان API ها که ببینم جاوا چقدر به ما کمک می کنه؟ خوشبختانه جاوا فکر این کارو برای ما کرده بوده و ما طبق معمول از آن استفاده می کنیم.
java.util.Observable
java.util.Observer
همانطور که مشاهده می کنید Observable کلاسی است که قرار اون Object ی که می خواهیم روی آن تغییرات خودمان انجام بدیم باید از این کلاس ارث بگیره.
دو Method در این کلاس وجود داره یک به نام
public void setChanged()
public void notifyObservers()
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
این دو متدود بسیار کار حیاتی برای ما انجام میدهند. اولی خبر تغییر را می دهید و دومی اون مقداری که تغییر کرده که ممکن است خود یک Object باشد را به مراقب می فرستد.
این ور قضیه حالا نوبت Observer هست که در جاوا یک inteface ی به این نام وجود دارد و یک متدود با نام public void update(Observer obj,Object arg)
دارد که ما باید آن را پیاده ساز کنیم. obj از جنس کلاس Observer است در صورتی که بخواهیم تغییرات بروز رسانی بر روی object های دیگر باشد می توانیم از این argument استفاده کنیم و در صورتی که بخواهیم از object ی که از طرف متدود notifyObservers که در Object اصلی فرستاده شده تغییرات روی Object های دیگر صورت گیرد از این argument استفاده می کنیم.
مثال:
سه کلاس مجزا از هم وجود دارد اولی که همان کلاس Observable می باشد یک رشته می گیرد و دو کلاس دیگر بلافاصله یکی معکوس رشته را و دیگر طول رشته را به ترتیب در خروجی چاپ می کند.

به کد توجه کنید
import java.util.*;

public class MyObservable extends Observable {

private String str;

public void setStr(String str) {
this.str = str;
this.setChanged();
this.notifyObservers(this.str);
}

public static void main(String[] s) {
MyObservable myObservable = new MyObservable();
MyObserver myObserver = new MyObserver();
myObservable.addObserver(myObserver);
myObservable.setStr("babak");
}
}

class Invertor {

private String str;

public Invertor(String str) {
this.str = str;
}

public String getInvert() {
int len = this.str.length();
char[] ch1 = new char[len];
char[] ch2 = new char[len];
ch1 = str.toCharArray();
for (int i=0; i<len; i++) {
ch2[i] = ch1[(len-1)-i];
}
return String.valueOf(ch2);
}
}

class StrLength {

private int a;

public StrLength(int a) {
this.a = a;
}
public int getA() {
return this.a;
}
}

class MyObserver implements Observer {
public void update(Observable obj,Object arg) {
if (arg instanceof String) {
String str = (String) arg;
Invertor invertor = new Invertor(str);
StrLength strLength = new StrLength(str.length());
System.out.println(invertor.getInvert());
System.out.println(strLength.getA());
}
}


خروجی برنامه ما در آخر بصورت
kabab
5
خواهد بود. خوب شاید بگویید بجای این کارا دو متدود تعریف می کردم کار رو راه می انداخت دیگه این همه دنگ و فنگ برای چی؟ جواب اگر دقت کرده باشید من بصورت Objective عمل کردم و روی دو Object جداگانه تغییرات را داده ام. این یک مثال بسیار بسیار ساده است. خودتون اونو می تونید پیچیده تر کنید.

javaphantom
پنج شنبه 09 اسفند 1386, 10:05 صبح
خوب بازم خوبه یک نفر اینو خونده. حالا همانطر که گفتم می خوام مسئله رو پیچیده تر کنم. اگر در اولین پست دقت کنید خودم از خودم پرسیدم delegate چیست؟
جواب هنگامی که خود کلاسی که می خواهیم روی آن تغییرات اعمال کنیم از کلاس دیگری ارث گرفته باشد اون موقع از delegate pattern استفاده می کنیم. اگر دقت کرده باشید در مثال قبل کلاسی که obserable بود یعنی کلاس MyObservable از هیچ کلاسی ارث نگرفته بود که ما تونستیم خیلی راحت از کلاس Observable در جاوا ارث بگیرم حالا همین مثال بالا رو توی تغییر می دهیم که کلاس MyObserable مثلا از کلاس JFrame ارث گرفته و اون موقع حالا می ریم سراغ راه حل که همان delegate pattern است.

delegate pattern

نکته: در این pattern در کلاس Observable باید دو متدود ذکر شده Override بشوند.
public void clearChanged , public void setChanged

به دین صورت عمل می کنیم که یک کلاس دیگر به مجموعه ما اضافه می شه که دباره از کلاس Observable ارث می گیره که من اسم اونو می زارم MyNewObservable
به مثال توجه کنید. برنامه عملکرد مثال قبل رو داره.
[Code]import javax.swing.*;
import java.util.*;

public class MyObservable extends JFrame {

private String str;
private MyNewObservable newObservable;

public MyObservable() {
this.newObservable = new MyNewObservable();
}


public void setStr(String str) {
this.str = str;
this.newObservable.setChanged();
this.newObservable.notifyObservers(this.str);
}

public Observable getObservable() {
return this.newObservable;
}

public static void main(String[] s) {
MyObservable myObservable = new MyObservable();

MyObserver myObserver = new MyObserver();
myObservable.getObservable().addObserver(myObserve r);
myObservable.setStr("ali");
}
}

class MyNewObservable extends Observable {

@Override
public void setChanged() {
super.setChanged();
}
@Override
public void clearChanged() {
super.clearChanged();
}
}

class Invertor {

private String str;

public Invertor(String str) {
this.str = str;
}

public String getInvert() {
int len = this.str.length();
char[] ch1 = new char[len];
char[] ch2 = new char[len];
ch1 = str.toCharArray();
for (int i=0; i<len; i++) {
ch2[i] = ch1[(len-1)-i];
}
return String.valueOf(ch2);
}
}

class StrLength {

private int a;

public StrLength(int a) {
this.a = a;
}
public int getA() {
return this.a;
}
}

class MyObserver implements Observer {
public void update(Observable obj,Object arg) {
if (arg instanceof String) {
String str = (String) arg;
Invertor invertor = new Invertor(str);
StrLength strLength = new StrLength(str.length());
System.out.println(invertor.getInvert());
System.out.println(strLength.getA());
}
}
}[Code/]
همانطور که مشاهده کردید یک کلاس به مجموعه ما اضافه شد که می شه گفت همان delegate ما می باشد. و در کلاسی که می خواهیم روی آن تغییرات انجام بشه از این delegate که همان نماینده به حساب می آید استفاده کرده ایم.

kobari
شنبه 11 اسفند 1386, 12:55 عصر
با سلام
آیا از آبژکتهای Observable و Observer در پیاده سازی MVC میتوان استفاده کرد؟

zer0cool
شنبه 11 اسفند 1386, 13:37 عصر
http://en.wikipedia.org/wiki/Software_architecture
http://www.javapassion.com/j2ee/MVCPatternAndFrameworks.pdf