Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

Παρουσίαση με Ετικέτες

Όλες οι Ετικέτε... » tutorial   (RSS)

A note to self: Silverlight DataBinding awesomeness μέσα από Expression Blend, XAML και κώδικα

 Post-it notes for la patilla

 

Το πιο δυνατό στοιχείο του Silverlight είναι η εκφραστικότητα των data binding μηχανισμών του με όλες τις μορφές που μας το παρέχει. Separation of concerns, animations, visual states, MVVM, αλληλένδετα controls και πολλά ακόμα “βαριά” ή ελαφρά features οφείλουν την ύπαρξή τους στο Data Binding.

Τι είναι Data Binding;

Data Binding είναι η σύνδεση μεταξύ μίας πηγής δεδομένων και ενός προορισμού.

Στο silverlight η πηγή είναι ένα CLR αντικείμενο που διατηρεί, ανανεώνει, κτλ πληροφορία (ένα object συγκεκριμένου τύπου) και ο προορισμός είναι ένα SL control. Όταν όλα είναι δηλωμένα σωστά, τότε όταν το CLR αντικείμενο αλλάζει με κάποιο τρόπο, μπορει να παρέχει ειδοποιήσεις για το τι άλλαξε, ποιό CLR property δηλαδή και όσα SL controls (elements) έχουν γίνει databound εκεί, μπορούν να ανανεώσουν τις τιμές τους. Η πρώτη επαφή με το DataBinding συνήθως έρχεται μέσα από τη XAML.

Through Expression Blend

Ας δούμε ένα μικρό παράδειγμα πριν πούμε τα βασικά του DataBinding και μάλιστα μέσα από το Blend, , ώστε να το γνωρίσουμε και αυτό το πολύτιμο εργαλείο καλύτερα. Έστω ότι θέλω να φτιάξω μία εφαρμογή για rating ταινιών (SL-IMDB δηλαδή), γρήγορα, τακτοποιημένα, μέσα από το Blend. Θέλω τα δεδομένα μου στην οθόνη να απεικονίζονται με βάση κάποιο συγκεκριμένο CLR Object, το οποίο μου έρχεται από τη βάση δεδομένων. Φτιάχνω ένα νέο silverlight project και για αρχή το object μου. Add New Item και φτιάχνω μία κλάση movie, που την γράφω κατευθείαν μέσα από το Blend έχοντας κανονικά Intellisense. Όχι ότι θα αναπτύξω κώδικα για το SL project στο Blend, αλλά μας δίνεται αυτή η ευκολία, χωρίς να χρειαζόμαστε πάντα και VS Studio και Expression Blend αναγκαστικά για κάποια μικροαλλαγή. Στη συνέχεια φτιάχνω μία καινούρια Page, ας χρησιμοποιήσουμε την ήδη υπάρχουσα MainPage.xaml. Ας δημιουργήσουμε και Sample Data στα γρήγορα για να βλέπουμε τη φτιάχνουμε.

Πηγαίνουμε δεξιά, πατάμε τη καρτέλα Data και Create διαλέγοντας την κλάση που θα κάνουμε populate με τυχαία (τα κλασσικά λατινικά) δεδομένα.

image

imageimageΜετά κάνοντας Drag το Movie στο Layout Root, έχω στο DataContext μου τυχαία δεδομένα, να κοιτάζω. Έχω τρεις περιοχές στην παραπάνω εικόνα. Έναν τίτλο (πάνω αριστερά), rating, περιγραφή και μία εικόνα, κάτω από τον τίτλο, που δεν έγινε populate με sample data, καθώς ο τύπος είναι Uri και το Sample Data από μόνο του δεν παρήγαγε κάποιο Url για να δείξει. Έχοντας το DataContext μου για τη σελίδα ορισμένο σε ένα Movie CLR object, το Expression Blend μπορεί να μου δώσει την δυνατότητα να επιλέξω γραφικά ποιό control θα παίρνει από που, δεδομένα. Επιλέγω το Textbox λοιπόν και πατάω δεξιά στα common properties το Text. Τι θέλω; Να γεμίζει με δεδομένα από την κλάση μου, οπότε πηγαίνω στα advanced properties και επιλέγω το DataContext tab. Εκεί θα βρω τα properties από τη Movie Class μου, και επιλέγω το Title. Κάνω το ίδιο και για τα υπόλοιπα. Στο Rating όμως θέλω και κάτι ακόμα. Όπως το Imdb. Να δείχνει μεν το μέσο όρο αλλά να μπορώ και εγώ να επιλέξω τιμή που αργότερα (θα συνυπολογιστεί στο ολικό μέσο όρο). Οπότε έχουμε μία διαφοροποίηση. Δεν θέλω η τιμή του να έρχεται στο UI μόνο, αλλά να επιλέξω κάτι εγώ και να κληθεί ο setter στο αντίστοιχο property επίσης. Επιλέγουμε λοιπόν το mode και το θέτουμε σε Two Way, όπως φαίνεται στο screenshot. Το μόνο που μένει για το demo μας είναι να θέσουμε με κάποιο τρόπο το DataContext της σελίδας μας σε ένα νέο Movie instance. Αυτό συνήθως το διαχειρίζεται το MVVM καλά, αλλά για την περίσταση μας αρκεί στο construction της σελίδας να γράψουμε ένα

 

