{"id":2087,"date":"2019-06-25T22:00:52","date_gmt":"2019-06-25T19:00:52","guid":{"rendered":"http:\/\/demensdeum.com\/blog\/?p=2087"},"modified":"2024-12-16T22:32:36","modified_gmt":"2024-12-16T19:32:36","slug":"%d0%a1%d1%82%d0%b5%d0%b9%d1%82-%d0%bc%d0%b0%d1%88%d0%b8%d0%bd%d0%b0-%d0%b8-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%a1%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%b8%d0%b5","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/de\/2019\/06\/25\/%d0%a1%d1%82%d0%b5%d0%b9%d1%82-%d0%bc%d0%b0%d1%88%d0%b8%d0%bd%d0%b0-%d0%b8-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%a1%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%b8%d0%b5\/","title":{"rendered":"Zustandsmaschine und Musterbedingung"},"content":{"rendered":"<p>In diesem Artikel werde ich die Verwendung der Zustandsmaschine (State Machine) beschreiben und eine einfache Implementierung zeigen, eine Implementierung unter Verwendung des Zustandsmusters. Es ist erw\u00e4hnenswert, dass es unerw\u00fcnscht ist, das Statusmuster zu verwenden, wenn es weniger als drei Zust\u00e4nde gibt, weil Dies f\u00fchrt normalerweise zu einer unn\u00f6tigen Komplexit\u00e4t der Codelesbarkeit und damit verbundenen Supportproblemen &#8211; Alles sollte in Ma\u00dfen erfolgen.<\/p>\n<figure id=\"attachment_2088\" aria-describedby=\"caption-attachment-2088\" style=\"width: 510px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-2088\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2019\/06\/flags.jpg\" alt=\"\" width=\"510\" height=\"190\" \/><figcaption id=\"caption-attachment-2088\" class=\"wp-caption-text\">MEAACT PHOTO \/ STUART PRICE.<\/figcaption><\/figure>\n<h3>Herr der Flaggen<\/h3>\n<p>Angenommen, wir entwickeln einen Videoplayer-Bildschirm f\u00fcr das Mediensystem eines Zivilflugzeugs. Der Player muss in der Lage sein, einen Videostream zu laden und abzuspielen, dem Benutzer das Stoppen des Downloadvorgangs, das Zur\u00fcckspulen und die Ausf\u00fchrung anderer \u00fcblicher Vorg\u00e4nge zu erm\u00f6glichen ein Spieler.<br \/>Nehmen wir an, der Player hat den n\u00e4chsten Teil des Videostreams zwischengespeichert, \u00fcberpr\u00fcft, ob gen\u00fcgend Teile f\u00fcr die Wiedergabe vorhanden sind, hat mit der Wiedergabe des Fragments f\u00fcr den Benutzer begonnen und f\u00e4hrt gleichzeitig mit dem Herunterladen des n\u00e4chsten Teils fort.<br \/>In diesem Moment spult der Benutzer zur Mitte des Videos zur\u00fcck, d. h. Sie m\u00fcssen jetzt die Wiedergabe des aktuellen Fragments stoppen und an einer neuen Position mit dem Laden beginnen. Es gibt jedoch Situationen, in denen dies nicht m\u00f6glich ist &#8211; Der Benutzer kann die Wiedergabe des Videostreams nicht steuern, w\u00e4hrend ihm ein Video \u00fcber Flugsicherheit gezeigt wird. Lassen Sie uns das isSafetyVideoPlaying-Flag \u00fcberpr\u00fcfen, um diese Situation zu \u00fcberpr\u00fcfen.<br \/>Das System muss au\u00dferdem in der Lage sein, das aktuelle Video anzuhalten und \u00fcber den Player eine Warnung des Schiffskapit\u00e4ns und der Schiffsbesatzung zu senden. F\u00fcgen wir ein weiteres isAnnouncementPlaying-Flag hinzu. Au\u00dferdem besteht die Anforderung, die Wiedergabe nicht anzuhalten, w\u00e4hrend Hilfe zur Arbeit mit dem Player angezeigt wird. Ein weiteres Flag ist HelpPresenting.<\/p>\n<p>Beispiel-Pseudocode f\u00fcr einen Mediaplayer:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>class MediaPlayer {\n\n    public var isHelpPresenting = false\n    public var isCaching = false\n    public var isMediaPlaying: Bool = false\n    public var isAnnouncementPlaying = false\n    public var isSafetyVideoPlaying = false\n\n    public var currentMedia: Media = null\n\n    fun play(media: Media) {\n\n        if isMediaPlaying == false, isAnnouncementPlaying == false, isSafetyVideoPlaying == false {\n\n            if isCaching == false {\n                if isHelpPresenting == false {\n                    media.playAfterHelpClosed()\n                }\n                else {\n                    media.playAfterCaching()\n                }\n            }\n    }\n\n    fun pause() {\n        if isAnnouncementPlaying == false, isSafetyVideoPlaying == false {\n            currentMedia.pause()\n        }\n    }\n}\n<\/code><\/pre>\n<\/div>\n<p>Das obige Beispiel ist aufgrund der hohen Variabilit\u00e4t (Entropie) schwer zu lesen und schwer zu warten. Dieses Beispiel basiert auf meiner Erfahrung mit der Codebasis *vieler* Projekte, die keine Zustandsmaschine verwendeten.<br \/ >Jedes Kontrollk\u00e4stchen muss speziell die Elemente der Schnittstelle und der Gesch\u00e4ftslogik der Anwendung \u201esteuern\u201c. Durch das Hinzuf\u00fcgen eines weiteren Kontrollk\u00e4stchens muss der Entwickler in der Lage sein, sie zu jonglieren und alles mehrmals mit allen m\u00f6glichen Optionen zu \u00fcberpr\u00fcfen.<br \/>Durch Einsetzen in die Formel \u201e2 ^ Anzahl der Kontrollk\u00e4stchen\u201c erhalten Sie 2 ^ 6 = 64 Optionen f\u00fcr das Anwendungsverhalten f\u00fcr nur 6 Kontrollk\u00e4stchen. Alle diese Kombinationen von Kontrollk\u00e4stchen m\u00fcssen manuell \u00fcberpr\u00fcft und verwaltet werden.<br \/>Aus Sicht des Entwicklers sieht das Hinzuf\u00fcgen neuer Funktionen mit einem solchen System folgenderma\u00dfen aus:<br \/>&#8211; Wir m\u00fcssen die M\u00f6glichkeit hinzuf\u00fcgen, die Browserseite der Fluggesellschaft anzuzeigen, und sie sollte wie bei Filmen minimiert werden, wenn Besatzungsmitglieder etwas ank\u00fcndigen.<br \/>&#8211; Ok, ich werde es tun. (Oh verdammt, ich muss eine weitere Flagge hinzuf\u00fcgen und alle Stellen, an denen sich die Flaggen kreuzen, noch einmal \u00fcberpr\u00fcfen, das sind viele Dinge, die ge\u00e4ndert werden m\u00fcssen!)<\/p>\n<p>Auch ein Schwachpunkt des Flaggensystems &#8211; \u00c4nderungen am Verhalten der Anwendung vornehmen. Es ist sehr schwer vorstellbar, wie man das Verhalten anhand von Flags schnell\/flexibel \u00e4ndern kann, wenn man nach der \u00c4nderung nur eines Flags alles noch einmal \u00fcberpr\u00fcfen muss. Dieser Entwicklungsansatz f\u00fchrt zu vielen Problemen, Zeit- und Geldverlusten.<\/p>\n<h3>Betreten Sie die Maschine<\/h3>\n<p>Wenn Sie sich die Flags genau ansehen, k\u00f6nnen Sie verstehen, dass wir tats\u00e4chlich versuchen, bestimmte Prozesse zu verarbeiten, die in der realen Welt auftreten. Wir listen sie auf: Normalmodus, Anzeige eines Sicherheitsvideos, \u00dcbertragung einer Nachricht des Kapit\u00e4ns oder der Besatzungsmitglieder. F\u00fcr jeden Prozess ist ein Regelwerk bekannt, das das Verhalten der Anwendung ver\u00e4ndert.<br \/>Gem\u00e4\u00df den Regeln des State-Machine-Musters (State-Machine) werden wir alle Prozesse als Zust\u00e4nde in der Aufz\u00e4hlung auflisten, ein solches Konzept als Zustand zum Player-Code hinzuf\u00fcgen und zustandsbasiertes Verhalten implementieren, indem wir Kombinationen auf den Flags entfernen. Dadurch reduzieren wir die Testm\u00f6glichkeiten auf genau die Anzahl der Zust\u00e4nde.<\/p>\n<p>Pseudocode:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>enum MediaPlayerState {\n\tmediaPlaying,\n\tmediaCaching,\n\tcrewSpeaking,\n\tsafetyVideoPlaying,\n\tpresentingHelp\n}\n\nclass MediaPlayer {\n\tfun play(media: Media) {\n\t\tmedia.play()\n\t}\n\n\tfunc pause() {\n\t\tmedia.pause()\n\t}\n}\n\nclass MediaPlayerStateMachine {\n\tpublic state: MediaPlayerState\n\tpublic mediaPlayer: MediaPlayer\n\tpublic currentMedia: Media\n\n\t\/\/.. init (mediaPlayer) etc\n\n\tpublic fun set(state: MediaPlayerState) {\n\t\tswitch state {\n\t\t\tcase mediaPlaying:\n\t\t\t\tmediaPlayer.play(currentMedia)\n\t\t\tcase mediaCaching, crewSpeaking,\n\t\t\tsafetyVideoPlaying, presentingHelp:\n\t\t\t\tmediaPlayer.pause()\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<\/div>\n<p>Der gro\u00dfe Unterschied zwischen einem Flag-System und einer Zustandsmaschine ist der logische Zustandsschalttrichter in der set(state: ..)-Methode, der es Ihnen erm\u00f6glicht, das menschliche Verst\u00e4ndnis des Zustands in Programmcode zu \u00fcbersetzen, ohne sich mit Logik auseinandersetzen zu m\u00fcssen Spiele zum Konvertieren von Flags in Zust\u00e4nde bei weiterer Codeunterst\u00fctzung.<\/p>\n<h3>Musterstatus<\/h3>\n<p>Als n\u00e4chstes werde ich den Unterschied zwischen der naiven Implementierung der Zustandsmaschine und dem Zustandsmuster zeigen. Stellen wir uns vor, wir m\u00fcssten 10 Zust\u00e4nde hinzuf\u00fcgen. Dadurch w\u00e4chst die Zustandsmaschinenklasse auf die Gr\u00f6\u00dfe eines Gottobjekts, dessen Wartung schwierig und kostspielig sein wird. Nat\u00fcrlich ist diese Implementierung besser als die Flag-Implementierung (mit dem Flag-System erschie\u00dft sich der Entwickler zuerst selbst, und wenn nicht, dann h\u00e4ngt sich die Qualit\u00e4tssicherung bei 2 ^ 10 = 1024 Variationen auf, aber wenn beide *nicht tun Beachten* Sie die Komplexit\u00e4t der Aufgabe, dann wird der Benutzer, dessen Anwendung einfach ist, bemerken, dass sie sich weigert, mit einer bestimmten Kombination von Flags zu arbeiten)<br \/>Bei einer gro\u00dfen Anzahl von Zust\u00e4nden ist die Verwendung des Zustandsmusters erforderlich.<br \/>F\u00fcgen wir dem State-Protokoll eine Reihe von Regeln hinzu:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>protocol State {\n    func playMedia(media: Media, context: MediaPlayerContext)\n    func shouldCacheMedia(context: MediaPlayerContext)\n    func crewSpeaking(context: MediaPlayerContext)\n    func safetyVideoPlaying(context:MediaPlayerContext)\n    func presentHelp(context: MediaPlayerContext)\n}\n<\/code><\/pre>\n<\/div>\n<p>Lassen Sie uns die Implementierung des Regelsatzes in separate Zust\u00e4nde verschieben, zum Beispiel den Code f\u00fcr einen Zustand:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>class CrewSpeakingState: State {\n\tfunc playMedia(context: MediaPlayerContext) {\n\t\tshowWarning(\u201cCan\u2019 t play media - listen to announce!\u201d)\n\t}\n\n\tfunc mediaCaching(context: MediaPlayerContext) {\n\t\tshowActivityIndicator()\n\t}\n\n\tfunc crewSpeaking(context: MediaPlayerContext) {\n\t\tset(volume: 100)\n\t}\n\n\tfunc safetyVideoPlaying(context: MediaPlayerContext) {\n\t\tset(volume: 100)\n\t}\n\n\tfunc presentHelp(context: MediaPlayerContext) {\n\t\tshowWarning(\u201cCan\u2019 t present help - listen to announce!\u201d)\n\t}\n}\n<\/code><\/pre>\n<\/div>\n<p>Als n\u00e4chstes erstellen wir einen Kontext, mit dem jeder Zustand arbeiten wird, und integrieren die Zustandsmaschine:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>final class MediaPlayerContext {\n\tprivate\n\tvar state: State\n\n\tpublic fun set(state: State) {\n\t\tself.state = state\n\t}\n\n\tpublic fun play(media: Media) {\n\t\tstate.play(media: media, context: this)\n\t}\n\n\t\u2026\n\t\u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\n}\n<\/code><\/pre>\n<\/div>\n<p>Anwendungskomponenten arbeiten mit dem Kontext \u00fcber \u00f6ffentliche Methoden; Zustandsobjekte entscheiden selbst, von welchem \u200b\u200bZustand aus sie \u00fcber die Zustandsmaschine innerhalb des Kontexts wechseln.<br \/>Daher haben wir die God-Object-Zerlegung implementiert. Die Aufrechterhaltung eines sich \u00e4ndernden Zustands wird viel einfacher, da der Compiler \u00c4nderungen im Protokoll verfolgt und die Komplexit\u00e4t des Verst\u00e4ndnisses von Zust\u00e4nden aufgrund der Reduzierung der Anzahl der Codezeilen verringert und sich darauf konzentriert L\u00f6sung eines bestimmten Staatsproblems. Sie k\u00f6nnen jetzt auch die Arbeit in einem Team teilen und Teammitgliedern die Implementierung eines bestimmten Zustands \u00fcbertragen, ohne sich Gedanken \u00fcber die Notwendigkeit machen zu m\u00fcssen, Konflikte zu \u201el\u00f6sen\u201c, was bei der Arbeit mit einer gro\u00dfen Zustandsmaschinenklasse der Fall ist.<\/p>\n<h3>Quellen<\/h3>\n<p><a href=\"https:\/\/refactoring.guru\/ru\/design-patterns\/state\" target=\"_blank\" rel=\"noopener\">https:\/\/refactoring.guru\/ru\/design-patterns\/state <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Artikel werde ich die Verwendung der Zustandsmaschine (State Machine) beschreiben und eine einfache Implementierung zeigen, eine Implementierung unter Verwendung des Zustandsmusters. Es ist erw\u00e4hnenswert, dass es unerw\u00fcnscht ist, das Statusmuster zu verwenden, wenn es weniger als drei Zust\u00e4nde gibt, weil Dies f\u00fchrt normalerweise zu einer unn\u00f6tigen Komplexit\u00e4t der Codelesbarkeit und damit verbundenen Supportproblemen<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/de\/2019\/06\/25\/%d0%a1%d1%82%d0%b5%d0%b9%d1%82-%d0%bc%d0%b0%d1%88%d0%b8%d0%bd%d0%b0-%d0%b8-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%a1%d0%be%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%b8%d0%b5\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Zustandsmaschine und Musterbedingung&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[95,109],"class_list":["post-2087","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-patterns","tag-state","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"de","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/posts\/2087","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/comments?post=2087"}],"version-history":[{"count":14,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/posts\/2087\/revisions"}],"predecessor-version":[{"id":3952,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/posts\/2087\/revisions\/3952"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/media?parent=2087"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/categories?post=2087"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/de\/wp-json\/wp\/v2\/tags?post=2087"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}