{"id":373,"date":"2024-05-03T18:24:46","date_gmt":"2024-05-03T17:24:46","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=373"},"modified":"2024-06-03T18:24:58","modified_gmt":"2024-06-03T17:24:58","slug":"das-visitor-design-pattern-in-java","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=373","title":{"rendered":"Das Visitor-Design-Pattern in Java"},"content":{"rendered":"\n<p>Das Visitor-Design-Pattern ist eines der Verhaltensmuster der GoF (Gang of Four) und dient dazu, Operationen auf Objekte einer Objektstruktur zu trennen, ohne die Klassen der Objekte \u00e4ndern zu m\u00fcssen, auf denen es arbeitet. Es ist besonders n\u00fctzlich, wenn es darum geht, neue Operationen auf einer bestehenden Objektstruktur hinzuzuf\u00fcgen, ohne die Struktur selbst zu ver\u00e4ndern.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Grundlagen und Motivation<\/h4>\n\n\n\n<p>In vielen Softwareentwicklungsprojekten gibt es Situationen, in denen eine feste Objektstruktur mit unterschiedlichen Arten von Operationen durchlaufen werden muss. Ein klassisches Beispiel ist das Durchlaufen eines Baumes, bei dem verschiedene Operationen wie Drucken, Berechnen oder Exportieren der Inhalte ausgef\u00fchrt werden sollen.<\/p>\n\n\n\n<p>Das Visitor-Design-Pattern bietet eine M\u00f6glichkeit, solche Operationen zu kapseln und getrennt von der Objektstruktur zu definieren. Dadurch wird die Wartbarkeit und Erweiterbarkeit des Codes erheblich verbessert.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Struktur des Patterns<\/h4>\n\n\n\n<p>Das Visitor-Pattern besteht aus den folgenden Hauptkomponenten:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Element<\/strong>: Eine Schnittstelle oder abstrakte Klasse, die eine <code>accept<\/code>-Methode deklariert, welche einen Visitor akzeptiert.<\/li>\n\n\n\n<li><strong>ConcreteElement<\/strong>: Konkrete Klassen, die die Element-Schnittstelle implementieren und die <code>accept<\/code>-Methode definieren.<\/li>\n\n\n\n<li><strong>Visitor<\/strong>: Eine Schnittstelle oder abstrakte Klasse, die eine <code>visit<\/code>-Methode f\u00fcr jedes konkrete Element deklariert.<\/li>\n\n\n\n<li><strong>ConcreteVisitor<\/strong>: Konkrete Klassen, die die Visitor-Schnittstelle implementieren und die spezifischen Operationen definieren.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Beispiel einer Implementierung<\/h4>\n\n\n\n<p>Nehmen wir an, wir haben eine Objektstruktur, die verschiedene Arten von geometrischen Formen enth\u00e4lt: Kreise, Rechtecke und Dreiecke. Wir m\u00f6chten mehrere Operationen wie Berechnung der Fl\u00e4che und das Zeichnen der Formen durchf\u00fchren.<\/p>\n\n\n\n<p>Zuerst definieren wir die <code>Element<\/code>-Schnittstelle:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">Shape<\/span> <\/span>{\n    void accept(ShapeVisitor visitor);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dann definieren wir konkrete Klassen f\u00fcr die verschiedenen Formen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Circle<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">Shape<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> double radius;\n\n    <span class=\"hljs-keyword\">public<\/span> Circle(double radius) {\n        this.radius = radius;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getRadius() {\n        <span class=\"hljs-keyword\">return<\/span> radius;\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void accept(ShapeVisitor visitor) {\n        visitor.visit(this);\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Rectangle<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">Shape<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> double width;\n    <span class=\"hljs-keyword\">private<\/span> double height;\n\n    <span class=\"hljs-keyword\">public<\/span> Rectangle(double width, double height) {\n        this.width = width;\n        this.height = height;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getWidth() {\n        <span class=\"hljs-keyword\">return<\/span> width;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getHeight() {\n        <span class=\"hljs-keyword\">return<\/span> height;\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void accept(ShapeVisitor visitor) {\n        visitor.visit(this);\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Triangle<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">Shape<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> double base;\n    <span class=\"hljs-keyword\">private<\/span> double height;\n\n    <span class=\"hljs-keyword\">public<\/span> Triangle(double base, double height) {\n        this.base = base;\n        this.height = height;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getBase() {\n        <span class=\"hljs-keyword\">return<\/span> base;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getHeight() {\n        <span class=\"hljs-keyword\">return<\/span> height;\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void accept(ShapeVisitor visitor) {\n        visitor.visit(this);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Nun definieren wir die <code>Visitor<\/code>-Schnittstelle:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">interface ShapeVisitor {\n    <span class=\"hljs-keyword\">void<\/span> visit(Circle circle);\n    <span class=\"hljs-keyword\">void<\/span> visit(Rectangle rectangle);\n    <span class=\"hljs-keyword\">void<\/span> visit(Triangle triangle);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Schlie\u00dflich erstellen wir konkrete Visitor-Klassen, die die spezifischen Operationen implementieren. Beispielsweise eine Klasse zum Berechnen der Fl\u00e4che:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AreaCalculator<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">ShapeVisitor<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> double totalArea = <span class=\"hljs-number\">0<\/span>;\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Circle circle) {\n        double area = Math.PI * Math.pow(circle.getRadius(), <span class=\"hljs-number\">2<\/span>);\n        totalArea += area;\n        System.out.println(<span class=\"hljs-string\">\"Circle area: \"<\/span> + area);\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Rectangle rectangle) {\n        double area = rectangle.getWidth() * rectangle.getHeight();\n        totalArea += area;\n        System.out.println(<span class=\"hljs-string\">\"Rectangle area: \"<\/span> + area);\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Triangle triangle) {\n        double area = <span class=\"hljs-number\">0.5<\/span> * triangle.getBase() * triangle.getHeight();\n        totalArea += area;\n        System.out.println(<span class=\"hljs-string\">\"Triangle area: \"<\/span> + area);\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> double getTotalArea() {\n        <span class=\"hljs-keyword\">return<\/span> totalArea;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Eine weitere Klasse f\u00fcr das Zeichnen der Formen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ShapeDrawer<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">ShapeVisitor<\/span> <\/span>{\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Circle circle) {\n        System.out.println(<span class=\"hljs-string\">\"Drawing a Circle with radius: \"<\/span> + circle.getRadius());\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Rectangle rectangle) {\n        System.out.println(<span class=\"hljs-string\">\"Drawing a Rectangle with width: \"<\/span> + rectangle.getWidth() + <span class=\"hljs-string\">\" and height: \"<\/span> + rectangle.getHeight());\n    }\n\n    @Override\n    <span class=\"hljs-keyword\">public<\/span> void visit(Triangle triangle) {\n        System.out.println(<span class=\"hljs-string\">\"Drawing a Triangle with base: \"<\/span> + triangle.getBase() + <span class=\"hljs-string\">\" and height: \"<\/span> + triangle.getHeight());\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Anwendung des Visitor-Patterns<\/h4>\n\n\n\n<p>Um das Visitor-Pattern zu verwenden, erstellen wir eine Sammlung von Formen und lassen jeden Visitor die Sammlung durchlaufen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">VisitorPatternDemo<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> void main(String&#91;] args) {\n        <span class=\"hljs-keyword\">List<\/span>&lt;Shape&gt; shapes = <span class=\"hljs-keyword\">new<\/span> ArrayList&lt;&gt;();\n        shapes.add(<span class=\"hljs-keyword\">new<\/span> Circle(<span class=\"hljs-number\">5<\/span>));\n        shapes.add(<span class=\"hljs-keyword\">new<\/span> Rectangle(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">6<\/span>));\n        shapes.add(<span class=\"hljs-keyword\">new<\/span> Triangle(<span class=\"hljs-number\">3<\/span>, <span class=\"hljs-number\">4<\/span>));\n\n        AreaCalculator areaCalculator = <span class=\"hljs-keyword\">new<\/span> AreaCalculator();\n        ShapeDrawer shapeDrawer = <span class=\"hljs-keyword\">new<\/span> ShapeDrawer();\n\n        <span class=\"hljs-keyword\">for<\/span> (Shape shape : shapes) {\n            shape.accept(areaCalculator);\n            shape.accept(shapeDrawer);\n        }\n\n        System.out.println(<span class=\"hljs-string\">\"Total area: \"<\/span> + areaCalculator.getTotalArea());\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In diesem Beispiel haben wir zwei verschiedene Besucher (Visitor): einen, der die Fl\u00e4che berechnet, und einen, der die Formen zeichnet. Jeder Form (Element) wird die M\u00f6glichkeit gegeben, die Operationen des Besuchers zu akzeptieren und spezifisch darauf zu reagieren.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Vorteile des Visitor-Design-Patterns<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Offen\/geschlossenes Prinzip<\/strong>: Die Klassenstruktur der Elemente bleibt unver\u00e4ndert, w\u00e4hrend neue Operationen hinzugef\u00fcgt werden k\u00f6nnen.<\/li>\n\n\n\n<li><strong>Erweiterbarkeit<\/strong>: Neue Operationen k\u00f6nnen einfach durch Hinzuf\u00fcgen neuer Visitor-Klassen hinzugef\u00fcgt werden, ohne die Elementklassen zu \u00e4ndern.<\/li>\n\n\n\n<li><strong>Trennung der Bedenken<\/strong>: Die Logik der Operationen ist von der Struktur der Elemente getrennt, was die Wartbarkeit und Verst\u00e4ndlichkeit des Codes erh\u00f6ht.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Nachteile des Visitor-Design-Patterns<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Komplexit\u00e4t<\/strong>: Das Hinzuf\u00fcgen von neuen Elementtypen erfordert \u00c4nderungen in allen bestehenden Visitor-Klassen, was den Vorteil der einfachen Erweiterbarkeit einschr\u00e4nkt.<\/li>\n\n\n\n<li><strong>Zugriff auf interne Daten<\/strong>: Visitor-Klassen m\u00fcssen m\u00f6glicherweise auf die internen Daten der Elemente zugreifen, was gegen das Prinzip der Kapselung versto\u00dfen kann.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Fazit<\/h4>\n\n\n\n<p>Das Visitor-Design-Pattern ist ein m\u00e4chtiges Werkzeug zur Trennung von Algorithmen und der Struktur von Objekten, auf denen sie operieren. Es erm\u00f6glicht es, neue Operationen hinzuzuf\u00fcgen, ohne die bestehenden Strukturen zu ver\u00e4ndern, und f\u00f6rdert die Einhaltung des offen\/geschlossen Prinzips. In Java ist es besonders n\u00fctzlich, wenn eine stabile Objektstruktur mit h\u00e4ufig wechselnden Operationen vorliegt.<\/p>\n\n\n\n<p>Trotz seiner Vorteile sollte das Visitor-Pattern mit Bedacht eingesetzt werden, da es die Komplexit\u00e4t des Systems erh\u00f6hen und die Kapselung brechen kann. Wie bei allen Design-Patterns ist es wichtig, die spezifischen Anforderungen und Einschr\u00e4nkungen des Projekts zu ber\u00fccksichtigen, bevor man sich f\u00fcr dessen Einsatz entscheidet.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Das Visitor-Design-Pattern ist eines der Verhaltensmuster der GoF (Gang of Four) und dient dazu, Operationen auf Objekte einer Objektstruktur zu trennen, ohne die Klassen der Objekte \u00e4ndern zu m\u00fcssen, auf denen es arbeitet. Es ist besonders n\u00fctzlich, wenn es darum geht, neue Operationen auf einer bestehenden Objektstruktur hinzuzuf\u00fcgen, ohne die Struktur selbst zu ver\u00e4ndern. Grundlagen [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-373","post","type-post","status-publish","format-standard","hentry","category-plain_java"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/373","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=373"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/373\/revisions"}],"predecessor-version":[{"id":374,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/373\/revisions\/374"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}