public MainPage()         {             // Required to initialize variables             InitializeComponent();             this.DataContext = new Movie             {                 Title = "The Hustler",                 Rating = 0.85,                 Description = "The Hustler is a 1961 American drama film directed by Robert Rossen from the 1959 novel of the same name he and Sidney Carroll adapted for the screen. It tells the story of small-time pool hustler Fast Eddie. Felson and his desire to prove himself the best player in the country by beating legendary pool player Minnesota Fats. After initially losing to Fats and getting involved with unscrupulous manager Bert Gordon, Eddie returns to beat Fats, but only after paying a terrible personal price. The film was shot on location in New York City. It stars Paul Newman as Eddie Felson, Jackie Gleason as Minnesota Fats, Piper Laurie as Sarah, and George C. Scott as Bert.",                 Poster = new Uri("http://i23.photobucket.com/albums/b352/grnemo/the-hustler-paul-newman-jackie-gleason1.jpg")             };         }

Το αποτέλεσμα είναι το παρακάτω, έχοντας πάρει τις τιμές για το Silverlight application μας από κάποιο object του model μας. Ανοίγοντας το project από το Visual Studio, μας ζητάει να ενεργοποιήσουμε στο web config το debugging. Ανοίγουμε την κλάση μας, βαζουμε ένα breakpoint στον setter στο Rating και πατάμε τη δική μας βαθμολογία. Βλέπουμε ότι καλείται ο setter με τη νέα τιμή.

image  image

Έστω ότι θέλω να έχω μία λίστα από ταινίες, ή αντικείμενα και να βλέπω την περιγραφή τους σε παρόμοιο layout. Το DataBinding από την έκδοση 3 του silverlight έχει ένα feature με το οποίο μπορούμε να συνδέσουμε, controls μεταξύ τους, με καταγραφή μόνο των controls που έχουν κάποια τιμή που μας ενδιαφέρει. Θέλουμε λοιπόν, όποτε αλλάζουμε το SelectedItem από τη λίστα, να αλλάζουμε properties σε άλλα controls. Για τις ανάγκες του demo, έφτιαξα ένα demo datasource από το ίδιο menu όπως και πριν (ορίζοντας τον τύπο των dummy δεδομένων μου, ακόμα και της εικόνας), έφτιαξα ένα ListBox και έκανα drag and drop το property name, από το Data Context παράθυρο στο ListBox που ήθελα, όπως φαίνεται στην εικόνα. Στα επιμέρους controls, έβαλα bindings από το Expression Blend, με το ίδιο τρόπο. Επιλέγοντας την τελίτσα δεξιά από το property του κάθε control στο common properties, διαλέγοντας αυτή τη φορά, το tab, Element Property, επιλέγοντας το scene element που με ενδιαφέρει και ορίζοντας το property στο custom path expression. To αποτέλεσμα φαίνεται στην παρακάτω εικόνα.

imageimage

Revealing XAML

Αφού είχαμε το πρώτο μας Demo στο expression blend, ας δούμε τι γίνεται στη XAML που παράγεται από κάτω. Η αλήθεια είναι ότι αρκετές φορές όταν σχεδιάζεται μία σελίδα θα χρειαστεί να γράψετε αυτούσια XAML με το χέρι. Η XAML ορίζει τo λεγόμενo binding markup extension, όπου για το Silverlight (στην τρέχουσα version, 4)  είναι ένα από τα, Binding, StaticResource, TemplateBinding, RelativeSource. Εμάς μας ενδιαφέρει εκείνο το extension που λέγεται binding. Όπως κάθε extension έτσι και το Binding ορίζεται μέσα σε “{” “}” και προσδιορίζει το binding expression μεταξύ εκείνου του Dependency property και του property κάποιου CLR Object. Στην εφαρμογή μας ο τίτλος, η περιγραφή, το poster και το rating έχουν την παρακάτω απεικόνιση σε XAML:

      <TextBlock Text="{Binding Title}" …. />       <TextBlock Text="{Binding Description}" …. />       <Image>                 <Image.Source>                     <BitmapImage UriSource="{Binding Poster}"/>                 </Image.Source>       </Image>       <toolkit:Rating ItemCount="10" Value="{Binding Rating, Mode=TwoWay}"  />

Στo rating, που θέλαμε, όχι μόνο να διαβάζουμε τιμές από το object και να τις απεικονίζουμε, αλλά και να θέτουμε τιμές, πρέπει να δηλώσουμε ότι το DataBinding αφορά και data entry. Αυτό γίνεται με το Mode=TwoWay.

Στη συνέχεια μετασχηματίσαμε το projectaki ώστε να υποστηρίζει selection από listbox και τα αντίστοιχα controls να γεμίζουν πληροφορία, από το Data Context του selected item του Listbox. Το Binding expression είναι διαφορετικό ως εξής. Ας πάρουμε το Image Control για την απεικόνιση του Poster. Δηλώνουμε το element με ElementName και μετά το Path του property που μας ενδιαφέρει. Όμοια και για τα υπόλοιπα.

<Image Margin="236,110,258,178" Source="{Binding  ElementName=MovieList, Path=SelectedItem.Poster}"/>

Το ElementName, το Path και το Mode είναι τρία από τα features του Binding. Ακολουθεί μία λίστα και σύντομη περιγραφή από τα πιο συχνά χρησιμοποιούμενα. Μπορούν αν χρησιμοποιηθούν χωριζόμενα με κόμμα.

Property Περιγραφή
Path To property path που μας ενδιαφέρει από το object που γίνεται bound.
Converter Ένα object που αλλάζει την τιμή ενός object σε μία άλλη (συμβατή με το target dependency property). Υλοποιεί το IValueConverter. Για παράδειγμα. BooleanToVisibility, ή UrlToImage.
ElementName Για databinding μεταξύ elements.
FallbackValue Default τιμή για εμφάνιση αν αποτύχει το data binding.
RelativeSource Πραγματοποιείται bind, με object που βρίσκεται σε μία σχετική θέση (ιεραρχίας) με το target object.
StringFormat Για παραμετροποιήσιμη εμφάνιση των strings.
Source Χρήση όταν θέλουμε να κάνουμε bind με κάτι που δεν βρίσκεται στο DataContext. Για παράδειγμα,  {Binding Source={x:Static DateTime.Now}, Path=Day}

Αξίζει σε αυτό το σημείο να σημειώσουμε κάποια πράγματα. Για αρχή, εξ ορισμού το silverlight θα πετάξει exception αν χρησιμοποιηθούν δύο ή περισσότερα ταυτόχρονα, των Source, RelativeSource και ElementName, για ευνόητους λόγους.

Αξίζει να πούμε ένα παράδεγμα για τον πολύ χρήσιμο Converter.  O converter είναι ένα object που υλοποιεί δύο συναρτήσεις, μία για conversion του source object σε κάτι άλλο και μία την ανάποδη διαδικασία. Έστω ότι θέλουμε να χρησιμοποιήσουμε ένα string formatter έτσι ώστε, όταν έρχεται ένα string object από το source να μετασχηματίζεται σε κάτι άλλο.

<StackPanel> <HyperLink NavigateUri=”{Binding Uri, Converter={StaticResource StringToUriConverter}, ConverterParameter=’{0:d}’}“ /> </StackPanel>

Υλοποιούμε τον converter και τον κάνουμε reference ως static resource στο XAML μας, χρησιμοποιώντας το κανονικά.

public class StringToUriConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return new Uri(value as string); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }

