Οι βέλτιστες πρακτικές για την τροποποίηση συλλογή χαρακτηριστικά λειτουργικά




Είμαι περίεργος πώς να πάνε για την εφαρμογή μιας τάξης που υπακούει σε αυστηρούς κανόνες λειτουργίας προγραμματισμού.


Για παράδειγμα, αν έχω μια τάξη που έχει δύο ιδιότητες και έχω μια μέθοδο που τους τροποποιεί, πώς θα κάνετε για αυτό; Τα χαρακτηριστικά θα είναι ιδιωτικό διαστήματα, και η μέθοδος θα πρέπει να επιστρέψει μια νέα εμφάνιση του χαρακτηριστικού κάθε φορά που το τροποποιεί. Αυτό είναι καλό, εκτός από Θα ήθελα να κρατήσει περιείχε, που σημαίνει ότι θα χρειαστεί έναν τρόπο να ορίσετε την val.


Ποιος θα ήταν ο καλύτερος τρόπος για να γίνει αυτό, έτσι ώστε δεν έχω χιλιάδες περιπτώσεις ας πούμε, μια συλλογή, που επιπλέουν γύρω στη μνήμη;
Αυτή είναι η γνώμη μου, αλλά? όπως ακριβώς και οι τάξεις περίπτωση δεν, θα ήθελα να εφαρμόσουν μια `copy`μέθοδο του είδους στην τάξη για να καταστεί δυνατή η τροποποίηση, διατηρώντας παράλληλα το αμετάβλητο, αλλά υπάρχει ορισμένες περιπτώσεις που δεν μπορώ να βοηθήσω να το μεταβλητό? Για παράδειγμα, όταν κάτι αναμένεται να γίνει η λειτουργία αντιγραφής είναι πολύ μεγάλη και αργή για την κατηγορία? όπως όταν η τάξη έχει τόσα πολλά συχνά τροποποιημένο μέλη. Και μην ανησυχείτε για χιλιάδες περιπτώσεις που επιπλέουν γύρω στη μνήμη, επειδή είναι αυτόματα GC'ed, οπότε το πιο πραγματικό πρόβλημα είναι ο χρόνος κόστος της αντιγραφής περιπτώσεις της κλάσης. Παρακαλώ πείτε μου εάν η γνώμη μου είναι κάπως λάθος :)
Αν χρησιμοποιείτε τάξεις Objective-C, τότε η `[myObject isKindOfClass: [InterestingClass class]]`δοκιμή είναι διαθέσιμη. Αν χρησιμοποιείτε πρωτόγονων τύπων (η οποία ερώτησή σας, αναφέροντας το «διπλό» τύπου, προτείνει), τότε δεν μπορείτε. Ωστόσο, αν κάνετε κάποια πολύ funky πράγματα, ο compiler μπορεί να σας πει πότε πρωτόγονων τύπων ή δεν ταιριάζουν, και όταν δεν θα εκτελέσει έμμεση προώθηση στο επιθυμητό τύπο.


Θα ήταν χρήσιμο να γνωρίζουμε λίγο περισσότερα για το ποιο είναι το συγκεκριμένο πρόβλημα είναι ότι προσπαθείτε να λύσετε, διότι μπορεί να είναι ότι η λύση δεν περιλαμβάνει την ανίχνευση της δημιουργίας διπλασιάζεται σε όλα :-). > 
> Μου αρέσει η ιδέα ότι δεν χρειάζεται για την κατάρτιση των προγραμμάτων κάθε φορά που κάνετε μια αλλαγή. Καταλαβαίνω ότι οι ερμηνεύεται γλώσσες πιθανότατα συνηθισμένος χτυπήσει την ίδια απόδοση αυτή τη στιγμή να πάρει.
> 
> 
> 


