„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Den perfekten Code erstellen: Erstellungsmuster verstehen

Den perfekten Code erstellen: Erstellungsmuster verstehen

Veröffentlicht am 25.08.2024
Durchsuche:614

Creating the Perfect Code: Understanding Creational Patterns

Dies ist der Beginn einer Reihe von Blogs über Designmuster. In diesem Blog besprechen wir die erste Art von Designmustern, Creational Patterns. Hier werden die Typen, die unter Schöpfungsmuster fallen, anhand einiger Beispiele aus der Praxis besprochen. Ich werde Java als Sprache meiner Wahl verwenden.

Was sind Designmuster?

Designmuster spielen eine entscheidende Rolle in der Softwareentwicklung, da sie bewährte Lösungen für häufige Probleme bereitstellen und Best Practices fördern. Sie sind wie vorgefertigte Blaupausen, die Sie anpassen können, um ein wiederkehrendes Designproblem in Ihrem Code zu lösen.

Erkundung kreativer Designmuster in Java

In der objektorientierten Programmierung spielen kreative Entwurfsmuster eine wichtige Rolle, da sie es ermöglichen, die Instanziierung von Objekten von ihrer Nutzung zu trennen und so die Flexibilität und Skalierbarkeit der Objekterstellung zu erhöhen. Dieser Blogbeitrag konzentriert sich auf fünf Haupttypen kreativer Designmuster: Factory Method, Abstract Factory, Builder, Prototype und Singleton. Um zu zeigen, wie jedes einzelne funktioniert, verwenden wir Beispiele aus der realen Welt in Java.

1. Factory-Methode

Das Factory-Methodenmuster definiert eine Schnittstelle zum Erstellen eines Objekts, ermöglicht jedoch Unterklassen, den Typ der zu erstellenden Objekte zu ändern. Dieses Muster unterstützt die lose Kopplung in Java, um die Notwendigkeit zu vermeiden, anwendungsspezifische Klassen in den Code einzubinden.

Realistisches Szenario: Stellen Sie sich ein Logistikunternehmen vor, das Waren mit verschiedenen Fahrzeugen wie Lastkraftwagen und Schiffen transportiert. Der Fahrzeugtyp hängt vom benötigten Transportmittel ab.

// Product Interface
interface Transport {
    void deliver();
}

// Concrete Products
class Truck implements Transport {
    @Override
    public void deliver() {
        System.out.println("Deliver by land in a truck.");
    }
}

class Ship implements Transport {
    @Override
    public void deliver() {
        System.out.println("Deliver by sea in a ship.");
    }
}

// Creator
abstract class Logistics {
    public abstract Transport createTransport();

    public void planDelivery() {
        Transport transport = createTransport();
        transport.deliver();
    }
}

// Concrete Creators
class RoadLogistics extends Logistics {
    @Override
    public Transport createTransport() {
        return new Truck();
    }
}

class SeaLogistics extends Logistics {
    @Override
    public Transport createTransport() {
        return new Ship();
    }
}

// let's call the main class
public class Main {
    public static void main(String[] args) {
        Logistics logistics = new RoadLogistics();
        logistics.planDelivery();

        logistics = new SeaLogistics();
        logistics.planDelivery();
    }
}

2. Abstrakte Fabrik

Das Abstract Factory-Muster bietet eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte, ohne deren konkrete Klassen anzugeben. Dies ist nützlich, wenn das System unabhängig davon sein muss, wie seine Objekte erstellt werden.

Realistisches Szenario: Stellen Sie sich ein Möbelgeschäft vor, das verschiedene Arten von Möbelsets verkauft, beispielsweise viktorianische und moderne Möbel. Jedes Set umfasst Produkte wie Stühle und Sofas.

// Abstract Products
interface Chair {
    void sitOn();
}

interface Sofa {
    void lieOn();
}

// Concrete Products
class VictorianChair implements Chair {
    @Override
    public void sitOn() {
        System.out.println("Sitting on a Victorian chair.");
    }
}

class ModernChair implements Chair {
    @Override
    public void sitOn() {
        System.out.println("Sitting on a Modern chair.");
    }
}

class VictorianSofa implements Sofa {
    @Override
    public void lieOn() {
        System.out.println("Lying on a Victorian sofa.");
    }
}

class ModernSofa implements Sofa {
    @Override
    public void lieOn() {
        System.out.println("Lying on a Modern sofa.");
    }
}

// Abstract Factory
interface FurnitureFactory {
    Chair createChair();
    Sofa createSofa();
}

// Concrete Factories
class VictorianFurnitureFactory implements FurnitureFactory {
    @Override
    public Chair createChair() {
        return new VictorianChair();
    }

    @Override
    public Sofa createSofa() {
        return new VictorianSofa();
    }
}

class ModernFurnitureFactory implements FurnitureFactory {
    @Override
    public Chair createChair() {
        return new ModernChair();
    }

    @Override
    public Sofa createSofa() {
        return new ModernSofa();
    }
}

// Client code
public class Main {
    private static void createFurniture(FurnitureFactory factory) {
        Chair chair = factory.createChair();
        Sofa sofa = factory.createSofa();
        chair.sitOn();
        sofa.lieOn();
    }

    public static void main(String[] args) {
        FurnitureFactory victorianFactory = new VictorianFurnitureFactory();
        createFurniture(victorianFactory);

        FurnitureFactory modernFactory = new ModernFurnitureFactory();
        createFurniture(modernFactory);
    }
}

3. Bauherr

Das Builder-Muster trennt die Konstruktion eines komplexen Objekts von seiner Darstellung, sodass mit demselben Konstruktionsprozess unterschiedliche Darstellungen erstellt werden können. Es ist besonders nützlich zum Erstellen von Objekten mit vielen optionalen Attributen.