Ένα πολύ ωραίο trick όταν βλέπετε τι σας έρχεται από τον binding μηχανισμό στο debug, είναι να κάνετε έναν DebugConverter, υλοποιώντας τον και κάνοντας ότι θέλετε μέσα του, ή απλά να τον έχετε για το πολύτιμo brakepoint που μπορείτε να βάλετε για να κάνετε inspect το value.

Code

Όταν γράφουμε στη XAML το binding, τότε στη πραγματικότητα το Silverlight δημιουργεί ένα instance της κλάσης Binding που ορίζεται στο System.Windows.Data και πραγματοποιεί αυτό ακριβώς το δέσιμο. Μας δίδεται και εμάς η δυνατότητα να πραγματοποιήσουμε δικά μας bindings in code .

<txtEcho Text="{Binding}" .../>

Binding myBinding = new Binding("Text"); myBinding.Source = txtRealBox;   txtEcho.SetBinding(System.Windows.Controls.TextBox.TextProperty, myBinding);

Η βασική προϋπόθεση για να παίξει το binding είναι η κλάση που μπαίνει στο datacontext να υλοποιεί το

public interface INotifyPropertyChanged {     event PropertyChangedEventHandler PropertyChanged; }

Και τα properties που γίνονται bound να κάνουν Raise όταν αυτά γίνονται set (o untyped τρόπος με magic-string στο propertyName).

public void NotifyPropertyChanged(string propertyName)     {         if (PropertyChanged != null)         {             PropertyChanged(this,                 new PropertyChangedEventArgs(propertyName));         }     }

To blog post για το MVVM (μία custom έκδοση δλδ, όπου το ViewModel γνώριζε το View - [Μαθαίνοντας Design Patterns] Model – View – ViewModel) κάνει χρήση αυτών των μηχανισμών.

Ας κλείσω με μία τυπική PIC από το msdn, που τα λέει όλα!

Posted: Δευτέρα, 18 Οκτωβρίου 2010 11:05 πμ από George J. Capnias | 0 σχόλια
Δημοσίευση στην κατηγορία: , ,

Παίζοντας με το Deep Zoom

Πέρσι τέτοιες μέρες ήθελα να φτιάξω ένα στατικό site γρήγορα και εύκολα. Οι σχέσεις μου με web design και web development δεν είναι οι καλύτερες, οπότε και αποφάσισα σήμερα να ξεκινήσω την αναδόμηση του site από πλευράς design και σκεφτόμουν τι μπορώ να προσθέσω ή να αλλάξω. Δύο πράγματα μπορούσα να αλλάξω. Το design και τη gallery φωτογραφιών που υπάρχει στο site. Έτσι σε αυτό το post θα σας δείξω, πως ένας developer μπορεί να προσθέσει μία πολύ όμορφη έκθεση φωτογραφιών στο site του. Χρησιμοποίησα το Deep Zoom Composer της Microsoft το οποίο χρησιμοποιεί την τεχνολογία silverlight. Μερικά από τα κυριότερα παραδείγματα του Deep  Zoom είναι τα παρακάτω, όπου όπως μπορείτε να δείτε, τα αποτελέσματα είναι εντυπωσιακά.

Vertigo :: Deep Zoom Obama :: Hard Rock Memorabilia

Βήμα 1

Κατεβάζουμε και εγκαθιστούμε τον Deep Zoom Composer από το site της Microsoft.

Βήμα 2

Φτιάχνουμε ένα νέο project και το ονομάζουμε όπως θέλουμε. Εγώ το ονόμασα pseudorofes από το ομώνυμο site στο οποίο θα το χρησιμοποιήσω.

 

 

 

 

 

 

image

Βήμα 3