Αυτό είναι το μεγαλύτερο πρόβλημα? μπορεί να ζείτε με το χτύπημα απόδοση. Θα μπορούσατε να δοκιμάσετε να χρησιμοποιήσετε την Python και την [επέκτασή του με την τρέχουσα C ++ σας modules](http://www.python.org/doc/ext/intro.html) για τα βαρέα τμήματα των επιδόσεων. Παρόλα αυτά, η αλλαγή ολόκληρου του συστήματός σας φαίνεται σαν μια μεγάλη προσπάθεια, αν ο μόνος λόγος είναι η έλλειψη της C ++ ταλέντο. Πρόσληψη ανθρώπους που ξέρουν C ++ φαίνεται να είναι η φθηνότερη επιλογή. Θα:


* Γράψτε τον έλεγχο ασφάλειας με τέτοιο τρόπο που να μπορεί να εφαρμοστεί σε οποιοδήποτε μέρος θέλετε. Με αυτό τον τρόπο μπορείτε να refactor οι απαιτήσεις αλλάζουν.
* Εάν ο έλεγχος ασφαλείας στην πραγματικότητα θα *είναι πάντα* ισχύει, τοποθετήστε το στο αποθετήριο στρώμα (ή καλύτερα, σε μια πτυχή αν η γλώσσα σας υποστηρίζει), έτσι ώστε πολλαπλές υπηρεσίες θα έχουν όλοι την κοινή ασφάλεια, εάν χρησιμοποιούν τον ίδιο χώρο αποθήκευσης. Διαφορετικά τοποθετήστε το στην υπηρεσία (ή μια πτυχή που ενεργεί για την υπηρεσία).
* να περάσει ολόκληρο το αντικείμενο χρήστη με το μηχανισμό ελέγχου ασφαλείας:


	+ εάν ο έλεγχος ασφαλείας αργότερα γίνεται πιο σύνθετη (εξαρτάται από τις άλλες ιδιότητες του χρήστη) το API δεν θα αλλάξει?
	+ καθιστά πιο σημασιολογικό νόημα - είστε έλεγχο ο χρήστης έχει την άδεια να κάνει κάτι, δεν είναι ότι η λίστα με τις χώρες κάνει. Λοιπόν, ένα από τα reaons γιατί τάξεις περιλαμβάνουν συνήθως ιδιωτικού μέλη με τις δημόσιες κτήτορες / setters είναι ακριβώς επειδή μπορεί να ελέγξει τα δεδομένα.


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


Όσο για τις επιδόσεις, είμαι με εδώ Knuth:



> 
> «Πρέπει να ξεχάσουμε τις μικρές αποδόσεις, δηλαδή περίπου το 97% του χρόνου. Πρόωρο βελτιστοποίησης είναι η ρίζα όλων των κακών»
> 
> 
> Ίσως είμαι τρελή, αλλά ανησυχούν για την ταχύτητα σε περιπτώσεις όπως αυτή, χρησιμοποιώντας μια ερμηνευτική γλώσσα είναι σαν να προσπαθώ να καταλάβω τι χρώμα να βάψει το υπόστεγο. Ας μην πάρετε ακόμη και στην ιδέα ότι αυτό το είδος της βελτιστοποίησης είναι εντελώς προ-ώριμη.


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


Μια αναλογία θα ήταν να χωροχρόνο στη φυσική. Αν θεωρείτε τον κόσμο ως 3δ, τότε τα αντικείμενα δεν έχουν σταθερές θέσεις - κινούνται πάροδο του χρόνου. Για να φέρει τα μαθηματικά για να φέρουν στο φυσικό κόσμο, ως εκ τούτου, να προσθέσετε μια διάσταση χρόνου και να εξετάσει τις τιμές των διαφόρων ιδιοτήτων σε συγκεκριμένες χρονικές στιγμές. Με τον τρόπο αυτό, έχουμε κάνει τα αντικείμενα της μελέτης μας σε σταθερές. Ομοίως, στον προγραμματισμό, υπάρχει μια εννοιολογική απλότητα που θα είχε από την εργασία με αμετάβλητες τιμές. Αντικείμενα με μια ταυτότητα στον πραγματικό κόσμο μπορεί να μοντελοποιηθεί ως μία ακολουθία αναλλοίωτες αξίες (τα κράτη του αντικειμένου στην αύξηση φορές) και όχι ως μια ενιαία τιμή που αλλάζει.


Φυσικά οι λεπτομέρειες για το πώς να συνδέσει την ακολουθία των τιμών σε μια «ταυτότητα αντικειμένου» μπορεί να είναι λίγο τριχωτό. Haskell έχει [Μονάδες](http://en.wikipedia.org/wiki/Monad_(functional_programming)) που θα αφήσει το μοντέλο κράτους. [Λειτουργική Αντιδραστική Προγραμματισμός](http://en.wikipedia.org/wiki/Functional_reactive_programming) είναι μια πιο κυριολεκτική προσπάθεια μοντελοποίηση αντικειμένων στον κόσμο με καθαρό λειτουργικό ενημερώσεις, που πιστεύω ότι είναι μια πολλά υποσχόμενη κατεύθυνση για τον προγραμματισμό.


Θα σημειωθεί ότι Clojure, σε αντίθεση με Haskell, δεν είναι καθαρό, και μπορείτε να ενημερώσετε τις μεταβλητές, όπως προτείνατε. Αν κάνετε ενημέρωση μόνο μερικές μεταβλητές σε υψηλό επίπεδο, θα εξακολουθούν πιθανώς να απολαύσουν πολλές από τις εννοιολογικές οφέλη απλότητα του λειτουργικού προγραμματισμού. Από προεπιλογή, **πάντα απλά να δημιουργήσετε νέο φάκελο** μέσα στο ίδιο έργο


* Θα πάρετε μόνο τη συναρμολόγηση (χωρίς επιπλέον γυμναστικής ILMerge)
* Είναι πιο εύκολο να θολώνω (επειδή θα έχετε λιγότερες δημόσιες τύπους και μεθόδους, ιδανικά καθόλου)


Ο διαχωρισμός πηγαίο κώδικα σας σε πολλά έργα νόημα μόνο εάν ...


* Έχετε κάποια τμήματα του πηγαίου κώδικα που αποτελούν μέρος του προγράμματος, αλλά όχι να αναπτυχθούν από προεπιλογή ή σε όλα (δοκιμές μονάδα, επιπλέον plugins κλπ)
* Περισσότερα προγραμματιστές που εμπλέκονται και θέλετε να αντιμετωπίζουν την εργασία τους ως αναλώσιμο μαύρο κουτί. (Όχι πολύ συνιστάται)
* Εάν μπορείτε να διαχωρίζονται σαφώς το έργο σας σε απομονώνονται στρώματα / ενότητες και θέλετε να βεβαιωθείτε ότι δεν μπορούν cross-καταναλώνουν **εσωτερικά** μέλη. (επίσης δεν συνιστάται, διότι θα πρέπει να αποφασίσει ποια πλευρά είναι το πιο σημαντικό)


Αν νομίζετε ότι κάποια τμήματα του πηγαίου κώδικα σας θα μπορούσε να είναι επαναχρησιμοποιήσιμα, ακόμα δεν το δημιουργήσετε ένα νέο έργο. Απλά περιμένετε έως ότου θα θέλετε πραγματικά να το χρησιμοποιήσετε ξανά σε μια άλλη λύση και να απομονώσουν έξω από αρχικό σχέδιο, όπως απαιτείται. Ο προγραμματισμός δεν είναι ένα lego, επαναχρησιμοποίηση είναι συνήθως πολύ δύσκολη και συχνά δεν θα συμβεί όπως έχει προγραμματιστεί. Karl είναι απολύτως σωστό, δεν υπάρχει ανάγκη να ρυθμίσετε αντικείμενα για να άκυρη μετά τη χρήση. Αν ένα αντικείμενο υλοποιεί `IDisposable`, απλά φροντίστε να καλέσετε `IDisposable.Dispose()`όταν τελειώσετε με αυτό το αντικείμενο (τυλιγμένο σε μια `try`.. `finally`, ή, ένα `using()`μπλοκ). Αλλά ακόμα και αν δεν θυμάστε να καλέσετε `Dispose()`, η μέθοδος finaliser στο αντικείμενο θα πρέπει να καλούν `Dispose()`για εσάς.


Σκέφτηκα ότι αυτό ήταν μια καλή θεραπεία:


[Σκάβοντας σε IDisposable](http://msdn.microsoft.com/en-us/magazine/cc163392.aspx)


και αυτό 


[Κατανόηση IDisposable](http://web.archive.org/web/20090426210049/www.marcclifton.com/tabid/79/Default.aspx)


Δεν υπάρχει κανένα νόημα να προσπαθούμε να μαντέψουμε το δεύτερο το GC και τις στρατηγικές διαχείρισης της επειδή είναι μόνος ρύθμιση και αδιαφανές. Υπήρξε μια καλή συζήτηση για τις εσωτερικές διεργασίες με Jeffrey Ρίχτερ στο Dot Net Rocks εδώ: [Jeffrey Ρίχτερ στο μοντέλο μνήμης των Windows](http://www.dotnetrocks.com/default.aspx?showNum=361) βιβλίου και Richters [CLR μέσω C #](http://www.compman.co.uk/scripts/browse.asp?ref=747022) κεφάλαιο 20 έχει μια πολύ καλή θεραπεία: Νομίζω ότι το κύριο πρακτικό πλεονέκτημα στη μάθηση πράγματα χαμηλού επιπέδου όπως η γλώσσα συναρμολόγησης, δείκτες και διαχείριση μνήμης είναι ότι όταν γράφετε ή την αναθεώρηση κώδικα υψηλού επιπέδου είστε σε θέση καλύτερα να ενστικτωδώς ή υποσυνείδητα ζητήματα τόπου ή άλλες παγίδες.


Ένα μέσο για την ανάπτυξη, θα μπορούσε να γράψει ένα απλό βρόχο και να σκεφτεί, «Αυτός ο κωδικός επαναλαμβάνεται σε ένα σύνολο ακεραίων και γράφει κάθε στην κονσόλα.»


Ένας προγραμματιστής ειδικός μπορεί να γράψει το ίδιο βρόχο και να σκεφτεί, «Αυτός ο κωδικός επαναλαμβάνεται σε μια σειρά ακεραίων, και έχει να κουτί κάθε στοιχείο για να καλέσετε τη μέθοδο toString και toString πρέπει να διαμορφώσετε το κορδόνι στη βάση 10, η οποία είναι κάπως μη τετριμμένη, και τότε τόσο το κουτί ακέραιο και η διαμορφωμένη κλωστή θα είναι σύντομα επιλέξιμες για τη συλλογή των απορριμμάτων, καθώς δεν αναφορές θα παραμείνει, και η πρώτη φορά που αυτή η μέθοδος λειτουργεί, θα πρέπει να JIT'ed ...»και ούτω καθεξής.


9 φορές από τα 10, μπορεί να μην έχει σημασία. Αλλά αυτό 1 ώρα στους 10, ο κύριος του έργου των εμπειρογνωμόνων είναι πιθανό να παρατηρήσετε ένα πρόβλημα στον κώδικα που ο μέσος προγραμματιστής ποτέ δεν θα σκεφτόταν να εξετάσει. Επιστροφή με .Net 1.1 συσκότιση ήταν απαραίτητη: Κωδικός μεταγλώττιση ήταν εύκολο, και θα μπορούσε να πάει από το συγκρότημα, με την IL, με C # κώδικα και έχουν συνταχθεί και πάλι με πολύ λίγη προσπάθεια.


Τώρα με .Net 3.5 δεν είμαι καθόλου σίγουρος. Δοκιμάστε μεταγλώττιση ένα συγκρότημα 3.5? αυτό που παίρνετε είναι μια μακρά μακριά από τη σύνταξη.


Προσθέστε τις βελτιστοποιήσεις από 3,5 (πολύ καλύτερα από 1,1) και τον τρόπο ανώνυμο τύπων, αντιπροσώπους και ούτω καθεξής αντιμετωπίζονται με αντανάκλαση (που είναι ένας εφιάλτης να ξαναμεταγλωττίσετε). Προσθέστε λάμδα εκφράσεις, compiler «μαγεία», όπως Linq-σύνταξη και `var`, και C # 2 λειτουργίες, όπως `yield`(η οποία οδηγεί σε νέες κατηγορίες με δυσανάγνωστο όνομα). Decompiled κωδικό σας καταλήγει σε μεγάλο μακριά από μεταγλωττιστεί.


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


Θα ήθελα να συστήσω-κλειδιά υπογραφή συνελεύσεις σας (που σημαίνει ότι αν οι χάκερ μπορούν να μεταγλωττίσετε ένα που πρέπει να ξαναμεταγλωττίσετε όλα), αλλά δεν νομίζω ότι συσκότιση της αξίζει τον κόπο.