Realistisches Szenario: Stellen Sie sich ein Online-Pizza-Bestellsystem vor, bei dem Kunden ihre Pizzen mit verschiedenen Belägen, Größen und Krustenarten individuell gestalten können.

// Product
class Pizza {
    private String dough = "";
    private String sauce = "";
    private String topping = "";

    public void setDough(String dough) { this.dough = dough; }
    public void setSauce(String sauce) { this.sauce = sauce; }
    public void setTopping(String topping) { this.topping = topping; }

    @Override
    public String toString() {
        return "Pizza [dough="   dough   ", sauce="   sauce   ", topping="   topping   "]";
    }
}

// Builder Interface
interface PizzaBuilder {
    void buildDough();
    void buildSauce();
    void buildTopping();
    Pizza getPizza();
}

// Concrete Builders
class HawaiianPizzaBuilder implements PizzaBuilder {
    private Pizza pizza;

    public HawaiianPizzaBuilder() {
        this.pizza = new Pizza();
    }

    @Override
    public void buildDough() { pizza.setDough("cross"); }
    @Override
    public void buildSauce() { pizza.setSauce("mild"); }
    @Override
    public void buildTopping() { pizza.setTopping("ham pineapple"); }
    @Override
    public Pizza getPizza() { return this.pizza; }
}

class SpicyPizzaBuilder implements PizzaBuilder {
    private Pizza pizza;

    public SpicyPizzaBuilder() {
        this.pizza = new Pizza();
    }

    @Override
    public void buildDough() { pizza.setDough("pan baked"); }
    @Override
    public void buildSauce() { pizza.setSauce("hot"); }
    @Override
    public void buildTopping() { pizza.setTopping("pepperoni salami"); }
    @Override
    public Pizza getPizza() { return this.pizza; }
}

// Director
class Waiter {
    private PizzaBuilder pizzaBuilder;

    public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
    public Pizza getPizza() { return pizzaBuilder.getPizza(); }

    public void constructPizza() {
        pizzaBuilder.buildDough();
        pizzaBuilder.buildSauce();
        pizzaBuilder.buildTopping();
    }
}

// Client code
public class Main {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
        PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

        waiter.setPizzaBuilder(hawaiianPizzaBuilder);
        waiter.constructPizza();
        Pizza pizza1 = waiter.getPizza();
        System.out.println("Pizza built: "   pizza1);

        waiter.setPizzaBuilder(spicyPizzaBuilder);
        waiter.constructPizza();
        Pizza pizza2 = waiter.getPizza();
        System.out.println("Pizza built: "   pizza2);
    }
}

4. Prototyp

Das Prototype-Muster wird verwendet, um ein neues Objekt zu erstellen, indem ein vorhandenes Objekt kopiert wird, das als Prototyp bezeichnet wird. Dieses Muster ist nützlich, wenn die Kosten für die Erstellung eines neuen Objekts hoch sind.

Realistisches Szenario: Stellen Sie sich einen grafischen Editor vor, mit dem Sie Formen erstellen, duplizieren und bearbeiten können.

import java.util.HashMap;
import java.util.Map;

// Prototype
abstract class Shape implements Cloneable {
    private String id;
    protected String type;

    abstract void draw();

    public String getType() { return type; }
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

// Concrete Prototypes
class Rectangle extends Shape {
    public Rectangle() { type = "Rectangle"; }
    @Override
    public void draw() { System.out.println("Drawing a Rectangle."); }
}

class Circle extends Shape {
    public Circle() { type = "Circle"; }
    @Override
    public void draw() { System.out.println("Drawing a Circle."); }
}

// Prototype Registry
class ShapeCache {
    private static Map shapeMap = new HashMap();

    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }

    public static void loadCache() {
        Rectangle rectangle = new Rectangle();
        rectangle.setId("1");
        shapeMap.put(rectangle.getId(), rectangle);

        Circle circle = new Circle();
        circle.setId("2");
        shapeMap.put(circle.getId(), circle);
    }
}

// Client code
public class Main {
    public static void main(String[] args) {
        ShapeCache.loadCache();

        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape: "   clonedShape1.getType());

        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape: "   clonedShape2.getType());
    }
}

5. Singleton

Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat und bietet einen globalen Zugriffspunkt darauf. Dieses Muster wird häufig für Protokollierung, Caching und Thread-Pools verwendet.

Realistisches Szenario: Stellen Sie sich einen Druckerspooler vor, bei dem nur eine Instanz alle Druckaufträge verwalten sollte.

class PrinterSpooler {
    private static PrinterSpooler instance;

    private PrinterSpooler() {
        // private constructor to prevent instantiation
    }

    public static PrinterSpooler getInstance() {
        if (instance == null) {
            instance = new PrinterSpooler();
        }
        return instance;
    }

    public void print(String document) {
        System.out.println("Printing document: "   document);
    }
}

// Client code
public class Main {
    public static void main(String[] args) {
        PrinterSpooler spooler1 = PrinterSpooler.getInstance();
        PrinterSpooler spooler2 = PrinterSpooler.getInstance();

        spooler1.print("Document 1");
        spooler2.print("Document 2");

        System.out.println("Are both spoolers the same instance? "   (spooler1 == spooler2));
    }
}

Referenzen

https://refactoring.guru/

https://www.javatpoint.com/design-patterns-in-java

https://www.digitalocean.com/community/tutorials/java-design-patterns-example-tutorial

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/tharindufdo/creating-the-perfect-code-understanding-creational-patterns-1ld6?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3