Προσθέτουμε όσες φωτογραφίες θέλουμε από το πλήκτρο add image πάνω δεξιά και όταν λέμε “όσες θέλουμε” το εννοούμε ;) Όταν τελειώσουμε πατάμε το Compose στο μενού πάνω από την φωτογραφία.

image

Βήμα 4

Εδώ είναι το διασκεδαστικό κομμάτι. Έχετε στην κεντρική εικόνα, το περιβάλλον εργασίας και δεξιά τις φωτογραφίες. Με drag n drop και μερικές απλές κινήσεις μπορείτε να φτιάξετε ότι θέλετε, να μετασχηματίσετε τις φωτογραφίες όπως θέλετε και σε ότι μεγέθη χρειάζεστε. Μην ανησυχήσετε για την ευκρίνεια. Θα δείτε στο τέλος ότι όλες οι φωτογραφίες φαίνονται τέλεια όταν γίνεται zoom πάνω τους (that’s y και Deep Zoom). To περιβάλλον είναι ξεκούραστο, έχει στηλοθέτες και λοιπα βοηθήματα που κάνουν την τοποθέτηση φωτογραφιών πραγματικό παιχνίδι, σαν κολλάζ χωρίς κόλλα, ψαλίδια και χάρακες. Όταν τελειώσετε πατήστε το export.

 

 

 

 

 

 

 

 

 

 

 

image

Βήμα 5

Εδώ έχετε δύο επιλογές, να φορτώσετε το gallery σε ένα photozoom account ή να πάρετε τον κώδικα που θα γίνει generate και να τον χρησιμοποιήσετε όπως εσείς θέλετε. Διάλεξα να έχω τα images σε png. Επίσης διάλεξα να δω και το silverlight project και πάτησα export. Περιμένουμε μερική ώρα μέχρι να τελειώσει η επεξεργασία και μετά μπορούμε να συνεχίσουμε.

image

Βήμα 6

Έχοντας έτοιμα τα αρχεία του silverlight μπορούμε να τα χρησιμοποιήσουμε όπως θέλουμε. Φόρτωσα στον server μου όλα τα αρχεία και το μόνο που έκανα ήτα να taggaro το object μέσα στο html μου. Σε αυτό το σημείο χρησιμοποίησα το Microsoft Expression Web 2 (το οποίο είναι φανταστικό) και έγραψα απλά το παρακάτω:

image

image

Το πρόγραμμα είναι σε silverlight οπότε δεν σας ενδιαφέρει αν έχετε apache, iis, php, asp, firefox, IE etc etc. Είναι Silverlight το οποίο τρέχει στον client και αν δεν υπάρχει το redistributable απλά το κατεβάζει και το εγκαθιστά ο χρήστης. Το αποτέλεσμα ήταν πολύ ωραίο όπως μπορείτε να δείτε και μόνοι σας. Τώρα μένει το lifting για όλο το υπόλοιπο site :P:P:P hehehe…

http://www.pseudorofes.gr/previous_work.htm

Cheers

Posted: Τρίτη, 19 Αυγούστου 2008 4:35 μμ από George J. Capnias | 0 σχόλια
Δημοσίευση στην κατηγορία: ,

Λαμβάνοντας δεδομένα από αισθητήρες

Έστω ότι έχουμε έναν αισθητήρα, το οποίον αποκαλούμε sensor node.  Αυτός ο αισθητήρας είναι μέρος, ενός ευρύτερου δικτύου αισθητήρων. Έστω τώρα ότι θέλουμε να ανακτήσουμε τα δεδομένα αυτού του αισθητήρα. Έχουν αναπτυχθεί συστήματα τα οποία "βλέπουν" κάθε sensor node σαν μια μικρή πηγή δεδομένων, και το προαναφερόμενο δίκτυο, σαν μια μεγάλη κατανεμημένη βάση δεδομένων. Όταν έχουμε όμως μια κατανεμημένη βάση δεδομένων, μας νοιάζει τι υπάρχει από κάτω; Όχι...κάνουμε SQL queries και απλά ανακτούμε τα αποτελέσματα χωρίς ιδιαίτερη αγωνία για το τι υπάρχει από κάτω. Κάπως έτσι γίνεται και με ένα δίκτυο αισθητήρων.

Ας εξηγήσω πως δουλεύει αυτός ο μηχανισμός. Έστω ότι έχω έναν υπολογιστή και ένα δίκτυο αισθητήρων και θέλω να κάνω ένα query, πώς γίνεται η επικοινωνία με τους αισθητήρες; Ανάμεσα στο δίκτυο και στον υπολογιστή, υπάρχει ένα ειδικός κόμβος-gateway που λειτουργεί ως μεσάζοντας σε αυτήν την επικοινωνία. Στέλνω εγώ μια αίτηση και εκείνος είναι υπεύθυνος να την δρομολογήσει hop-by-hop στο δίκτυο αισθητήρων. Αυτή είναι η φάση της ανάλυσης επερώτησης. Στην συνέχεια έχουμε την ανάκτηση αποτελέσματος η οποία είναι παρόμοια με την πρώτη διαδικασία αλλά σε αντίστροφη πορεία. Τόσο απλό!!!! (εχμ μάλλον δεν είναι τόσο απλό, γιατί κάπου εδώ μπαίνει η επιστήμη. Αυτή η διαδικασία πρέπει να μελετηθεί με μαθηματική ακρίβεια διότι πρέπει να πετύχουμε τη μικρότερη δυνατή κατανάλωση ενέργειας, αλλά λεπτομερής ανάλυση δεν είναι ο σκοπός μου).

Πάμε να πούμε μερικά παραδείγματα επερωτήσεων τώρα. Σε αυτούς λοιπόν τους αισθητήρες, θέλω να κάνω δύο τύπους επερωτήσεων. Κάποιες επερωτήσεις τις κάνω μια φορά (on demand) και κάποιες θέλω να τις κάνω ανα τακτα χρονικά διαστήματα. Η πρώτη κατηγορία είναι απλή και μπορούμε να σκεφτούμε πολλά παραδείγματα. Στην δεύτερη κατηγορία, για παράδειγμα, εμπίπτουν περιβαλλοντολογικές εφαρμογές. Θα θεωρήσουμε ότι έχουμε αισθητήρες θερμοκρασίας, οι οποίοι είναι τοποθετημένοι σε μια δασική έκταση. Για να ελέγχω εγώ αν υπάρχει ένδειξη αύξησης θερμοκρασίας (φωτιά), πρέπει να ελέγχω συνεχώς για μετρήσεις. Πχ σε SQL - like γλώσσα θα είχα κάτι τέτοιο

SELECT sensorId, temperature FROM sensors EVERY 30 sec

Βέβαια από εκεί και πέρα μπορούμε να παίζουμε με τα queries ώστε να παίρνουμε είτε raw data είτε αποτελέσματα με τις MIN, MAX, SUM, COUNT και AVG. Επίσης μπορούμε να παίξουμε με τα events. Αν ανιχνεύαμε φωτιά και θέλαμε να επεξεργαστούμε τα δεδομένα περαιτέρω μπορούσαμε πχ να τρέξουμε κάτι τέτοιο:

ON EVENT ret.temperature > 60 SELECT nodeId, nodeLocation, temperature FROM sensors

Έστω λοιπόν ότι γράψαμε το query μας. Ανάλογα με το τι περιγράφει η επερώτησή μας η προαναφερόμενη gateway αναλαμβάνει να το μεταδώσει καταλλήλως. Αν για παράδειγμα είχαμε και ένα WHERE στο query μας τότε αυτό θα δρομολογηθεί στον συγκεκριμένο κόμβο αντί να είχαμε broadcast (Εδω παίζουν αλγόριθμοι αναζήτησης σε γράφους που είμαι σίγουρος ότι μάθατε σε κάποιο μάθημα πολυπλοκότητας και θεωρούσατε ότι "τι μας τα λένε αυτά τώρα, αφού δεν πρόκειτε να τα χρειαστούμε...".... σιγά σιγά με έκπληξη θα καταλάβετε ότι όλα χρειάζονται :))

Τι γίνεται όμως όταν έχουμε έναν aggregation operator οπως τον SUM...Τότε τα πράγματα δυσκολεύουν. Και αν θέλαμε μέση τιμή από κάποια περιοχή; Τότε τα πράγματα δυσκολεύουν ακόμα πιο πολύ. Οι κόμβοι μεταξύ τους έχουν πληροφορίες για το ποιος είναι ο πατέρας κόμβος, ποια είναι τα παιδιά, ποια είναι τα αδέρφια κτλ. Η πληροφορία πρέπει να ταξιδέψει ανάμεσα από αυτούς τους κόμβους με τα μικρότερα μονοπάτια ανάμεσα στις παραπάνω σχέσεις. Για παράδειγμα. Στην περίπτωση του SUM δείτε το παρακάτω σχηματάκι

A     B     C

D     E     F

G     H     I

Έστω ότι θέλω το άθροισμα των τιμών των A,B,C αισθητήρων και η gateway είναι το G. Δείτε το λίγο.

Αν η αθροιστική πληροφορία πάει από C στο B, μετά C+B στο B και μετά A+B+C στο A και από εκεί στο D και μετά στο G έχουμε μία καλή λύση. Δεν είναι λίγοτερα μηνύματα από το να μεταφέρονταν παράλληλα οι μετρήσεις C->I, B->H , A->G και να άθροιζαν στο επίπεδο G, H, I??

Κάπως έτσι γίνεται η επερώτηση σε ένα δίκτυο αισθητήρων. Βέβαια αν πάω τώρα και πάρω ένα βιβλίο για WSN's (Wireless Sensor Networks) είμαι σίγουρος ότι έκανα την γενίκευση της τάξης των 1500 σελίδων ++... :D Αλλά γενικά, η βασική ιδέα αυτή είναι.

Τώρα για τον προγραμματιστή πραγματική σημασία έχει μόνο το πρώτο στάδιο. Αυτό που κάνει απλές επερωτήσεις στην γλώσσα του δικτύου (για απλά δίκτυα η SQL είναι η πιο κοινά χρησιμοποιούμενη γλώσσα). Οπότε αν έχετε μια εφαρμογή και θέλετε να δοκιμάσετε κάποια δεδομένα από αισθητήρες, πείτε το super duper "Έστω οτι..." και θεωρήστε ότι έχετε μια βάση με πραγματικά δεδομένα.

Enjoy science!

Posted: Παρασκευή, 25 Απριλίου 2008 1:28 πμ από George J. Capnias | 0 σχόλια
Δημοσίευση στην κατηγορία:

[Μαθαίνοντας Design Patterns] Factory

Συνεχίζοντας λοιπόν αυτή τη μικρή αναζήτηση γύρω από τα Design Patterns, σήμερα θα μιλήσουμε για το Factory. Πριν αναφέρω τα χαρακτηριστικά του pattern, ακολουθώντας τον τρόπο που ξεκίνησα το προηγούμενο post μου, θα ήθελα να πω τα εξής:

Έρχεται μια άλλη φάση στην ζωή του προγραμματιστή :P , που έχοντας αποφασίσει ότι θα κάνει το βήμα να μάθει να σχεδιάζει σωστά τον κώδικά του, ψάχνει να βρει πηγές που θα του δώσουν αυτό που θέλει να μάθει με τον καλύτερο και πιο κατανοητό τρόπο. Έτσι λοιπόν έκανα και εγώ...

Αναζήτησα το Design Patterns: Elements of Reusable Object-Oriented Software. Ένα παλιό βιβλίο (94), μία έκδοση έχει βγάλει, όλοι το θεωρούν την βίβλο των design patterns. Το πήρα και εγώ με αισιοδοξία για το μέλλον. Όσο όμως προσεκτικά και αν το διάβαζα δεν μπορούσα να κάνω κτήμα μου κάθε τι που έλεγε εκεί μέσα. Ήταν απλά αδύνατο, οι πληροφορίες ήταν τόσες πολλές, οι λεπτομέριες χαοτικές και η θεωρία τόσο πλήρης (πράγματα που όντως, κάνουν ένα βιβλίο, θρησκεία) που μόνο για να έχεις μια πρώτη επαφή με Design Patterns δεν ήταν...όσο και αν είχα την ελπίδα ότι θα τα καταφέρω εύκολα και γρήγορα, τουλάχιστον σε θεωρητικό επίπεδο, τόσο μπερδευόμουν όχι από θέμα ποιότητας (που ήταν άριστη), αλλά περιεκτικότητας πληροφορίας. Ένιωθα όπως τότε που είχα πάρει το βιβλίο των KnR για να μάθω C. Δεύτερη φορά στην ζωή μου λοιπόν. Και για να μην βρεθείτε σε παρόμοια κατάσταση θα το πω φωναχτά.

ΔΕΝ ΠΑΙΡΝΟΥΜΕ CORE REFERENCE MANUAL ΣΤΗΝ ΠΡΩΤΗ ΜΑΣ ΕΠΑΦΗ ΜΕ ΚΑΠΟΙΟ ΘΕΜΑ

Αυτή η φάση του προγραμματιστή λοιπόν, τελειώνει όταν βρούμε ένα βιβλίο απλό, κατανοητό και ταυτόχρονα να κρατάει υψηλό το επίπεδο της ποιότητας στις παρεχόμενες πληροφορίες.  Ένα τέτοιο βιβλίο είναι αυτό που μου πρότεινε ο φίλος Νίκος Παλλαδινός πρόσφατα και θα ήθελα να το μοιραστώ και με εσάς, μιας και το βρήκα τρομακτικά ενδιαφέρον (σε σημείο να απειλήσει λοιπές υποχρεώσεις μου) και πολύ έξυπνα γραμμένο. Και ο τίτλος αυτού Head First Design Patterns με κώδικα σε Java και με ένα εξώφυλλο που έχω ιδιαίτερη αδυναμία. Heheheh. Ακολουθώντας ένα μείγμα εμπειριών απο διάφορα βιβλία συνεχίζω να δίνω μια μικρή περιγραφή στα patterns για να συζητάμε κάθε φορά και να μαθαίνουμε μέσα από την συζήτηση.

 

Design Pattern 2#: Factory

Με το Factory pattern μπορούμε να δημιουργήσουμε μία διεπαφή η οποία θα μας επιστρέφει το νέο αντικείμενο που θέλουμε αλλά το είδους του αντικειμένου που θα επιστραφεί θα καθορίζεται στις υποκλάσεις. Αρκετά με την θεωρία. Μία πρόταση φτάνει. Ας πάμε κατευθείαν στο παράδειγμα για να δούμε πώς λειτουργεί το Factory pattern και που χρησιμοποιείται.

Το αγαπημένο μου θέμα. Πείτε ότι θέλουμε να φτιάξουμε ένα κατάστημα που να φτιάχνει σουβλάκια (no comments pls...show some respect στο τρόφιμο :P:P..hehe). Θέλω μία τέτοια μέθοδο δηλαδη

Souvlaki orderSouvlaki()
{
Souvlaki souvlaki = new Souvlaki();

souvlaki.etoimase();
souvlaki.tilikse();
souvlaki.paketarise();

return souvlaki;
}

Έστω λοιπόν ότι θέλω να προσθέσω κώδικα που να ελέγχει τι τύπο σουβλάκι θέλω να φτιάξω με βάση την περιοχή (τοπική παραλλαγή), θα έχω κάτι σαν αυτό:

Souvlaki orderSouvlaki(String perioxi)
{
Souvlaki souvlaki;

if (perioxi.Equals("notia_ellada"))
souvlaki = new KanonikoSouvlaki();
else if (perioxi.Equals("voreia_ellada"))
souvlaki = new VoreiasElladasSouvlaki();
else if (perioxi.Equals("kipriako"))
souvlaki = new KipriakiPitaSouvlaki();

souvlaki.etoimase();
souvlaki.tilikse();
souvlaki.paketarise();

return souvlaki;
}

Αν το κατάστημα δεν πουλάει πολύ σουβλάκια τύπου βόρειας ελλάδας, για να μην έχει απώλεια κέρδους θα πρέπει να σταματήσει την παρασκευή τους. Αν βλέπει ότι του ζητάνε σουβλάκι τύπου Ιωαννίνων κάτι θα έπρεπε να κάνει, οπότε:

Souvlaki orderSouvlaki(String perioxi)
{
Souvlaki souvlaki;

if (perioxi.Equals("notia_ellada"))
souvlaki = new KanonikoSouvlaki();
else if (perioxi.Equals("voreia_ellada"))
souvlaki = new VoreiasElladasSouvlaki();
else if (perioxi.Equals("kipriako"))
souvlaki = new KipriakiPitaSouvlaki();
else if (perioxi.Equals("ioannina"))
souvlaki = new GianniotikoSouvlaki();
souvlaki.etoimase();
souvlaki.tilikse();
souvlaki.paketarise();

return souvlaki;
}

Είναι προφανές ότι όταν θέλουμε να ρυθμίσουμε ποια κλάση θα αρχικοποιείται, υπάρχει σοβαρό πρόβλημα. Ο κώδικάς μας δεν είναι καθόλου modular. Έχουμε ένα στοιχείο όμως!!!! Ξέρουμε τώρα τι πρέπει να κάνουμε encapsulate!!! Καταρχάς φτιάχνουμε μια καινούρια μέθοδο αφαιρώτας το παραπάνω κομμάτι βάζοντας το σε μία μέθοδο που αναλαμβάνει αυτό ακριβώς το σημείο. Και έχουμε όνομα να της δώσουμε...SouvlakiFactory.

public class SouvlakiFactory
{
public Souvlaki createSouvlaki(String perioxi)
{
Souvlaki souvlaki;

if (perioxi.Equals("notia_ellada"))
souvlaki = new KanonikoSouvlaki();
else if (perioxi.Equals("voreia_ellada"))
souvlaki = new VoreiasElladasSouvlaki();
else if (perioxi.Equals("kipriako"))
souvlaki = new KipriakiPitaSouvlaki();
else if (perioxi.Equals("ioannina"))
souvlaki = new GianniotikoSouvlaki();

return souvlaki;
}

}

Μα τι κάναμε τώρα; Πήραμε το πρόβλημα και το μεταθέσαμε. Άλλαξε κάτι; Ναι! Άλλαξε κάτι πολύ σημαντικό. Το SouvlakiFactory μπορεί να έχει πολλούς clients και όχι μόνο την orderSouvlaki. Μπορεί να υπάρχει άλλη κλάση που να υπολογίζει την τιμή, ή να κανονίζει την παράδοση εφόσον υπάρχει διανομή κατοίκων. Έτσι, τώρα έχουμε ένα σημείο να κάνουμε αλλαγές. Ορίστε πως έχει τώρα ο κώδικάς μας.

SouvlakiFactory factory;

public Souvlantzidiko(SouvlakiFactory factory)
{
this.factory = factory;
}
Souvlaki orderSouvlaki(String perioxi)
{
Souvlaki souvlaki;
souvlaki = factory.createSouvlaki(perioxi);
souvlaki.etoimase();
souvlaki.tilikse();
souvlaki.paketarise();

return souvlaki;
}

Έστω τώρα ότι το κατάστημά μας επεκτείνεται σε όλη την Ελλάδα και ο κώδικας είναι παντού ο ίδιος. Παρόλα αυτά, όταν θα πάμε στην Σπάρτη, υπάρχει ένας ειδικός τύπος για Σουβλάκι Νότιας Ελλάδας(σπεσιαλ σαλτσα) που αρέσει στους ντόπιους. Δεν θα έπρεπε να έχω λοιπόν ένα ειδικό factory όπως το παρακάτω;

SpartiFactory spFactory = new SpartiFactory();
Souvlantzidiko spartiSouvlantzidiko = new Souvlantzidiko(spFactory);
spartiSouvlantzidiko.orderSouvlaki("notia_ellada");

Το πρόβλημα εδώ όμως είναι ότι δεν έχουμε τον έλεγχο το ποιος θα κάνει create τι. Πχ. κάποιος κάνει την δική επιχείρηση χρησιμοποιώντας το δικό σας factory. Χρειαζόμαστε μία ακόμα πινελιά για να έχουμε το Factory μας δεμένο με το κάθε κατάστημα. Παρατηρείστε το σχόλιο στην abstract κλάση

public abstract class Souvlantzidiko
{
public Souvlantzidiko(SouvlakiFactory factory)
{
}

Souvlaki orderSouvlaki(String perioxi)
{
Souvlaki souvlaki;
souvlaki = createSouvlaki(perioxi);
souvlaki.etoimase();
souvlaki.tilikse();
souvlaki.paketarise();

return souvlaki;
}
//To factory object υπάρχει εδώ. Αυτό ακριβώς το σημείο
//είναι εκείνο στο οποίο αποφασίζει η κάθε υποκλάση την υλοποίηση που θέλει.
protected abstract Souvlaki createSouvlaki(String perioxi);
}

Το factory pattern όπως το αναλύσαμε εδώ μπορεί να χρησιμοποιηθεί σε πάρα πολλές καταστάσεις και αν το καταλάβουμε καλά, θα μας λύσει τα χέρια σε πολλά σημεία. Στο .NET υπάρχει υλοποιημένο σε πολλές λειτουργίες της βιβλιοθήκης εξυπηρετώντας κάθε φορά αυτήν την λειτουργικότητα. Για παράδειγμα, για να διαβάσετε/στείλετε δεδομένα στο δίκτυο με βάση ένα uri μπορείτε να χρησιμοποιήσετε την System.Net.WebRequest. Αν ξέρετε λίγο από system programming κάθε πρωτόκολλο ακολουθεί αυστηρά τις δικές του συμβάσεις επικοινωνίας, τόσο στην δημιουργία sockets όσο και στα μηνύματα που ανταλάσσονται κλπ. Η WebRequest.Create δημιουργεί ένα αρμόδιο αντικείμενο με βάση το URI που θα του δώσουμε επιστρέφοντας μας το κατάλληλο instance που θα μας επιτρέψει την επικοινωνία. Το uri μπορεί να είναι ένα από τα τρία (default) "http://", "https://", and "file://".

Enjoy, stay tuned!!!

Posted: Δευτέρα, 11 Φεβρουαρίου 2008 9:06 μμ από George J. Capnias | 0 σχόλια
Δημοσίευση στην κατηγορία: ,

[Μαθαίνοντας Design Patterns] Singleton

Έρχεται μία φάση στην ζωή του προγραμματιστή που καταλαβαίνει πως κάτι του λείπει, πως ο κώδικας που γράφει είναι λίγο ελλειπής, ή ότι πρέπει να κάνει κάτι αλλά δεν είναι σίγουρος πως να το κάνει κομψά. Σχεδιάζοντας αντικειμενοστραφή προγράμματα είναι κάτι δύσκολο, σχεδιάζοντας κώδικα που θα επαναχρησιμοποιηθεί ακόμα δυσκολότερο. Εδώ έρχεται μία έννοια που έρχεται να συμπληρώσει κάθε προγραμματιστή, να βελτιώσει την τεχνική του, να μειώσει τον χρόνο και τον κόπο που καταβάλει για τον σχεδιασμό.

DESIGN PATTERNS

Μιας και εγώ πρόσφατα άρχισα να τα χρησιμοποιώ, θα πρότεινα για αρχή, να πούμε τι είναι στην πραγματικότητα design patterns και να εξετάσουμε μαζί μερικά patterns που χρησιμοποιούνται συχνά. Θα προσπαθήσω να τα πω όσο περιεκτικά μπορώ ώστε και εγώ να μαθαίνω μέσα από την αφαιρετικότητα και να αρκούν αυτά που γράφω για να ενισχύσω την διάθεσή σας να πειραματιστείτε και να διαβάσετε περισσότερα. Θα προσπαθώ να περιγράφω 2-3 patterns την εβδομάδα. Ή γλώσσα που θα χρησιμοποιώ δεν έχει καμία απολύτως σημασία μιας και εδώ μιλάμε για αντικειμενοστραφή προγραμματισμό και όχι για κάποια συγκεκριμένη γλώσσα (C++, Java, C#, ...)

Τι είναι design pattern;

Κάθε pattern περιγράφει ένα πρόβλημα το οποίο μας παρουσιάζεται συνέχεια στον χώρο μας. Στην συνέχεια περιγράφει την λύση που επιλύει το πρόβλημα με τέτοιο τρόπο που να μπορούμε να την ξαναχρησιμοποιήσουμε ξανά και ξανά με μηδενική προσπάθεια ( Ο χρόνος είναι χρήμα, οπότε κάνοντας τα design patterns κτήμα μας, u know the drill ;) ).

Στοιχεία pattern
  1. Όνομα
  2. Το πρόβλημα που λύνει
  3. Την λύση που προτείνει, περιγράφει, προδιαγράφει
  4. Τις συνέπειες μετά από την χρήση. Συνήθως σε ένα πρόγραμμα οι συνέπειες είναι ο χώρος και ο χρόνος. Οπότε κάθε φορά στον έναν ζυγό έχουμε επαναχρησιμοποίηση, λειτουργικότητα, επεκτασιμότητα και στον άλλον, κόστος σχεδίασης, χρόνο
Είδη

Τα design patterns κατηγοριοποιούνται με βάση δύο παραμέτρους. Εμβέλεια και σκοπός. Επιγραμματικά αναφέρω σκοπούς και εμβέλειες και θα αφήνω σε εσάς στο τέλος κάθε pattern τι είναι κάθε ένα ;)

  • Εμβέλεια
    Ανά Κλάση
    Ανά Αντικείμενο
  • Σκοπός
    Για δημιουργία
    Για δόμηση
    Για συμπεριφορά
Design Pattern 1#: Singleton

Singleton είναι το pattern που μας διαβεβαιώνει ότι η κλάση μας έχει μόνο ένα στιγμιότυπο. Επίσης παρέχεται ένας συγκεκριμένος τρόπος για να μπορούμε να το ανακτούμε από οπουδήποτε. Ας πούμε ένα παράδειγμα. Πείτε ότι έχετε πολλούς εκτυπωτές στο σύστημά σας. Παρόλα αυτά όταν πάτε να εκτυπώσετε, η εκτύπωσή σας περνάει από έναν printer spooler. Θα μπορούσαμε να βάλουμε μια global μεταβλητή ώστε να μπορούμε να ανακτήσουμε από παντού το αντικείμενο, αλλά δεν μας εμποδίζει κάτι από το να δημιουργήσουμε πολλαπλά στιγμιότυπα της κλάσης αυτής. Η λύση είναι λοιπόν, η ίδια η κλάση να κρατάει την πληροφορία για τον εαυτό της, το πως θα δημιουργηθεί, το πότε και πως θα μας επιστρέφει το ένα και μοναδικό instance της (εαν έχει δημιουργηθεί).

 class Singleton
  {
    private static Singleton instance;

    protected Singleton()
    {
    }

    public static Singleton Instance()
    {

      if (instance == null)
      {
        instance = new Singleton();
      }

      return instance;
    }

Posted: Τρίτη, 18 Δεκεμβρίου 2007 4:11 μμ από George J. Capnias | 0 σχόλια
Δημοσίευση στην κατηγορία: ,