Entwurfsmuster-Kurzanleitung

Entwurfsmuster stellen die Best Practices dar, die von erfahrenen objektorientierten Softwareentwicklern verwendet werden. Entwurfsmuster sind Lösungen für allgemeine Probleme, mit denen Softwareentwickler während der Softwareentwicklung konfrontiert waren. Diese Lösungen wurden von zahlreichen Softwareentwicklern über einen längeren Zeitraum durch Ausprobieren erhalten.

Was ist Gang of Four (GOF)?

1994 veröffentlichten vier Autoren, Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides, ein Buch mit dem Titel Design Patterns - Elements of Reusable Object-Oriented Software das initiierte das Konzept des Design Pattern in der Softwareentwicklung.

Diese Autoren sind zusammen bekannt als Gang of Four (GOF). Diesen Autoren zufolge basieren Entwurfsmuster hauptsächlich auf den folgenden Prinzipien des objektorientierten Entwurfs.

  • Programmieren Sie auf eine Schnittstelle, keine Implementierung

  • Bevorzugen Sie die Objektzusammensetzung gegenüber der Vererbung

Verwendung des Entwurfsmusters

Entwurfsmuster haben zwei Hauptverwendungen in der Softwareentwicklung.

Gemeinsame Plattform für Entwickler

Entwurfsmuster bieten eine Standardterminologie und sind spezifisch für ein bestimmtes Szenario. Beispielsweise bedeutet ein Singleton-Entwurfsmuster die Verwendung eines einzelnen Objekts, sodass alle Entwickler, die mit einem einzelnen Entwurfsmuster vertraut sind, ein einzelnes Objekt verwenden und sich gegenseitig mitteilen können, dass das Programm einem Singleton-Muster folgt.

Empfohlene Vorgehensweise

Entwurfsmuster wurden über einen langen Zeitraum entwickelt und bieten die besten Lösungen für bestimmte Probleme, die während der Softwareentwicklung auftreten. Das Erlernen dieser Muster hilft unerfahrenen Entwicklern, Software-Design auf einfache und schnellere Weise zu erlernen.

Arten von Entwurfsmustern

Gemäß dem Nachschlagewerk für Entwurfsmuster Design Patterns - Elements of Reusable Object-Oriented Softwaregibt es 23 Entwurfsmuster. Diese Muster können in drei Kategorien eingeteilt werden: Kreations-, Struktur- und Verhaltensmuster. Wir werden auch eine andere Kategorie von Entwurfsmustern diskutieren: J2EE-Entwurfsmuster.

SN Muster & Beschreibung
1 Creational Patterns
Diese Entwurfsmuster bieten die Möglichkeit, Objekte zu erstellen, während die Erstellungslogik ausgeblendet wird, anstatt Objekte direkt mit dem neuen Operator zu instanziieren. Dies gibt dem Programm mehr Flexibilität bei der Entscheidung, welche Objekte für einen bestimmten Anwendungsfall erstellt werden müssen.
2 Structural Patterns
Diese Entwurfsmuster betreffen die Klassen- und Objektzusammensetzung. Das Konzept der Vererbung wird verwendet, um Schnittstellen zu erstellen und Möglichkeiten zum Erstellen von Objekten zu definieren, um neue Funktionen zu erhalten.
3 Behavioral Patterns
Diese Entwurfsmuster befassen sich speziell mit der Kommunikation zwischen Objekten.
4 J2EE Patterns
Diese Entwurfsmuster betreffen speziell die Präsentationsebene. Diese Muster werden von Sun Java Center identifiziert.

Das Factory-Muster ist eines der am häufigsten verwendeten Entwurfsmuster in Java. Diese Art von Entwurfsmuster fällt unter das Erstellungsmuster, da dieses Muster eine der besten Möglichkeiten zum Erstellen eines Objekts bietet.

Im Factory-Muster erstellen wir ein Objekt, ohne die Erstellungslogik dem Client zur Verfügung zu stellen, und verweisen über eine gemeinsame Schnittstelle auf neu erstellte Objekte.

Implementierung

Wir werden eine Shape- Schnittstelle und konkrete Klassen erstellen, die die Shape- Schnittstelle implementieren . Als nächster Schritt wird eine Factory-Klasse ShapeFactory definiert.

FactoryPatternDemo , unsere Demo-Klasse, verwendet ShapeFactory , um ein Shape- Objekt abzurufen . Es werden Informationen ( CIRCLE / RECTANGLE / SQUARE ) an ShapeFactory übergeben , um den Objekttyp zu erhalten, den es benötigt.

Schritt 1

Erstellen Sie eine Schnittstelle.

Shape.java

public interface Shape {
   void draw();
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

Rectangle.java

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Square.java

public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Circle.java

public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

Schritt 3

Erstellen Sie eine Factory, um basierend auf den angegebenen Informationen ein Objekt der konkreten Klasse zu generieren.

ShapeFactory.java

public class ShapeFactory {
	
   //use getShape method to get object of type shape 
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }		
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}

Schritt 4

Verwenden Sie die Factory, um ein Objekt der konkreten Klasse abzurufen, indem Sie Informationen wie den Typ übergeben.

FactoryPatternDemo.java

public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //get an object of Circle and call its draw method.
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //call draw method of Circle
      shape1.draw();

      //get an object of Rectangle and call its draw method.
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //call draw method of Rectangle
      shape2.draw();

      //get an object of Square and call its draw method.
      Shape shape3 = shapeFactory.getShape("SQUARE");

      //call draw method of square
      shape3.draw();
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

Abstrakte Fabrikmuster arbeiten um eine Superfabrik herum, die andere Fabriken schafft. Diese Fabrik wird auch als Fabrik der Fabriken bezeichnet. Diese Art von Entwurfsmuster fällt unter das Erstellungsmuster, da dieses Muster eine der besten Möglichkeiten zum Erstellen eines Objekts bietet.

Im Abstract Factory-Muster ist eine Schnittstelle dafür verantwortlich, eine Factory verwandter Objekte zu erstellen, ohne deren Klassen explizit anzugeben. Jede generierte Factory kann die Objekte gemäß dem Factory-Muster angeben.

Implementierung

Wir werden eine Shape-Schnittstelle erstellen und eine konkrete Klasse implementieren. Als nächsten Schritt erstellen wir eine abstrakte Factory-Klasse AbstractFactory. Es ist die Factory-Klasse ShapeFactory definiert, die AbstractFactory erweitert. Eine Factory Creator / Generator-Klasse FactoryProducer wird erstellt.

AbstractFactoryPatternDemo, unsere Demo-Klasse, verwendet FactoryProducer, um ein AbstractFactory-Objekt abzurufen. Es werden Informationen (CIRCLE / RECTANGLE / SQUARE for Shape) an AbstractFactory übergeben, um den benötigten Objekttyp zu erhalten.

Schritt 1

Erstellen Sie eine Schnittstelle für Formen.

Shape.java

public interface Shape {
   void draw();
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

RoundedRectangle.java

public class RoundedRectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside RoundedRectangle::draw() method.");
   }
}

RoundedSquare.java

public class RoundedSquare implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside RoundedSquare::draw() method.");
   }
}

Rectangle.java

public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Schritt 3

Erstellen Sie eine abstrakte Klasse, um Fabriken für Objekte mit normaler und abgerundeter Form abzurufen.

AbstractFactory.java

public abstract class AbstractFactory {
   abstract Shape getShape(String shapeType) ;
}

Schritt 4

Erstellen Sie Factory-Klassen, die AbstractFactory erweitern, um basierend auf den angegebenen Informationen ein Objekt einer konkreten Klasse zu generieren.

ShapeFactory.java

public class ShapeFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){    
      if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();         
      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }	 
      return null;
   }
}

RoundedShapeFactory.java

public class RoundedShapeFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){    
      if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new RoundedRectangle();         
      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new RoundedSquare();
      }	 
      return null;
   }
}

Schritt 5

Erstellen Sie eine Factory-Generator- / Produzentenklasse, um Fabriken zu erhalten, indem Sie Informationen wie Shape übergeben

FactoryProducer.java

public class FactoryProducer {
   public static AbstractFactory getFactory(boolean rounded){   
      if(rounded){
         return new RoundedShapeFactory();         
      }else{
         return new ShapeFactory();
      }
   }
}

Schritt 6

Verwenden Sie den FactoryProducer, um AbstractFactory abzurufen und Fabriken konkreter Klassen durch Übergabe von Informationen wie type abzurufen.

AbstractFactoryPatternDemo.java

public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
      //get shape factory
      AbstractFactory shapeFactory = FactoryProducer.getFactory(false);
      //get an object of Shape Rectangle
      Shape shape1 = shapeFactory.getShape("RECTANGLE");
      //call draw method of Shape Rectangle
      shape1.draw();
      //get an object of Shape Square 
      Shape shape2 = shapeFactory.getShape("SQUARE");
      //call draw method of Shape Square
      shape2.draw();
      //get shape factory
      AbstractFactory shapeFactory1 = FactoryProducer.getFactory(true);
      //get an object of Shape Rectangle
      Shape shape3 = shapeFactory1.getShape("RECTANGLE");
      //call draw method of Shape Rectangle
      shape3.draw();
      //get an object of Shape Square 
      Shape shape4 = shapeFactory1.getShape("SQUARE");
      //call draw method of Shape Square
      shape4.draw();
      
   }
}

Schritt 7

Überprüfen Sie die Ausgabe.

Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside RoundedRectangle::draw() method.
Inside RoundedSquare::draw() method.

Das Singleton-Muster ist eines der einfachsten Entwurfsmuster in Java. Diese Art von Entwurfsmuster fällt unter das Erstellungsmuster, da dieses Muster eine der besten Möglichkeiten zum Erstellen eines Objekts darstellt.

Bei diesem Muster handelt es sich um eine einzelne Klasse, die für die Erstellung eines eigenen Objekts verantwortlich ist und gleichzeitig sicherstellt, dass nur ein einzelnes Objekt erstellt wird. Diese Klasse bietet eine Möglichkeit, auf ihr einziges Objekt zuzugreifen, auf das direkt zugegriffen werden kann, ohne dass das Objekt der Klasse instanziiert werden muss.

Implementierung

Wir werden eine SingleObject- Klasse erstellen . Die SingleObject- Klasse hat ihren Konstruktor als privat und eine statische Instanz von sich.

Die SingleObject- Klasse bietet eine statische Methode, um ihre statische Instanz an die Außenwelt zu übertragen. SingletonPatternDemo , unsere Demo-Klasse verwendet die SingleObject- Klasse, um ein SingleObject- Objekt abzurufen .

Schritt 1

Erstellen Sie eine Singleton-Klasse.

SingleObject.java

public class SingleObject {

   //create an object of SingleObject
   private static SingleObject instance = new SingleObject();

   //make the constructor private so that this class cannot be
   //instantiated
   private SingleObject(){}

   //Get the only object available
   public static SingleObject getInstance(){
      return instance;
   }

   public void showMessage(){
      System.out.println("Hello World!");
   }
}

Schritt 2

Holen Sie sich das einzige Objekt aus der Singleton-Klasse.

SingletonPatternDemo.java

public class SingletonPatternDemo {
   public static void main(String[] args) {

      //illegal construct
      //Compile Time Error: The constructor SingleObject() is not visible
      //SingleObject object = new SingleObject();

      //Get the only object available
      SingleObject object = SingleObject.getInstance();

      //show the message
      object.showMessage();
   }
}

Schritt 3

Überprüfen Sie die Ausgabe.

Hello World!

Das Builder-Muster erstellt ein komplexes Objekt mit einfachen Objekten und einem schrittweisen Ansatz. Diese Art von Entwurfsmuster fällt unter das Erstellungsmuster, da dieses Muster eine der besten Möglichkeiten zum Erstellen eines Objekts bietet.

Eine Builder-Klasse erstellt das endgültige Objekt Schritt für Schritt. Dieser Builder ist unabhängig von anderen Objekten.

Implementierung

Wir haben einen Business Case für ein Fast-Food-Restaurant in Betracht gezogen, in dem eine typische Mahlzeit ein Burger und ein kaltes Getränk sein kann. Burger kann entweder ein Veg Burger oder ein Chicken Burger sein und wird von einer Verpackung verpackt. Kaltes Getränk kann entweder Cola oder Pepsi sein und wird in einer Flasche verpackt.

Wir werden eine Artikelschnittstelle erstellen, die Lebensmittel wie Burger und kalte Getränke sowie Betonklassen darstellt, die die Artikelschnittstelle implementieren, und eine Verpackungsschnittstelle , die die Verpackung von Lebensmitteln und Betonklassen darstellt, die die Verpackungsschnittstelle implementieren, da Burger in Verpackung und Kälte verpackt werden Getränk würde als Flasche verpackt werden.

Anschließend erstellen wir eine Meal- Klasse mit ArrayList of Item und einem MealBuilder , um verschiedene Arten von Meal- Objekten durch Kombinieren von Item zu erstellen . BuilderPatternDemo , unsere Demo-Klasse, verwendet MealBuilder , um eine Mahlzeit zu erstellen .

Schritt 1

Erstellen Sie eine Schnittstelle Artikel, der Lebensmittel und Verpackung darstellt.

Item.java

public interface Item {
   public String name();
   public Packing packing();
   public float price();	
}

Packing.java

public interface Packing {
   public String pack();
}

Schritt 2

Erstellen Sie Concreate-Klassen, die die Packing-Schnittstelle implementieren.

Wrapper.java

public class Wrapper implements Packing {

   @Override
   public String pack() {
      return "Wrapper";
   }
}

Bottle.java

public class Bottle implements Packing {

   @Override
   public String pack() {
      return "Bottle";
   }
}

Schritt 3

Erstellen Sie abstrakte Klassen, die die Elementschnittstelle implementieren und Standardfunktionen bereitstellen.

Burger.java

public abstract class Burger implements Item {

   @Override
   public Packing packing() {
      return new Wrapper();
   }

   @Override
   public abstract float price();
}

ColdDrink.java

public abstract class ColdDrink implements Item {

	@Override
	public Packing packing() {
       return new Bottle();
	}

	@Override
	public abstract float price();
}

Schritt 4

Erstellen Sie konkrete Klassen, die die Burger- und ColdDrink-Klassen erweitern

VegBurger.java

public class VegBurger extends Burger {

   @Override
   public float price() {
      return 25.0f;
   }

   @Override
   public String name() {
      return "Veg Burger";
   }
}

ChickenBurger.java

public class ChickenBurger extends Burger {

   @Override
   public float price() {
      return 50.5f;
   }

   @Override
   public String name() {
      return "Chicken Burger";
   }
}

Coke.java

public class Coke extends ColdDrink {

   @Override
   public float price() {
      return 30.0f;
   }

   @Override
   public String name() {
      return "Coke";
   }
}

Pepsi.java

public class Pepsi extends ColdDrink {

   @Override
   public float price() {
      return 35.0f;
   }

   @Override
   public String name() {
      return "Pepsi";
   }
}

Schritt 5

Erstellen Sie eine Mahlzeitklasse mit den oben definierten Objektobjekten.

Meal.java

import java.util.ArrayList;
import java.util.List;

public class Meal {
   private List<Item> items = new ArrayList<Item>();	

   public void addItem(Item item){
      items.add(item);
   }

   public float getCost(){
      float cost = 0.0f;
      for (Item item : items) {
         cost += item.price();
      }		
      return cost;
   }

   public void showItems(){
      for (Item item : items) {
         System.out.print("Item : "+item.name());
         System.out.print(", Packing : "+item.packing().pack());
         System.out.println(", Price : "+item.price());
      }		
   }	
}

Schritt 6

Erstellen Sie eine MealBuilder-Klasse, die eigentliche Builder-Klasse, die für die Erstellung von Meal-Objekten verantwortlich ist.

MealBuilder.java

public class MealBuilder {

   public Meal prepareVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new VegBurger());
      meal.addItem(new Coke());
      return meal;
   }   

   public Meal prepareNonVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new ChickenBurger());
      meal.addItem(new Pepsi());
      return meal;
   }
}

Schritt 7

BuiderPatternDemo verwendet MealBuider, um das Builder-Muster zu demonstrieren.

BuilderPatternDemo.java

public class BuilderPatternDemo {
   public static void main(String[] args) {
      MealBuilder mealBuilder = new MealBuilder();

      Meal vegMeal = mealBuilder.prepareVegMeal();
      System.out.println("Veg Meal");
      vegMeal.showItems();
      System.out.println("Total Cost: " +vegMeal.getCost());

      Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
      System.out.println("\n\nNon-Veg Meal");
      nonVegMeal.showItems();
      System.out.println("Total Cost: " +nonVegMeal.getCost());
   }
}

Schritt 8

Überprüfen Sie die Ausgabe.

Veg Meal
Item : Veg Burger, Packing : Wrapper, Price : 25.0
Item : Coke, Packing : Bottle, Price : 30.0
Total Cost: 55.0

Non-Veg Meal
Item : Chicken Burger, Packing : Wrapper, Price : 50.5
Item : Pepsi, Packing : Bottle, Price : 35.0
Total Cost: 85.5

Das Prototypmuster bezieht sich auf das Erstellen eines doppelten Objekts unter Berücksichtigung der Leistung. Diese Art von Entwurfsmuster fällt unter das Erstellungsmuster, da dieses Muster eine der besten Möglichkeiten zum Erstellen eines Objekts darstellt.

Dieses Muster beinhaltet die Implementierung einer Prototypschnittstelle, die anweist, einen Klon des aktuellen Objekts zu erstellen. Dieses Muster wird verwendet, wenn die direkte Erstellung eines Objekts kostspielig ist. Beispielsweise soll ein Objekt nach einer kostspieligen Datenbankoperation erstellt werden. Wir können das Objekt zwischenspeichern, seinen Klon bei der nächsten Anforderung zurückgeben und die Datenbank nach Bedarf aktualisieren, wodurch Datenbankaufrufe reduziert werden.

Implementierung

Wir werden eine abstrakte Klasse Shape und konkrete Klassen erstellen , die die Shape- Klasse erweitern. Eine Klasse ShapeCache wird als nächster Schritt definiert die Form speichert in einem Objekt Hashtable und gibt sie Klon , wenn angefordert.

PrototypPatternDemo , unsere Demo-Klasse, verwendet die ShapeCache- Klasse, um ein Shape- Objekt abzurufen .

Schritt 1

Erstellen Sie eine abstrakte Klasse, die die klonbare Schnittstelle implementiert .

Shape.java

public 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;
   }
}

Schritt 2

Erstellen Sie konkrete Klassen, die die obige Klasse erweitern.

Rectangle.java

public class Rectangle extends Shape {

   public Rectangle(){
     type = "Rectangle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Square.java

public class Square extends Shape {

   public Square(){
     type = "Square";
   }

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Circle.java

public class Circle extends Shape {

   public Circle(){
     type = "Circle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

Schritt 3

Erstellen Sie eine Klasse concreate Klassen aus der Datenbank und speichert sie in einem bekommen Hashtable .

ShapeCache.java

import java.util.Hashtable;

public class ShapeCache {
	
   private static Hashtable<String, Shape> shapeMap 
      = new Hashtable<String, Shape>();

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

   // for each shape run database query and create shape
   // shapeMap.put(shapeKey, shape);
   // for example, we are adding three shapes
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);

      Square square = new Square();
      square.setId("2");
      shapeMap.put(square.getId(),square);

      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(),rectangle);
   }
}

Schritt 4

PrototypePatternDemo verwendet die ShapeCache- Klasse, um Klone von Formen abzurufen , die in einer Hashtable gespeichert sind .

PrototypePatternDemo.java

public class PrototypePatternDemo {
   public static void main(String[] args) {
      ShapeCache.loadCache();

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

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

      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
      System.out.println("Shape : " + clonedShape3.getType());		
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Shape : Circle
Shape : Square
Shape : Rectangle

Das Adaptermuster fungiert als Brücke zwischen zwei inkompatiblen Schnittstellen. Diese Art von Entwurfsmuster fällt unter ein Strukturmuster, da dieses Muster die Fähigkeit zweier unabhängiger Schnittstellen kombiniert.

Dieses Muster umfasst eine einzelne Klasse, die für die Verknüpfung von Funktionen unabhängiger oder inkompatibler Schnittstellen verantwortlich ist. Ein Beispiel aus dem wirklichen Leben könnte ein Kartenleser sein, der als Adapter zwischen Speicherkarte und Laptop fungiert. Sie stecken die Speicherkarte in den Kartenleser und den Kartenleser in den Laptop, damit die Speicherkarte über den Laptop gelesen werden kann.

Wir demonstrieren die Verwendung des Adaptermusters anhand des folgenden Beispiels, in dem ein Audio-Player-Gerät nur MP3-Dateien abspielen kann und einen erweiterten Audio-Player verwenden möchte, der VLC- und MP4-Dateien abspielen kann.

Implementierung

Wir haben eine Schnittstelle MediaPlayer- Schnittstelle und eine konkrete Klasse AudioPlayer, die die MediaPlayer- Schnittstelle implementiert . AudioPlayer kann standardmäßig Audiodateien im MP3-Format abspielen.

Wir haben eine weitere Schnittstelle AdvancedMediaPlayer und konkrete Klassen, die die AdvancedMediaPlayer- Schnittstelle implementieren. Diese Klassen können Dateien im VLC- und MP4-Format abspielen.

Wir möchten, dass AudioPlayer auch andere Formate wiedergibt . Um dies zu erreichen, haben wir eine Adapterklasse MediaAdapter erstellt, die die MediaPlayer- Schnittstelle implementiert und AdvancedMediaPlayer- Objekte verwendet, um das erforderliche Format abzuspielen.

AudioPlayer verwendet die Adapterklasse MediaAdapter, die den gewünschten Audiotyp übergibt, ohne die tatsächliche Klasse zu kennen, die das gewünschte Format wiedergeben kann. AdapterPatternDemo , unsere Demo-Klasse, verwendet die AudioPlayer- Klasse, um verschiedene Formate abzuspielen.

Schritt 1

Erstellen Sie Schnittstellen für Media Player und Advanced Media Player.

MediaPlayer.java

public interface MediaPlayer {
   public void play(String audioType, String fileName);
}

AdvancedMediaPlayer.java

public interface AdvancedMediaPlayer {	
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

Schritt 2

Erstellen Sie konkrete Klassen, die die AdvancedMediaPlayer- Schnittstelle implementieren .

VlcPlayer.java

public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);		
   }

   @Override
   public void playMp4(String fileName) {
      //do nothing
   }
}

Mp4Player.java

public class Mp4Player implements AdvancedMediaPlayer{

   @Override
   public void playVlc(String fileName) {
      //do nothing
   }

   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);		
   }
}

Schritt 3

Erstellen Sie eine Adapterklasse, die die MediaPlayer- Schnittstelle implementiert .

MediaAdapter.java

public class MediaAdapter implements MediaPlayer {

   AdvancedMediaPlayer advancedMusicPlayer;

   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();			
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }	
   }

   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

Schritt 4

Erstellen Sie eine konkrete Klasse, die die MediaPlayer- Schnittstelle implementiert .

AudioPlayer.java

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 

   @Override
   public void play(String audioType, String fileName) {		

      //inbuilt support to play mp3 music files
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);			
      } 
      //mediaAdapter is providing support to play other file formats
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

Schritt 5

Verwenden Sie den AudioPlayer, um verschiedene Arten von Audioformaten abzuspielen.

AdapterPatternDemo.java

public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();

      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported

Bridge wird verwendet, wenn eine Abstraktion von ihrer Implementierung entkoppelt werden muss, damit die beiden unabhängig voneinander variieren können. Diese Art von Entwurfsmuster fällt unter ein Strukturmuster, da dieses Muster die Implementierungsklasse und die abstrakte Klasse entkoppelt, indem eine Brückenstruktur zwischen ihnen bereitgestellt wird.

Bei diesem Muster handelt es sich um eine Schnittstelle, die als Brücke fungiert und die Funktionalität konkreter Klassen von Klassen für Schnittstellenimplementierer unabhängig macht. Beide Arten von Klassen können strukturell geändert werden, ohne sich gegenseitig zu beeinflussen.

Wir demonstrieren die Verwendung des Brückenmusters anhand des folgenden Beispiels, in dem ein Kreis mit derselben abstrakten Klassenmethode, aber verschiedenen Brückenimplementierungsklassen in verschiedenen Farben gezeichnet werden kann.

Implementierung

Wir haben eine DrawAPI- Schnittstelle, die als Bridge-Implementierer fungiert, und konkrete Klassen RedCircle , GreenCircle, die die DrawAPI- Schnittstelle implementieren . Shape ist eine abstrakte Klasse und verwendet das Objekt von DrawAPI . BridgePatternDemo , unsere Demo-Klasse, verwendet die Shape- Klasse, um verschiedenfarbige Kreise zu zeichnen.

Schritt 1

Erstellen Sie eine Bridge-Implementierungsschnittstelle.

DrawAPI.java

public interface DrawAPI {
   public void drawCircle(int radius, int x, int y);
}

Schritt 2

Erstellen Sie konkrete Bridge-Implementierungsklassen, die die DrawAPI- Schnittstelle implementieren .

RedCircle.java

public class RedCircle implements DrawAPI {
   @Override
   public void drawCircle(int radius, int x, int y) {
      System.out.println("Drawing Circle[ color: red, radius: "
         + radius +", x: " +x+", "+ y +"]");
   }
}

GreenCircle.java

public class GreenCircle implements DrawAPI {
   @Override
   public void drawCircle(int radius, int x, int y) {
      System.out.println("Drawing Circle[ color: green, radius: "
         + radius +", x: " +x+", "+ y +"]");
   }
}

Schritt 3

Erstellen Sie eine abstrakte Klasse - Form , die mit DrawAPI Schnittstelle.

Shape.java

public abstract class Shape {
   protected DrawAPI drawAPI;
   protected Shape(DrawAPI drawAPI){
      this.drawAPI = drawAPI;
   }
   public abstract void draw();	
}

Schritt 4

Erstellen Sie eine konkrete Klasse, die die Formschnittstelle implementiert.

Circle.java

public class Circle extends Shape {
   private int x, y, radius;

   public Circle(int x, int y, int radius, DrawAPI drawAPI) {
      super(drawAPI);
      this.x = x;  
      this.y = y;  
      this.radius = radius;
   }

   public void draw() {
      drawAPI.drawCircle(radius,x,y);
   }
}

Schritt 5

Verwenden Sie die Klassen Shape und DrawAPI , um verschiedenfarbige Kreise zu zeichnen.

BridgePatternDemo.java

public class BridgePatternDemo {
   public static void main(String[] args) {
      Shape redCircle = new Circle(100,100, 10, new RedCircle());
      Shape greenCircle = new Circle(100,100, 10, new GreenCircle());

      redCircle.draw();
      greenCircle.draw();
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Drawing Circle[ color: red, radius: 10, x: 100, 100]
Drawing Circle[  color: green, radius: 10, x: 100, 100]

Filtermuster oder Kriterienmuster ist ein Entwurfsmuster, mit dem Entwickler eine Reihe von Objekten nach verschiedenen Kriterien filtern und sie durch logische Operationen entkoppelt verketten können. Diese Art von Entwurfsmuster fällt unter ein Strukturmuster, da dieses Muster mehrere Kriterien kombiniert, um einzelne Kriterien zu erhalten.

Implementierung

Wir werden ein Personenobjekt , eine Kriterienschnittstelle und konkrete Klassen erstellen, die diese Schnittstelle implementieren, um die Liste der Personenobjekte zu filtern . CriteriaPatternDemo , unsere Demo-Klasse, verwendet Kriterienobjekte , um die Liste der Personenobjekte anhand verschiedener Kriterien und ihrer Kombinationen zu filtern .

Schritt 1

Erstellen Sie eine Klasse, auf die Kriterien angewendet werden sollen.

Person.java

public class Person {
	
   private String name;
   private String gender;
   private String maritalStatus;

   public Person(String name,String gender,String maritalStatus){
      this.name = name;
      this.gender = gender;
      this.maritalStatus = maritalStatus;		
   }

   public String getName() {
      return name;
   }
   public String getGender() {
      return gender;
   }
   public String getMaritalStatus() {
      return maritalStatus;
   }	
}

Schritt 2

Erstellen Sie eine Schnittstelle für Kriterien.

Criteria.java

import java.util.List;

public interface Criteria {
   public List<Person> meetCriteria(List<Person> persons);
}

Schritt 3

Erstellen Sie konkrete Klassen, die die Kriterienschnittstelle implementieren.

CriteriaMale.java

import java.util.ArrayList;
import java.util.List;

public class CriteriaMale implements Criteria {

   @Override
   public List<Person> meetCriteria(List<Person> persons) {
      List<Person> malePersons = new ArrayList<Person>(); 
      for (Person person : persons) {
         if(person.getGender().equalsIgnoreCase("MALE")){
            malePersons.add(person);
         }
      }
      return malePersons;
   }
}

CriteriaFemale.java

import java.util.ArrayList;
import java.util.List;

public class CriteriaFemale implements Criteria {

   @Override
   public List<Person> meetCriteria(List<Person> persons) {
      List<Person> femalePersons = new ArrayList<Person>(); 
      for (Person person : persons) {
         if(person.getGender().equalsIgnoreCase("FEMALE")){
            femalePersons.add(person);
         }
      }
      return femalePersons;
   }
}

CriteriaSingle.java

import java.util.ArrayList;
import java.util.List;

public class CriteriaSingle implements Criteria {

   @Override
   public List<Person> meetCriteria(List<Person> persons) {
      List<Person> singlePersons = new ArrayList<Person>(); 
      for (Person person : persons) {
         if(person.getMaritalStatus().equalsIgnoreCase("SINGLE")){
            singlePersons.add(person);
         }
      }
      return singlePersons;
   }
}

AndCriteria.java

import java.util.List;

public class AndCriteria implements Criteria {

   private Criteria criteria;
   private Criteria otherCriteria;

   public AndCriteria(Criteria criteria, Criteria otherCriteria) {
      this.criteria = criteria;
      this.otherCriteria = otherCriteria; 
   }

   @Override
   public List<Person> meetCriteria(List<Person> persons) {
      List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);		
      return otherCriteria.meetCriteria(firstCriteriaPersons);
   }
}

OrCriteria.java

import java.util.List;

public class AndCriteria implements Criteria {

   private Criteria criteria;
   private Criteria otherCriteria;

   public AndCriteria(Criteria criteria, Criteria otherCriteria) {
      this.criteria = criteria;
      this.otherCriteria = otherCriteria; 
   }

   @Override
   public List<Person> meetCriteria(List<Person> persons) {
      List<Person> firstCriteriaItems = criteria.meetCriteria(persons);
      List<Person> otherCriteriaItems = otherCriteria.meetCriteria(persons);

      for (Person person : otherCriteriaItems) {
         if(!firstCriteriaItems.contains(person)){
	        firstCriteriaItems.add(person);
         }
      }	
      return firstCriteriaItems;
   }
}

Schritt 4

Verwenden Sie verschiedene Kriterien und deren Kombination, um Personen herauszufiltern.

CriteriaPatternDemo.java

import java.util.ArrayList;
import java.util.List;

public class CriteriaPatternDemo {
   public static void main(String[] args) {
      List<Person> persons = new ArrayList<Person>();

      persons.add(new Person("Robert","Male", "Single"));
      persons.add(new Person("John","Male", "Married"));
      persons.add(new Person("Laura","Female", "Married"));
      persons.add(new Person("Diana","Female", "Single"));
      persons.add(new Person("Mike","Male", "Single"));
      persons.add(new Person("Bobby","Male", "Single"));

      Criteria male = new CriteriaMale();
      Criteria female = new CriteriaFemale();
      Criteria single = new CriteriaSingle();
      Criteria singleMale = new AndCriteria(single, male);
      Criteria singleOrFemale = new OrCriteria(single, female);

      System.out.println("Males: ");
      printPersons(male.meetCriteria(persons));

      System.out.println("\nFemales: ");
      printPersons(female.meetCriteria(persons));

      System.out.println("\nSingle Males: ");
      printPersons(singleMale.meetCriteria(persons));

      System.out.println("\nSingle Or Females: ");
      printPersons(singleOrFemale.meetCriteria(persons));
   }

   public static void printPersons(List<Person> persons){
      for (Person person : persons) {
         System.out.println("Person : [ Name : " + person.getName() 
            +", Gender : " + person.getGender() 
            +", Marital Status : " + person.getMaritalStatus()
            +" ]");
      }
   }      
}

Schritt 5

Überprüfen Sie die Ausgabe.

Males: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : John, Gender : Male, Marital Status : Married ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]

Females: 
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]
Person : [ Name : Diana, Gender : Female, Marital Status : Single ]

Single Males: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]

Single Or Females: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : Diana, Gender : Female, Marital Status : Single ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]

Ein zusammengesetztes Muster wird verwendet, wenn eine Gruppe von Objekten auf ähnliche Weise wie ein einzelnes Objekt behandelt werden muss. Das zusammengesetzte Muster setzt Objekte in Form einer Baumstruktur zusammen, um sowohl eine Teil- als auch eine ganze Hierarchie darzustellen. Diese Art von Entwurfsmuster fällt unter ein Strukturmuster, da dieses Muster eine Baumstruktur einer Gruppe von Objekten erstellt.

Dieses Muster erstellt eine Klasse, die eine Gruppe eigener Objekte enthält. Diese Klasse bietet Möglichkeiten zum Ändern der Gruppe derselben Objekte.

Wir demonstrieren die Verwendung des zusammengesetzten Musters anhand des folgenden Beispiels, in dem die Mitarbeiterhierarchie einer Organisation dargestellt wird.

Implementierung

Wir haben eine Klasse Employee, die als Composite Pattern Actor Class fungiert. CompositePatternDemo , unsere Demo-Klasse, verwendet die Employee- Klasse, um Hierarchien auf Abteilungsebene hinzuzufügen und alle Mitarbeiter zu drucken.

Schritt 1

Erstellen Sie eine Mitarbeiterklasse mit einer Liste von Mitarbeiterobjekten .

Employee.java

import java.util.ArrayList;
import java.util.List;

public class Employee {
   private String name;
   private String dept;
   private int salary;
   private List<Employee> subordinates;

   // constructor
   public Employee(String name,String dept, int sal) {
      this.name = name;
      this.dept = dept;
      this.salary = sal;
      subordinates = new ArrayList<Employee>();
   }

   public void add(Employee e) {
      subordinates.add(e);
   }

   public void remove(Employee e) {
      subordinates.remove(e);
   }

   public List<Employee> getSubordinates(){
     return subordinates;
   }

   public String toString(){
      return ("Employee :[ Name : "+ name 
      +", dept : "+ dept + ", salary :"
      + salary+" ]");
   }   
}

Schritt 2

Verwenden Sie die Employee- Klasse, um eine Mitarbeiterhierarchie zu erstellen und zu drucken.

CompositePatternDemo.java

public class CompositePatternDemo {
   public static void main(String[] args) {
      Employee CEO = new Employee("John","CEO", 30000);

      Employee headSales = new Employee("Robert","Head Sales", 20000);

      Employee headMarketing = new Employee("Michel","Head Marketing", 20000);

      Employee clerk1 = new Employee("Laura","Marketing", 10000);
      Employee clerk2 = new Employee("Bob","Marketing", 10000);

      Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
      Employee salesExecutive2 = new Employee("Rob","Sales", 10000);

      CEO.add(headSales);
      CEO.add(headMarketing);

      headSales.add(salesExecutive1);
      headSales.add(salesExecutive2);

      headMarketing.add(clerk1);
      headMarketing.add(clerk2);

      //print all employees of the organization
      System.out.println(CEO); 
      for (Employee headEmployee : CEO.getSubordinates()) {
         System.out.println(headEmployee);
         for (Employee employee : headEmployee.getSubordinates()) {
            System.out.println(employee);
         }
      }		
   }
}

Schritt 3

Überprüfen Sie die Ausgabe.

Employee :[ Name : John, dept : CEO, salary :30000 ]
Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
Employee :[ Name : Richard, dept : Sales, salary :10000 ]
Employee :[ Name : Rob, dept : Sales, salary :10000 ]
Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
Employee :[ Name : Bob, dept : Marketing, salary :10000 ]

Mit dem Dekorationsmuster können Sie einem vorhandenen Objekt neue Funktionen hinzufügen, ohne dessen Struktur zu ändern. Diese Art von Entwurfsmuster fällt unter das Strukturmuster, da dieses Muster als Wrapper für vorhandene Klassen fungiert.

Dieses Muster erstellt eine Dekorationsklasse, die die ursprüngliche Klasse umschließt und zusätzliche Funktionen bietet, wobei die Signatur der Klassenmethoden intakt bleibt.

Wir demonstrieren die Verwendung des Dekorationsmusters anhand des folgenden Beispiels, in dem wir eine Form mit etwas Farbe dekorieren, ohne die Formklasse zu ändern.

Implementierung

Wir werden eine Shape- Schnittstelle und konkrete Klassen erstellen, die die Shape- Schnittstelle implementieren . Anschließend erstellen wir eine abstrakte Dekorationsklasse ShapeDecorator, die die Shape- Schnittstelle implementiert und das Shape- Objekt als Instanzvariable verwendet.

RedShapeDecorator ist eine konkrete Klasse, die ShapeDecorator implementiert .

DecoratorPatternDemo , unsere Demo-Klasse, verwendet RedShapeDecorator , um Shape- Objekte zu dekorieren .

Schritt 1

Erstellen Sie eine Schnittstelle.

Shape.java

public interface Shape {
   void draw();
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

Rectangle.java

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}

Circle.java

public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Shape: Circle");
   }
}

Schritt 3

Erstellen Sie eine abstrakte Dekorationsklasse, die die Formschnittstelle implementiert.

ShapeDecorator.java

public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }

   public void draw(){
      decoratedShape.draw();
   }	
}

Schritt 4

Erstellen Sie eine konkrete Dekorationsklasse, die die ShapeDecorator- Klasse erweitert.

RedShapeDecorator.java

public class RedShapeDecorator extends ShapeDecorator {

   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);		
   }

   @Override
   public void draw() {
      decoratedShape.draw();	       
      setRedBorder(decoratedShape);
   }

   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

Schritt 5

Verwenden Sie den RedShapeDecorator , um Shape- Objekte zu dekorieren .

DecoratorPatternDemo.java

public class DecoratorPatternDemo {
   public static void main(String[] args) {

      Shape circle = new Circle();

      Shape redCircle = new RedShapeDecorator(new Circle());

      Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();

      System.out.println("\nCircle of red border");
      redCircle.draw();

      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Circle with normal border
Shape: Circle

Circle of red border
Shape: Circle
Border Color: Red

Rectangle of red border
Shape: Rectangle
Border Color: Red

Das Fassadenmuster verbirgt die Komplexität des Systems und bietet eine Schnittstelle zum Client, über die der Client auf das System zugreifen kann. Diese Art von Entwurfsmuster fällt unter ein Strukturmuster, da dieses Muster eine Schnittstelle zum verlassenen System hinzufügt, um dessen Komplexität zu verbergen.

Dieses Muster umfasst eine einzelne Klasse, die vereinfachte Methoden bereitstellt, die vom Client benötigt werden, und Aufrufe an vorhandene Systemklassenmethoden delegiert.

Implementierung

Wir werden eine Shape- Schnittstelle und konkrete Klassen erstellen, die die Shape- Schnittstelle implementieren . Als nächsten Schritt wird eine Fassadenklasse ShapeMaker definiert.

Die ShapeMaker- Klasse verwendet die konkreten Klassen, um Benutzeraufrufe an diese Klassen zu delegieren. FacadePatternDemo , unsere Demo-Klasse, verwendet die ShapeMaker- Klasse, um die Ergebnisse anzuzeigen .

Schritt 1

Erstellen Sie eine Schnittstelle.

Shape.java

public interface Shape {
   void draw();
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

Rectangle.java

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Rectangle::draw()");
   }
}

Square.java

public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}

Circle.java

public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Circle::draw()");
   }
}

Schritt 3

Erstellen Sie eine Fassadenklasse.

ShapeMaker.java

public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
   private Shape square;

   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }

   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}

Schritt 4

Verwenden Sie die Fassade, um verschiedene Arten von Formen zu zeichnen.

FacadePatternDemo.java

public class FacadePatternDemo {
   public static void main(String[] args) {
      ShapeMaker shapeMaker = new ShapeMaker();

      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();
      shapeMaker.drawSquare();		
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Circle::draw()
Rectangle::draw()
Square::draw()

Das Fliegengewichtsmuster wird hauptsächlich verwendet, um die Anzahl der erstellten Objekte zu verringern, den Speicherbedarf zu verringern und die Leistung zu steigern. Diese Art von Entwurfsmuster fällt unter das Strukturmuster, da dieses Muster Möglichkeiten zum Verringern der Objektanzahl bietet, wodurch die für die Anwendung erforderliche Objektstruktur verbessert wird.

Flyweight-Muster versuchen, bereits vorhandene Objekte ähnlicher Art durch Speichern wiederzuverwenden, und erstellen ein neues Objekt, wenn kein passendes Objekt gefunden wird. Wir werden dieses Muster demonstrieren, indem wir 20 Kreise an verschiedenen Orten zeichnen, aber wir werden nur 5 Objekte erstellen. Es sind nur 5 Farben verfügbar, sodass die Farbeigenschaft verwendet wird, um bereits vorhandene Kreisobjekte zu überprüfen .

Implementierung

Wir werden eine schaffen Form Schnittstelle und konkrete Klasse Kreis der Umsetzung der Form - Schnittstelle. Als nächster Schritt wird eine Factory-Klasse ShapeFactory definiert.

ShapeFactory hat eine HashMap of Circle mit dem Schlüssel als Farbe des Circle- Objekts. Immer wenn eine Anforderung zum Erstellen eines Kreises mit einer bestimmten Farbe für ShapeFactory eingeht . ShapeFactory überprüft das Kreisobjekt in seiner HashMap . Wenn ein Objekt von Circle gefunden wird, wird dieses Objekt zurückgegeben. Andernfalls wird ein neues Objekt erstellt, in der Hashmap für die zukünftige Verwendung gespeichert und an den Client zurückgegeben.

FlyWeightPatternDemo , unsere Demo-Klasse, verwendet ShapeFactory , um ein Shape- Objekt abzurufen . Es werden Informationen ( rot / grün / blau / schwarz / weiß ) an ShapeFactory übergeben , um den Kreis der gewünschten Farbe zu erhalten, den es benötigt.

Schritt 1

Erstellen Sie eine Schnittstelle.

Shape.java

public interface Shape {
   void draw();
}

Schritt 2

Erstellen Sie eine konkrete Klasse, die dieselbe Schnittstelle implementiert.

Circle.java

public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;

   public Circle(String color){
      this.color = color;		
   }

   public void setX(int x) {
      this.x = x;
   }

   public void setY(int y) {
      this.y = y;
   }

   public void setRadius(int radius) {
      this.radius = radius;
   }

   @Override
   public void draw() {
      System.out.println("Circle: Draw() [Color : " + color 
         +", x : " + x +", y :" + y +", radius :" + radius);
   }
}

Schritt 3

Erstellen Sie eine Factory, um basierend auf den angegebenen Informationen ein Objekt der konkreten Klasse zu generieren.

ShapeFactory.java

import java.util.HashMap;

public class ShapeFactory {

   // Uncomment the compiler directive line and
   // javac *.java will compile properly.
   // @SuppressWarnings("unchecked")
   private static final HashMap circleMap = new HashMap();

   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}

Schritt 4

Verwenden Sie die Factory, um ein Objekt der konkreten Klasse zu erhalten, indem Sie Informationen wie Farbe übergeben.

FlyweightPatternDemo.java

public class FlyweightPatternDemo {
   private static final String colors[] = 
      { "Red", "Green", "Blue", "White", "Black" };
   public static void main(String[] args) {

      for(int i=0; i < 20; ++i) {
         Circle circle = 
            (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }
   private static String getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   private static int getRandomX() {
      return (int)(Math.random()*100 );
   }
   private static int getRandomY() {
      return (int)(Math.random()*100);
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Creating circle of color : Black
Circle: Draw() [Color : Black, x : 36, y :71, radius :100
Creating circle of color : Green
Circle: Draw() [Color : Green, x : 27, y :27, radius :100
Creating circle of color : White
Circle: Draw() [Color : White, x : 64, y :10, radius :100
Creating circle of color : Red
Circle: Draw() [Color : Red, x : 15, y :44, radius :100
Circle: Draw() [Color : Green, x : 19, y :10, radius :100
Circle: Draw() [Color : Green, x : 94, y :32, radius :100
Circle: Draw() [Color : White, x : 69, y :98, radius :100
Creating circle of color : Blue
Circle: Draw() [Color : Blue, x : 13, y :4, radius :100
Circle: Draw() [Color : Green, x : 21, y :21, radius :100
Circle: Draw() [Color : Blue, x : 55, y :86, radius :100
Circle: Draw() [Color : White, x : 90, y :70, radius :100
Circle: Draw() [Color : Green, x : 78, y :3, radius :100
Circle: Draw() [Color : Green, x : 64, y :89, radius :100
Circle: Draw() [Color : Blue, x : 3, y :91, radius :100
Circle: Draw() [Color : Blue, x : 62, y :82, radius :100
Circle: Draw() [Color : Green, x : 97, y :61, radius :100
Circle: Draw() [Color : Green, x : 86, y :12, radius :100
Circle: Draw() [Color : Green, x : 38, y :93, radius :100
Circle: Draw() [Color : Red, x : 76, y :82, radius :100
Circle: Draw() [Color : Blue, x : 95, y :82, radius :100

Im Proxy-Muster repräsentiert eine Klasse die Funktionalität einer anderen Klasse. Diese Art von Entwurfsmuster fällt unter Strukturmuster.

Im Proxy-Muster erstellen wir ein Objekt mit dem ursprünglichen Objekt, um seine Funktionalität mit der Außenwelt zu verbinden.

Implementierung

Wir werden eine Image- Schnittstelle und konkrete Klassen erstellen, die die Image- Schnittstelle implementieren . ProxyImage ist eine Proxy-Klasse, um den Speicherbedarf beim Laden von RealImage- Objekten zu verringern .

ProxyPatternDemo , unsere Demo-Klasse, verwendet ProxyImage , um ein Image- Objekt zu laden und nach Bedarf anzuzeigen.

Schritt 1

Erstellen Sie eine Schnittstelle.

Image.java

public interface Image {
   void display();
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

RealImage.java

public class RealImage implements Image {

   private String fileName;

   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }

   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }

   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}

ProxyImage.java

public class ProxyImage implements Image{

   private RealImage realImage;
   private String fileName;

   public ProxyImage(String fileName){
      this.fileName = fileName;
   }

   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}

Schritt 3

Verwenden Sie ProxyImage , um bei Bedarf ein Objekt der RealImage- Klasse abzurufen .

ProxyPatternDemo.java

public class ProxyPatternDemo {
	
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");

      //image will be loaded from disk
      image.display(); 
      System.out.println("");
      //image will not be loaded from disk
      image.display(); 	
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Loading test_10mb.jpg
Displaying test_10mb.jpg

Displaying test_10mb.jpg

Wie der Name schon sagt, erstellt das Verantwortungskettenmuster eine Kette von Empfängerobjekten für eine Anforderung. Dieses Muster entkoppelt Sender und Empfänger einer Anfrage basierend auf der Art der Anfrage. Dieses Muster fällt unter Verhaltensmuster.

In diesem Muster enthält normalerweise jeder Empfänger einen Verweis auf einen anderen Empfänger. Wenn ein Objekt die Anforderung nicht verarbeiten kann, gibt es dasselbe an den nächsten Empfänger weiter und so weiter.

Implementierung

Wir haben eine abstrakte Klasse AbstractLogger mit einer Protokollierungsstufe erstellt. Dann haben wir drei Arten von Loggern erstellt, die den AbstractLogger erweitern . Jeder Logger überprüft die Nachrichtenebene auf ihre Ebene und druckt entsprechend. Andernfalls wird die Nachricht nicht gedruckt und an den nächsten Logger weitergeleitet.

Schritt 1

Erstellen Sie eine abstrakte Logger-Klasse.

AbstractLogger.java

public abstract class AbstractLogger {
   public static int INFO = 1;
   public static int DEBUG = 2;
   public static int ERROR = 3;

   protected int level;

   //next element in chain or responsibility
   protected AbstractLogger nextLogger;

   public void setNextLogger(AbstractLogger nextLogger){
      this.nextLogger = nextLogger;
   }

   public void logMessage(int level, String message){
      if(this.level <= level){
         write(message);
      }
      if(nextLogger !=null){
         nextLogger.logMessage(level, message);
      }
   }

   abstract protected void write(String message);
	
}

Schritt 2

Erstellen Sie konkrete Klassen, die den Logger erweitern.

ConsoleLogger.java

public class ConsoleLogger extends AbstractLogger {

   public ConsoleLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {		
      System.out.println("Standard Console::Logger: " + message);
   }
}

ErrorLogger.java

public class ErrorLogger extends AbstractLogger {

   public ErrorLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {		
      System.out.println("Error Console::Logger: " + message);
   }
}

FileLogger.java

public class FileLogger extends AbstractLogger {

   public FileLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {		
      System.out.println("File::Logger: " + message);
   }
}

Schritt 3

Erstellen Sie verschiedene Arten von Loggern. Weisen Sie ihnen Fehlerstufen zu und legen Sie in jedem Logger den nächsten Logger fest. Der nächste Logger in jedem Logger repräsentiert den Teil der Kette.

ChainPatternDemo.java

public class ChainPatternDemo {
	
   private static AbstractLogger getChainOfLoggers(){

      AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
      AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
      AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

      errorLogger.setNextLogger(fileLogger);
      fileLogger.setNextLogger(consoleLogger);

      return errorLogger;	
   }

   public static void main(String[] args) {
      AbstractLogger loggerChain = getChainOfLoggers();

      loggerChain.logMessage(AbstractLogger.INFO, 
         "This is an information.");

      loggerChain.logMessage(AbstractLogger.DEBUG, 
         "This is an debug level information.");

      loggerChain.logMessage(AbstractLogger.ERROR, 
         "This is an error information.");
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Standard Console::Logger: This is an information.
File::Logger: This is an debug level information.
Standard Console::Logger: This is an debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.

Das Befehlsmuster ist ein datengesteuertes Entwurfsmuster und fällt unter die Kategorie Verhaltensmuster. Eine Anforderung wird als Befehl unter ein Objekt eingeschlossen und an das Aufruferobjekt übergeben. Das Invoker-Objekt sucht nach dem entsprechenden Objekt, das diesen Befehl verarbeiten und den Befehl an das entsprechende Objekt übergeben kann, und dieses Objekt führt den Befehl aus.

Implementierung

Wir haben eine Schnittstelle geschaffen Auftrag , die als Befehl handelt. Wir haben eine Aktienklasse erstellt , die als Anfrage fungiert. Wir haben konkrete Befehlsklassen BuyStock und SellStock, die die Order- Schnittstelle implementieren , die die eigentliche Befehlsverarbeitung übernimmt. Eine Klasse Broker erzeugt , die wirkt wie ein Aufrufer - Objekt. Es kann Bestellungen annehmen und Bestellungen aufgeben.

Das Broker- Objekt verwendet das Befehlsmuster, um zu identifizieren, welches Objekt welchen Befehl basierend auf dem Befehlstyp ausführt. CommandPatternDemo , unsere Demo-Klasse, verwendet die Broker- Klasse, um das Befehlsmuster zu demonstrieren.

Schritt 1

Erstellen Sie eine Befehlsschnittstelle.

Order.java

public interface Order {
   void execute();
}

Schritt 2

Erstellen Sie eine Anforderungsklasse.

Stock.java

public class Stock {
	
   private String name = "ABC";
   private int quantity = 10;

   public void buy(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] bought");
   }
   public void sell(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] sold");
   }
}

Schritt 3

Erstellen Sie konkrete Klassen, die die Order- Schnittstelle implementieren .

BuyStock.java

public class BuyStock implements Order {
   private Stock abcStock;

   public BuyStock(Stock abcStock){
      this.abcStock = abcStock;
   }

   public void execute() {
      abcStock.buy();
   }
}

SellStock.java

public class SellStock implements Order {
   private Stock abcStock;

   public SellStock(Stock abcStock){
      this.abcStock = abcStock;
   }

   public void execute() {
      abcStock.sell();
   }
}

Schritt 4

Erstellen Sie eine Befehlsaufruferklasse.

Broker.java

import java.util.ArrayList;
import java.util.List;

   public class Broker {
   private List<Order> orderList = new ArrayList<Order>(); 

   public void takeOrder(Order order){
      orderList.add(order);		
   }

   public void placeOrders(){
      for (Order order : orderList) {
         order.execute();
      }
      orderList.clear();
   }
}

Schritt 5

Verwenden Sie die Broker-Klasse, um Befehle zu übernehmen und auszuführen.

CommandPatternDemo.java

public class CommandPatternDemo {
   public static void main(String[] args) {
      Stock abcStock = new Stock();

      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);

      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);

      broker.placeOrders();
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold

Das Interpreter-Muster bietet eine Möglichkeit, die Grammatik oder den Ausdruck einer Sprache zu bewerten. Diese Art von Muster fällt unter Verhaltensmuster. Dieses Muster beinhaltet die Implementierung einer Ausdrucksschnittstelle, die angibt, einen bestimmten Kontext zu interpretieren. Dieses Muster wird beim SQL-Parsing, bei der Symbolverarbeitungsengine usw. verwendet.

Implementierung

Wir werden eine Schnittstelle Expression und konkrete Klassen erstellen, die die Expression- Schnittstelle implementieren . Es ist eine Klasse TerminalExpression definiert, die als Hauptinterpreter des betreffenden Kontexts fungiert. Andere Klassen OrExpression , AndExpression werden verwendet, um kombinatorische Ausdrücke zu erstellen.

InterpreterPatternDemo , unsere Demo-Klasse, verwendet die Expression- Klasse, um Regeln zu erstellen und das Parsen von Ausdrücken zu demonstrieren.

Schritt 1

Erstellen Sie eine Ausdrucksschnittstelle.

Expression.java

public interface Expression {
   public boolean interpret(String context);
}

Schritt 2

Erstellen Sie konkrete Klassen, die die obige Schnittstelle implementieren.

TerminalExpression.java

public class TerminalExpression implements Expression {
	
   private String data;

   public TerminalExpression(String data){
      this.data = data; 
   }

   @Override
   public boolean interpret(String context) {
      if(context.contains(data)){
         return true;
      }
      return false;
   }
}

OrExpression.java

public class OrExpression implements Expression {
	 
   private Expression expr1 = null;
   private Expression expr2 = null;

   public OrExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {		
      return expr1.interpret(context) || expr2.interpret(context);
   }
}

AndExpression.java

public class AndExpression implements Expression {
	 
   private Expression expr1 = null;
   private Expression expr2 = null;

   public AndExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {		
      return expr1.interpret(context) && expr2.interpret(context);
   }
}

Schritt 3

InterpreterPatternDemo verwendet die Expression- Klasse, um Regeln zu erstellen und diese dann zu analysieren.

InterpreterPatternDemo.java

public class InterpreterPatternDemo {

   //Rule: Robert and John are male
   public static Expression getMaleExpression(){
      Expression robert = new TerminalExpression("Robert");
      Expression john = new TerminalExpression("John");
      return new OrExpression(robert, john);		
   }

   //Rule: Julie is a married women
   public static Expression getMarriedWomanExpression(){
      Expression julie = new TerminalExpression("Julie");
      Expression married = new TerminalExpression("Married");
      return new AndExpression(julie, married);		
   }

   public static void main(String[] args) {
      Expression isMale = getMaleExpression();
      Expression isMarriedWoman = getMarriedWomanExpression();

      System.out.println("John is male? " + isMale.interpret("John"));
      System.out.println("Julie is a married women? " 
      + isMarriedWoman.interpret("Married Julie"));
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

John is male? true
Julie is a married women? true

Iteratormuster sind sehr häufig verwendete Entwurfsmuster in Java- und .NET-Programmierumgebungen. Dieses Muster wird verwendet, um eine Möglichkeit zu erhalten, sequentiell auf die Elemente eines Sammlungsobjekts zuzugreifen, ohne die zugrunde liegende Darstellung kennen zu müssen.

Das Iteratormuster fällt unter die Kategorie Verhaltensmuster.

Implementierung

Wir werden eine Iterator- Schnittstelle erstellen , die die Navigationsmethode beschreibt, und eine Container- Schnittstelle, die den Iterator erneut ausführt. Konkrete Klassen, die die Container- Schnittstelle implementieren , sind dafür verantwortlich, die Iterator- Schnittstelle zu implementieren und zu verwenden

IteratorPatternDemo , unsere Demo - Klasse verwenden NamesRepository , eine konkrete Klasse Implementierung ein drucken Namen als eine Sammlung in gespeichert NamesRepository .

Schritt 1

Schnittstellen erstellen.

Iterator.java

public interface Iterator {
   public boolean hasNext();
   public Object next();
}

Container.java

public interface Container {
   public Iterator getIterator();
}

Schritt 2

Erstellen Sie eine konkrete Klasse, die die Container- Schnittstelle implementiert . Diese Klasse hat die innere Klasse NameIterator, die die Iterator- Schnittstelle implementiert .

NameRepository.java

public class NameRepository implements Container {
   public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

   @Override
   public Iterator getIterator() {
      return new NameIterator();
   }

   private class NameIterator implements Iterator {

      int index;

      @Override
      public boolean hasNext() {
         if(index < names.length){
            return true;
         }
         return false;
      }

      @Override
      public Object next() {
         if(this.hasNext()){
            return names[index++];
         }
         return null;
      }		
   }
}

Schritt 3

Verwenden Sie das NameRepository , um Iterator- und Drucknamen abzurufen .

IteratorPatternDemo.java

public class IteratorPatternDemo {
	
   public static void main(String[] args) {
      NameRepository namesRepository = new NameRepository();

      for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
         String name = (String)iter.next();
         System.out.println("Name : " + name);
      } 	
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Name : Robert
Name : John
Name : Julie
Name : Lora

Das Mediatormuster wird verwendet, um die Kommunikationskomplexität zwischen mehreren Objekten oder Klassen zu verringern. Dieses Muster stellt eine Mediatorklasse bereit, die normalerweise die gesamte Kommunikation zwischen verschiedenen Klassen abwickelt und die einfache Wartbarkeit des Codes durch lose Kopplung unterstützt. Das Mediatormuster fällt unter die Kategorie Verhaltensmuster.

Implementierung

Wir demonstrieren das Mediatormuster anhand eines Chatrooms, in dem mehrere Benutzer Nachrichten an den Chatroom senden können. Es liegt in der Verantwortung des Chatrooms, die Nachrichten allen Benutzern anzuzeigen. Wir haben zwei Klassen ChatRoom und User erstellt . Benutzerobjekte verwenden die ChatRoom- Methode, um ihre Nachrichten freizugeben .

MediatorPatternDemo , unsere Demo-Klasse, verwendet Benutzerobjekte , um die Kommunikation zwischen ihnen anzuzeigen.

Schritt 1

Mediator-Klasse erstellen.

ChatRoom.java

import java.util.Date;

public class ChatRoom {
   public static void showMessage(User user, String message){
      System.out.println(new Date().toString()
         + " [" + user.getName() +"] : " + message);
   }
}

Schritt 2

Benutzerklasse erstellen

User.java

public class User {
   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public User(String name){
      this.name  = name;
   }

   public void sendMessage(String message){
      ChatRoom.showMessage(this,message);
   }
}

Schritt 3

Verwenden Sie das Benutzerobjekt , um die Kommunikation zwischen ihnen anzuzeigen.

MediatorPatternDemo.java

public class MediatorPatternDemo {
   public static void main(String[] args) {
      User robert = new User("Robert");
      User john = new User("John");

      robert.sendMessage("Hi! John!");
      john.sendMessage("Hello! Robert!");
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John!
Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!

Das Erinnerungsmuster wird verwendet, um zu reduzieren, wo der Status eines Objekts auf einen vorherigen Status zurückgesetzt werden soll. Das Erinnerungsmuster fällt unter die Kategorie Verhaltensmuster.

Implementierung

Das Erinnerungsmuster verwendet drei Schauspielerklassen. Memento enthält den Status eines wiederherzustellenden Objekts. Originator erstellt und speichert Status in Memento-Objekten und im Caretaker-Objekt, das für die Wiederherstellung des Objektstatus aus Memento verantwortlich ist. Wir haben die Klassen Memento , Originator und CareTaker erstellt .

MementoPatternDemo , unsere Demo-Klasse, verwendet CareTaker- und Originator- Objekte, um die Wiederherstellung von Objektzuständen anzuzeigen .

Schritt 1

Erstellen Sie eine Memento-Klasse.

Memento.java

public class Memento {
   private String state;

   public Memento(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }	
}

Schritt 2

Erstellen Sie eine Originator-Klasse

Originator.java

public class Originator {
   private String state;

   public void setState(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }

   public Memento saveStateToMemento(){
      return new Memento(state);
   }

   public void getStateFromMemento(Memento Memento){
      state = memento.getState();
   }
}

Schritt 3

Erstellen Sie die CareTaker-Klasse

CareTaker.java

import java.util.ArrayList;
import java.util.List;

public class CareTaker {
   private List<Memento> mementoList = new ArrayList<Memento>();

   public void add(Memento state){
      mementoList.add(state);
   }

   public Memento get(int index){
      return mementoList.get(index);
   }
}

Schritt 4

Verwenden Sie CareTaker- und Originator- Objekte.

MementoPatternDemo.java

public class MementoPatternDemo {
   public static void main(String[] args) {
      Originator originator = new Originator();
      CareTaker careTaker = new CareTaker();
      originator.setState("State #1");
      originator.setState("State #2");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #3");
      careTaker.add(originator.saveStateToMemento());
      originator.setState("State #4");

      System.out.println("Current State: " + originator.getState());		
      originator.getStateFromMemento(careTaker.get(0));
      System.out.println("First saved State: " + originator.getState());
      originator.getStateFromMemento(careTaker.get(1));
      System.out.println("Second saved State: " + originator.getState());
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Current State: State #4
First saved State: State #2
Second saved State: State #3

Das Beobachtermuster wird verwendet, wenn zwischen Objekten eine zu viele Beziehungen bestehen, z. B. wenn ein Objekt geändert wird, müssen seine abhängigen Objekte automatisch benachrichtigt werden. Das Beobachtermuster fällt unter die Kategorie Verhaltensmuster.

Implementierung

Das Beobachtermuster verwendet drei Akteursklassen. Betreff, Beobachter und Kunde. Subjekt, ein Objekt mit Methoden zum Anhängen und Deaktivieren von Beobachtern an ein Clientobjekt. Wir haben Klassen Subject , Observer Abstract Class und konkrete Klassen erstellt, die die abstrakte Klasse Observer erweitern .

ObserverPatternDemo , unsere Demo-Klasse, verwendet Subject- und konkrete Klassenobjekte, um das Beobachtermuster in Aktion anzuzeigen.

Schritt 1

Betreffklasse erstellen.

Subject.java

import java.util.ArrayList;
import java.util.List;

public class Subject {
	
   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;

   public int getState() {
      return state;
   }

   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }

   public void attach(Observer observer){
      observers.add(observer);		
   }

   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   } 	
}

Schritt 2

Observer-Klasse erstellen.

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

Schritt 3

Erstellen Sie konkrete Beobachterklassen

BinaryObserver.java

public class BinaryObserver extends Observer{

   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}

OctalObserver.java

public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
     System.out.println( "Octal String: " 
     + Integer.toOctalString( subject.getState() ) ); 
   }
}

HexaObserver.java

public class HexaObserver extends Observer{

   public HexaObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Hex String: " 
      + Integer.toHexString( subject.getState() ).toUpperCase() ); 
   }
}

Schritt 4

Verwenden Sie Subjekt- und konkrete Beobachterobjekte.

ObserverPatternDemo.java

public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();

      new HexaObserver(subject);
      new OctalObserver(subject);
      new BinaryObserver(subject);

      System.out.println("First state change: 15");	
      subject.setState(15);
      System.out.println("Second state change: 10");	
      subject.setState(10);
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010

Im Statusmuster ändert sich das Verhalten einer Klasse basierend auf ihrem Status. Diese Art von Entwurfsmuster fällt unter Verhaltensmuster.

Im Statusmuster erstellen wir Objekte, die verschiedene Status darstellen, und ein Kontextobjekt, dessen Verhalten sich ändert, wenn sich das Statusobjekt ändert.

Implementierung

Wir werden eine erstellen staatliche Schnittstelle eine Aktion und konkrete Zustandsklassen der Umsetzung der Definition von Staat Schnittstelle. Kontext ist eine Klasse, die einen Zustand trägt.

StaePatternDemo , unsere Demo - Klasse verwendet Kontext und Statusobjekte Änderung im Kontext Verhalten es in ist , basierend auf Art von Staat zu demonstrieren.

Schritt 1

Erstellen Sie eine Schnittstelle.

Image.java

public interface State {
   public void doAction(Context context);
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

StartState.java

public class StartState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in start state");
      context.setState(this);	
   }

   public String toString(){
      return "Start State";
   }
}

StopState.java

public class StopState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in stop state");
      context.setState(this);	
   }

   public String toString(){
      return "Stop State";
   }
}

Schritt 3

Erstellen Context - Klasse.

Context.java

public class Context {
   private State state;

   public Context(){
      state = null;
   }

   public void setState(State state){
      this.state = state;		
   }

   public State getState(){
      return state;
   }
}

Schritt 4

Verwenden Sie den Kontext , um Verhaltensänderungen zu sehen, wenn sich der Status ändert.

StatePatternDemo.java

public class StatePatternDemo {
   public static void main(String[] args) {
      Context context = new Context();

      StartState startState = new StartState();
      startState.doAction(context);

      System.out.println(context.getState().toString());

      StopState stopState = new StopState();
      stopState.doAction(context);

      System.out.println(context.getState().toString());
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Player is in start state
Start State
Player is in stop state
Stop State

Im Nullobjektmuster ersetzt ein Nullobjekt die Überprüfung der NULL-Objektinstanz. Anstatt zu setzen, ob nach einem Nullwert gesucht wird, spiegelt Null Object eine Do-Nothing-Beziehung wider. Ein solches Null-Objekt kann auch verwendet werden, um ein Standardverhalten bereitzustellen, falls keine Daten verfügbar sind.

Im Nullobjektmuster erstellen wir eine abstrakte Klasse, die die verschiedenen auszuführenden Operationen angibt, erstellen Klassen, die diese Klasse erweitern, und eine Nullobjektklasse, sofern diese Klasse nicht implementiert wird, und werden scheinbar dort verwendet, wo wir den Nullwert überprüfen müssen.

Implementierung

Wir werden eine abstrakte AbstractCustomer-Klasse erstellen, die Operationen definiert, hier den Namen des Kunden und konkrete Klassen, die die AbstractCustomer- Klasse erweitern. Eine Factory-Klasse CustomerFactory wird erstellt, um entweder RealCustomer- oder NullCustomer- Objekte basierend auf dem Namen des an sie übergebenen Kunden zurückzugeben.

NullPatternDemo , unsere Demo-Klasse, verwendet CustomerFactory , um die Verwendung des Null-Objekt-Musters zu demonstrieren.

Schritt 1

Erstellen Sie eine abstrakte Klasse.

AbstractCustomer.java

public abstract class AbstractCustomer {
   protected String name;
   public abstract boolean isNil();
   public abstract String getName();
}

Schritt 2

Erstellen Sie konkrete Klassen, die die obige Klasse erweitern.

RealCustomer.java

public class RealCustomer extends AbstractCustomer {

   public RealCustomer(String name) {
      this.name = name;		
   }
   
   @Override
   public String getName() {
      return name;
   }
   
   @Override
   public boolean isNil() {
      return false;
   }
}

NullCustomer.java

public class NullCustomer extends AbstractCustomer {

   @Override
   public String getName() {
      return "Not Available in Customer Database";
   }

   @Override
   public boolean isNil() {
      return true;
   }
}

Schritt 3

Erstellen Sie eine CustomerFactory- Klasse.

CustomerFactory.java

public class CustomerFactory {
	
   public static final String[] names = {"Rob", "Joe", "Julie"};

   public static AbstractCustomer getCustomer(String name){
      for (int i = 0; i < names.length; i++) {
         if (names[i].equalsIgnoreCase(name)){
            return new RealCustomer(name);
         }
      }
      return new NullCustomer();
   }
}

Schritt 4

Verwenden Sie die CustomerFactory, um entweder RealCustomer- oder NullCustomer- Objekte basierend auf dem Namen des an sie übergebenen Kunden abzurufen .

NullPatternDemo.java

public class NullPatternDemo {
   public static void main(String[] args) {

      AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
      AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
      AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
      AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");

      System.out.println("Customers");
      System.out.println(customer1.getName());
      System.out.println(customer2.getName());
      System.out.println(customer3.getName());
      System.out.println(customer4.getName());
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Customers
Rob
Not Available in Customer Database
Julie
Not Available in Customer Database

Im Strategiemuster kann ein Klassenverhalten oder sein Algorithmus zur Laufzeit geändert werden. Diese Art von Entwurfsmuster fällt unter Verhaltensmuster.

Im Strategiemuster erstellen wir Objekte, die verschiedene Strategien darstellen, und ein Kontextobjekt, dessen Verhalten je nach Strategieobjekt variiert. Das Strategieobjekt ändert den Ausführungsalgorithmus des Kontextobjekts.

Implementierung

Wir werden eine Strategie- Schnittstelle erstellen , die eine Aktion definiert, und konkrete Strategieklassen, die die Strategie- Schnittstelle implementieren . Kontext ist eine Klasse, die eine Strategie verwendet.

StrategyPatternDemo , unsere Demo-Klasse, verwendet Kontext- und Strategieobjekte, um Änderungen im Kontextverhalten basierend auf der Strategie zu demonstrieren, die sie bereitstellt oder verwendet.

Schritt 1

Erstellen Sie eine Schnittstelle.

Strategy.java

public interface Strategy {
   public int doOperation(int num1, int num2);
}

Schritt 2

Erstellen Sie konkrete Klassen, die dieselbe Schnittstelle implementieren.

OperationAdd.java

public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}

OperationSubstract.java

public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}

OperationMultiply.java

public class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}

Schritt 3

Erstellen Context - Klasse.

Context.java

public class Context {
   private Strategy strategy;

   public Context(Strategy strategy){
      this.strategy = strategy;
   }

   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

Schritt 4

Verwenden Sie den Kontext , um Verhaltensänderungen zu sehen, wenn die Strategie geändert wird .

StatePatternDemo.java

public class StrategyPatternDemo {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());		
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationSubstract());		
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationMultiply());		
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

Im Vorlagenmuster stellt eine abstrakte Klasse definierte Methoden / Vorlagen zur Ausführung ihrer Methoden bereit. Seine Unterklassen können die Methodenimplementierungen nach Bedarf überschreiben, aber der Aufruf muss auf die gleiche Weise erfolgen, wie sie von einer abstrakten Klasse definiert wird. Dieses Muster fällt unter die Kategorie Verhaltensmuster.

Implementierung

Wir werden eine erstellen Spiel abstrakte Klasse Operationen definiert , mit einem Template - Methode Satz endgültig so sein , dass es nicht außer Kraft gesetzt werden kann. Cricket und Fußball sind konkrete Klassen, die das Spiel erweitern und seine Methoden außer Kraft setzen.

TemplatePatternDemo , unsere Demo-Klasse, verwendet Game , um die Verwendung von Vorlagenmustern zu demonstrieren.

Schritt 1

Erstellen Sie eine abstrakte Klasse, wobei eine Vorlagenmethode endgültig ist.

Game.java

public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();

   //template method
   public final void play(){

      //initialize the game
      initialize();

      //start game
      startPlay();

      //end game
      endPlay();
   }
}

Schritt 2

Erstellen Sie konkrete Klassen, die die obige Klasse erweitern.

Cricket.java

public class Cricket extends Game {

   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}

Football.java

public class Football extends Game {
   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

Schritt 3

Verwenden Sie das Spiel ‚s Template - Methode play () eine definierte Art und Weise des Spielens Spiel zu demonstrieren.

TemplatePatternDemo.java

public class TemplatePatternDemo {
   public static void main(String[] args) {

      Game game = new Cricket();
      game.play();
      System.out.println();
      game = new Football();
      game.play();		
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!

Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!

Im Besuchermuster verwenden wir eine Besucherklasse, die den Ausführungsalgorithmus einer Elementklasse ändert. Auf diese Weise kann der Ausführungsalgorithmus des Elements variieren, wenn der Besucher variiert. Dieses Muster fällt unter die Kategorie Verhaltensmuster. Gemäß dem Muster muss das Elementobjekt das Besucherobjekt akzeptieren, damit das Besucherobjekt die Operation für das Elementobjekt ausführt.

Implementierung

Wir werden eine ComputerPart- Schnittstelle erstellen , die die Akzeptanzoption definiert. Tastatur , Maus , Monitor und Computer sind konkrete Klassen, die die ComputerPart- Schnittstelle implementieren . Wir definieren eine weitere Schnittstelle ComputerPartVisitor, die eine Besucherklasse definiert. Der Computer verwendet einen konkreten Besucher, um entsprechende Aktionen auszuführen.

VisitorPatternDemo , unsere Demo-Klasse, verwendet Computer- und ComputerPartVisitor- Klassen, um die Verwendung des Besuchermusters zu demonstrieren.

Schritt 1

Definieren Sie eine Schnittstelle zur Darstellung des Elements.

ComputerPart.java

public interface class ComputerPart {
   public void accept(ComputerPartVisitor computerPartVisitor);
}

Schritt 2

Erstellen Sie konkrete Klassen, die die obige Klasse erweitern.

Keyboard.java

public class Keyboard  implements ComputerPart {

   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

Monitor.java

public class Monitor  implements ComputerPart {

   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

Mouse.java

public class Mouse  implements ComputerPart {

   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

Computer.java

public class Computer implements ComputerPart {
	
   ComputerPart[] parts;

   public Computer(){
      parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};		
   } 


   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      for (int i = 0; i < parts.length; i++) {
         parts[i].accept(computerPartVisitor);
      }
      computerPartVisitor.visit(this);
   }
}

Schritt 3

Definieren Sie eine Schnittstelle zur Darstellung des Besuchers.

ComputerPartVisitor.java

public interface ComputerPartVisitor {
	public void visit(Computer computer);
	public void visit(Mouse mouse);
	public void visit(Keyboard keyboard);
	public void visit(Monitor monitor);
}

Schritt 4

Erstellen Sie einen konkreten Besucher, der die oben genannte Klasse implementiert.

ComputerPartDisplayVisitor.java

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {

   @Override
   public void visit(Computer computer) {
      System.out.println("Displaying Computer.");
   }

   @Override
   public void visit(Mouse mouse) {
      System.out.println("Displaying Mouse.");
   }

   @Override
   public void visit(Keyboard keyboard) {
      System.out.println("Displaying Keyboard.");
   }

   @Override
   public void visit(Monitor monitor) {
      System.out.println("Displaying Monitor.");
   }
}

Schritt 5

Verwenden Sie den ComputerPartDisplayVisitor , um Teile des Computers anzuzeigen .

VisitorPatternDemo.java

public class VisitorPatternDemo {
   public static void main(String[] args) {

      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.

MVC Pattern steht für Model-View-Controller Pattern. Dieses Muster wird verwendet, um die Bedenken der Anwendung zu trennen.

  • Model- Das Modell repräsentiert ein Objekt oder JAVA POJO, das Daten trägt. Es kann auch eine Logik zum Aktualisieren des Controllers haben, wenn sich seine Daten ändern.

  • View - Ansicht repräsentiert die Visualisierung der Daten, die das Modell enthält.

  • Controller- Der Controller wirkt sowohl auf das Modell als auch auf die Ansicht. Es steuert den Datenfluss in das Modellobjekt und aktualisiert die Ansicht, wenn sich Daten ändern. Es hält Ansicht und Modell getrennt.

Implementierung

Wir werden ein Student- Objekt erstellen , das als Modell fungiert. StudentView ist eine Ansichtsklasse, die Schülerdetails auf der Konsole drucken kann, und StudentController ist die Controller-Klasse, die dafür verantwortlich ist, Daten im Student- Objekt zu speichern und die Ansicht StudentView entsprechend zu aktualisieren .

MVCPatternDemo , unsere Demo-Klasse, verwendet StudentController , um die Verwendung des MVC-Musters zu demonstrieren.

Schritt 1

Modell erstellen.

Student.java

public class Student {
   private String rollNo;
   private String name;
   public String getRollNo() {
      return rollNo;
   }
   public void setRollNo(String rollNo) {
      this.rollNo = rollNo;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}

Schritt 2

Ansicht erstellen.

StudentView.java

public class StudentView {
   public void printStudentDetails(String studentName, String studentRollNo){
      System.out.println("Student: ");
      System.out.println("Name: " + studentName);
      System.out.println("Roll No: " + studentRollNo);
   }
}

Schritt 3

Controller erstellen.

StudentController.java

public class StudentController {
   private Student model;
   private StudentView view;

   public StudentController(Student model, StudentView view){
      this.model = model;
      this.view = view;
   }

   public void setStudentName(String name){
      model.setName(name);		
   }

   public String getStudentName(){
      return model.getName();		
   }

   public void setStudentRollNo(String rollNo){
      model.setRollNo(rollNo);		
   }

   public String getStudentRollNo(){
      return model.getRollNo();		
   }

   public void updateView(){				
      view.printStudentDetails(model.getName(), model.getRollNo());
   }	
}

Schritt 4

Verwenden Sie die StudentController- Methoden, um die Verwendung von MVC-Entwurfsmustern zu demonstrieren.

MVCPatternDemo.java

public class MVCPatternDemo {
   public static void main(String[] args) {

      //fetch student record based on his roll no from the database
      Student model  = retriveStudentFromDatabase();

      //Create a view : to write student details on console
      StudentView view = new StudentView();

      StudentController controller = new StudentController(model, view);

      controller.updateView();

      //update model data
      controller.setStudentName("John");

      controller.updateView();
   }

   private static Student retriveStudentFromDatabase(){
      Student student = new Student();
      student.setName("Robert");
      student.setRollNo("10");
      return student;
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Student: 
Name: Robert
Roll No: 10
Student: 
Name: Julie
Roll No: 10

Das Business Delegate Pattern wird verwendet, um die Präsentationsschicht und die Geschäftsschicht zu entkoppeln. Es wird im Wesentlichen verwendet, um die Kommunikations- oder Remote-Lookup-Funktionalität auf Business-Tier-Code im Presentation-Tier-Code zu reduzieren. In der Business-Ebene haben wir folgende Entitäten.

  • Client - Der Präsentationsschichtcode kann JSP-, Servlet- oder UI-Java-Code sein.

  • Business Delegate - Eine einzelne Einstiegspunktklasse für Client-Entitäten, um den Zugriff auf Business Service-Methoden zu ermöglichen.

  • LookUp Service - Das Suchdienstobjekt ist dafür verantwortlich, die relative Geschäftsimplementierung zu erhalten und den Geschäftsobjektzugriff auf das Geschäftsdelegatenobjekt bereitzustellen.

  • Business Service- Business Service-Schnittstelle. Konkrete Klassen implementieren diesen Geschäftsdienst, um die tatsächliche Geschäftsimplementierungslogik bereitzustellen.

Implementierung

Wir werden einen Client , BusinessDelegate , BusinessService , LookUpService , JMSService und EJBService erstellen, die verschiedene Entitäten des Business Delegate-Musters darstellen.

BusinessDelegatePatternDemo , unsere Demo-Klasse, verwendet BusinessDelegate und Client , um die Verwendung des Business Delegate-Musters zu demonstrieren.

Schritt 1

Erstellen Sie eine BusinessService-Schnittstelle.

BusinessService.java

public interface BusinessService {
   public void doProcessing();
}

Schritt 2

Erstellen Sie Concreate-Serviceklassen.

EJBService.java

public class EJBService implements BusinessService {

   @Override
   public void doProcessing() {
      System.out.println("Processing task by invoking EJB Service");
   }
}

JMSService.java

public class JMSService implements BusinessService {

   @Override
   public void doProcessing() {
      System.out.println("Processing task by invoking JMS Service");
   }
}

Schritt 3

Erstellen Sie einen Business Lookup Service.

BusinessLookUp.java

public class BusinessLookUp {
   public BusinessService getBusinessService(String serviceType){
      if(serviceType.equalsIgnoreCase("EJB")){
         return new EJBService();
      }else {
         return new JMSService();
      }
   }
}

Schritt 4

Geschäftsdelegierten erstellen.

BusinessLookUp.java

public class BusinessDelegate {
   private BusinessLookUp lookupService = new BusinessLookUp();
   private BusinessService businessService;
   private String serviceType;

   public void setServiceType(String serviceType){
      this.serviceType = serviceType;
   }

   public void doTask(){
      businessService = lookupService.getBusinessService(serviceType);
      businessService.doProcessing();		
   }
}

Schritt 5

Client erstellen.

Student.java

public class Client {
	
   BusinessDelegate businessService;

   public Client(BusinessDelegate businessService){
      this.businessService  = businessService;
   }

   public void doTask(){		
      businessService.doTask();
   }
}

Schritt 6

Verwenden Sie BusinessDelegate- und Client-Klassen, um das Business Delegate-Muster zu demonstrieren.

BusinessDelegatePatternDemo.java

public class BusinessDelegatePatternDemo {
	
   public static void main(String[] args) {

      BusinessDelegate businessDelegate = new BusinessDelegate();
      businessDelegate.setServiceType("EJB");

      Client client = new Client(businessDelegate);
      client.doTask();

      businessDelegate.setServiceType("JMS");
      client.doTask();
   }
}

Schritt 7

Überprüfen Sie die Ausgabe.

Processing task by invoking EJB Service
Processing task by invoking JMS Service

Das zusammengesetzte Entitätsmuster wird im EJB-Persistenzmechanismus verwendet. Eine zusammengesetzte Entität ist eine EJB-Entity-Bean, die ein Diagramm von Objekten darstellt. Wenn eine zusammengesetzte Entität aktualisiert wird, werden intern abhängige Objekt-Beans automatisch aktualisiert, da sie von der EJB-Entity-Bean verwaltet werden. Im Folgenden sind die Teilnehmer an Composite Entity Bean aufgeführt.

  • Composite Entity - Es handelt sich um eine primäre Entity-Bean. Sie kann grobkörnig sein oder ein grobkörniges Objekt enthalten, das für Persistenzzwecke verwendet werden soll.

  • Coarse-Grained Object-Dieses Objekt enthält abhängige Objekte. Es hat einen eigenen Lebenszyklus und verwaltet auch den Lebenszyklus abhängiger Objekte.

  • Dependent Object - Abhängige Objekte sind Objekte, deren Persistenzlebenszyklus von grobkörnigen Objekten abhängt.

  • Strategies - Strategien stellen dar, wie eine zusammengesetzte Entität implementiert wird.

Implementierung

Wir werden ein CompositeEntity- Objekt erstellen , das als CompositeEntity fungiert. CoarseGrainedObject ist eine Klasse, die abhängige Objekte enthält. CompositeEntityPatternDemo , unsere Demo-Klasse verwendet die Client- Klasse, um die Verwendung des Composite Entity-Musters zu demonstrieren.

Schritt 1

Erstellen Sie abhängige Objekte.

DependentObject1.java

public class DependentObject1 {
	
   private String data;

   public void setData(String data){
      this.data = data; 
   } 

   public String getData(){
      return data;
   }
}

DependentObject2.java

public class DependentObject2 {
	
   private String data;

   public void setData(String data){
      this.data = data; 
   } 

   public String getData(){
      return data;
   }
}

Schritt 2

Erstellen Sie ein grobkörniges Objekt.

CoarseGrainedObject.java

public class CoarseGrainedObject {
   DependentObject1 do1 = new DependentObject1();
   DependentObject2 do2 = new DependentObject2();

   public void setData(String data1, String data2){
      do1.setData(data1);
      do2.setData(data2);
   }

   public String[] getData(){
      return new String[] {do1.getData(),do2.getData()};
   }
}

Schritt 3

Erstellen Sie eine zusammengesetzte Entität.

CompositeEntity.java

public class CompositeEntity {
   private CoarseGrainedObject cgo = new CoarseGrainedObject();

   public void setData(String data1, String data2){
      cgo.setData(data1, data2);
   }

   public String[] getData(){
      return cgo.getData();
   }
}

Schritt 4

Erstellen Sie eine Client-Klasse, um Composite Entity zu verwenden.

Client.java

public class Client {
   private CompositeEntity compositeEntity = new CompositeEntity();

   public void printData(){
      for (int i = 0; i < compositeEntity.getData().length; i++) {
         System.out.println("Data: " + compositeEntity.getData()[i]);
      }
   }

   public void setData(String data1, String data2){
      compositeEntity.setData(data1, data2);
   }
}

Schritt 5

Verwenden Sie den Client , um die Verwendung von Entwurfsmustern für zusammengesetzte Entitäten zu demonstrieren.

CompositeEntityPatternDemo.java

public class CompositeEntityPatternDemo {
   public static void main(String[] args) {
       Client client = new Client();
       client.setData("Test", "Data");
       client.printData();
       client.setData("Second Test", "Data1");
       client.printData();
   }
}

Schritt 6

Überprüfen Sie die Ausgabe.

Data: Test
Data: Data
Data: Second Test
Data: Data1

Das Datenzugriffsobjektmuster oder DAO-Muster wird verwendet, um Datenzugriffs-API oder Vorgänge auf niedriger Ebene von Geschäftsdiensten auf hoher Ebene zu trennen. Im Folgenden sind die Teilnehmer am Datenzugriffsobjektmuster aufgeführt.

  • Data Access Object Interface - Diese Schnittstelle definiert die Standardoperationen, die an einem oder mehreren Modellobjekten ausgeführt werden sollen.

  • Data Access Object concrete class-Diese Klasse implementiert die obige Schnittstelle. Diese Klasse ist dafür verantwortlich, Daten aus einer Datenquelle abzurufen, die Datenbank / XML oder ein anderer Speichermechanismus sein kann.

  • Model Object or Value Object - Dieses Objekt ist ein einfaches POJO, das get / set-Methoden zum Speichern von Daten enthält, die mit der DAO-Klasse abgerufen wurden.

Implementierung

Wir werden ein Student- Objekt erstellen , das als Modell- oder Wertobjekt fungiert. StudentDao ist die Datenzugriffsobjektschnittstelle. StudentDaoImpl ist eine konkrete Klasse, die die Datenzugriffsobjektschnittstelle implementiert. DaoPatternDemo , unsere Demo-Klasse, verwendet StudentDao, um die Verwendung des Datenzugriffsobjektmusters zu demonstrieren.

Schritt 1

Wertobjekt erstellen.

Student.java

public class Student {
   private String name;
   private int rollNo;

   Student(String name, int rollNo){
      this.name = name;
      this.rollNo = rollNo;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getRollNo() {
      return rollNo;
   }

   public void setRollNo(int rollNo) {
      this.rollNo = rollNo;
   }
}

Schritt 2

Datenzugriffsobjektschnittstelle erstellen.

StudentDao.java

import java.util.List;

public interface StudentDao {
   public List<Student> getAllStudents();
   public Student getStudent(int rollNo);
   public void updateStudent(Student student);
   public void deleteStudent(Student student);
}

Schritt 3

Erstellen Sie eine Concreate-Klasse, die die obige Schnittstelle implementiert.

StudentDaoImpl.java

import java.util.ArrayList;
import java.util.List;

public class StudentDaoImpl implements StudentDao {
	
   //list is working as a database
   List<Student> students;

   public StudentDaoImpl(){
      students = new ArrayList<Student>();
      Student student1 = new Student("Robert",0);
      Student student2 = new Student("John",1);
      students.add(student1);
      students.add(student2);		
   }
   @Override
   public void deleteStudent(Student student) {
      students.remove(student.getRollNo());
      System.out.println("Student: Roll No " + student.getRollNo() 
         +", deleted from database");
   }

   //retrive list of students from the database
   @Override
   public List<Student> getAllStudents() {
      return students;
   }

   @Override
   public Student getStudent(int rollNo) {
      return students.get(rollNo);
   }

   @Override
   public void updateStudent(Student student) {
      students.get(student.getRollNo()).setName(student.getName());
      System.out.println("Student: Roll No " + student.getRollNo() 
         +", updated in the database");
   }
}

Schritt 4

Verwenden Sie StudentDao , um die Verwendung von Datenzugriffsobjektmustern zu demonstrieren.

CompositeEntityPatternDemo.java

public class DaoPatternDemo {
   public static void main(String[] args) {
      StudentDao studentDao = new StudentDaoImpl();

      //print all students
      for (Student student : studentDao.getAllStudents()) {
         System.out.println("Student: [RollNo : "
            +student.getRollNo()+", Name : "+student.getName()+" ]");
      }


      //update student
      Student student =studentDao.getAllStudents().get(0);
      student.setName("Michael");
      studentDao.updateStudent(student);

      //get the student
      studentDao.getStudent(0);
      System.out.println("Student: [RollNo : "
         +student.getRollNo()+", Name : "+student.getName()+" ]");		
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]

Das Entwurfsmuster des Frontcontrollers wird verwendet, um einen zentralen Anforderungsbearbeitungsmechanismus bereitzustellen, sodass alle Anforderungen von einem einzelnen Handler verarbeitet werden. Dieser Handler kann die Authentifizierung / Autorisierung / Protokollierung oder Verfolgung der Anforderung durchführen und die Anforderungen dann an die entsprechenden Handler weiterleiten. Im Folgenden sind die Entitäten dieser Art von Entwurfsmuster aufgeführt.

  • Front Controller - Einzelner Handler für alle Arten von Anfragen an die Anwendung (entweder webbasiert / desktopbasiert).

  • Dispatcher - Front Controller kann ein Dispatcher-Objekt verwenden, das die Anforderung an den entsprechenden spezifischen Handler senden kann.

  • View - Ansichten sind das Objekt, für das die Anforderungen gestellt werden.

Implementierung

Wir werden einen FrontController , einen Dispatcher erstellen , der entsprechend als Front Controller und Dispatcher fungiert. HomeView und StudentView stellen verschiedene Ansichten dar, für die Anforderungen an den Front-Controller gesendet werden können.

FrontControllerPatternDemo , unsere Demo-Klasse, verwendet FrontController, um das Front Controller Design Pattern zu demonstrieren.

Schritt 1

Ansichten erstellen.

HomeView.java

public class HomeView {
   public void show(){
      System.out.println("Displaying Home Page");
   }
}

StudentView.java

public class StudentView {
   public void show(){
      System.out.println("Displaying Student Page");
   }
}

Schritt 2

Dispatcher erstellen.

Dispatcher.java

public class Dispatcher {
   private StudentView studentView;
   private HomeView homeView;
   public Dispatcher(){
      studentView = new StudentView();
      homeView = new HomeView();
   }

   public void dispatch(String request){
      if(request.equalsIgnoreCase("STUDENT")){
         studentView.show();
      }else{
         homeView.show();
      }	
   }
}

Schritt 3

Erstellen Sie FrontController

Context.java

public class FrontController {
	
   private Dispatcher dispatcher;

   public FrontController(){
      dispatcher = new Dispatcher();
   }

   private boolean isAuthenticUser(){
      System.out.println("User is authenticated successfully.");
      return true;
   }

   private void trackRequest(String request){
      System.out.println("Page requested: " + request);
   }

   public void dispatchRequest(String request){
      //log each request
      trackRequest(request);
      //authenticate the user
      if(isAuthenticUser()){
         dispatcher.dispatch(request);
      }	
   }
}

Schritt 4

Verwenden Sie den FrontController , um das Entwurfsmuster des Frontcontrollers zu demonstrieren.

FrontControllerPatternDemo.java

public class FrontControllerPatternDemo {
   public static void main(String[] args) {
      FrontController frontController = new FrontController();
      frontController.dispatchRequest("HOME");
      frontController.dispatchRequest("STUDENT");
   }
}

Schritt 5

Überprüfen Sie die Ausgabe.

Page requested: HOME
User is authenticated successfully.
Displaying Home Page
Page requested: STUDENT
User is authenticated successfully.
Displaying Student Page

Das Abfangfilter-Entwurfsmuster wird verwendet, wenn eine Vorverarbeitung / Nachverarbeitung mit Anforderung oder Antwort der Anwendung durchgeführt werden soll. Filter werden definiert und auf die Anforderung angewendet, bevor die Anforderung an die tatsächliche Zielanwendung übergeben wird. Filter können die Authentifizierung / Autorisierung / Protokollierung oder Nachverfolgung von Anforderungen durchführen und die Anforderungen dann an die entsprechenden Handler weiterleiten. Im Folgenden sind die Entitäten dieser Art von Entwurfsmuster aufgeführt.

  • Filter - Filter, der bestimmte Aufgaben vor oder nach der Ausführung der Anforderung durch den Anforderungshandler ausführt.

  • Filter Chain - Die Filterkette enthält mehrere Filter und hilft, diese in definierter Reihenfolge auf dem Ziel auszuführen.

  • Target - Zielobjekt ist der Anforderungshandler

  • Filter Manager - Filter Manager verwaltet die Filter und die Filterkette.

  • Client - Client ist das Objekt, das eine Anforderung an das Zielobjekt sendet.

Implementierung

Wir werden FilterChain , FilterManager , Target , Client als verschiedene Objekte erstellen , die unsere Entitäten darstellen. AuthenticationFilter und DebugFilter stehen für konkrete Filter.

InterceptingFilterDemo , unsere Demo-Klasse, verwendet Client , um das Intercepting Filter Design Pattern zu demonstrieren.

Schritt 1

Filterschnittstelle erstellen.

Filter.java

public interface Filter {
   public void execute(String request);
}

Schritt 2

Erstellen Sie konkrete Filter.

AuthenticationFilter.java

public class AuthenticationFilter implements Filter {
   public void execute(String request){
      System.out.println("Authenticating request: " + request);
   }
}

DebugFilter.java

public class DebugFilter implements Filter {
   public void execute(String request){
      System.out.println("request log: " + request);
   }
}

Schritt 3

Ziel erstellen

Target.java

public class Target {
   public void execute(String request){
      System.out.println("Executing request: " + request);
   }
}

Schritt 4

Filterkette erstellen

FilterChain.java

import java.util.ArrayList;
import java.util.List;

public class FilterChain {
   private List<Filter> filters = new ArrayList<Filter>();
   private Target target;

   public void addFilter(Filter filter){
      filters.add(filter);
   }

   public void execute(String request){
      for (Filter filter : filters) {
         filter.execute(request);
      }
      target.execute(request);
   }

   public void setTarget(Target target){
      this.target = target;
   }
}

Schritt 5

Erstellen Sie den Filter-Manager

FilterManager.java

public class FilterManager {
   FilterChain filterChain;

   public FilterManager(Target target){
      filterChain = new FilterChain();
      filterChain.setTarget(target);
   }
   public void setFilter(Filter filter){
      filterChain.addFilter(filter);
   }

   public void filterRequest(String request){
      filterChain.execute(request);
   }
}

Schritt 6

Client erstellen

Client.java

public class Client {
   FilterManager filterManager;

   public void setFilterManager(FilterManager filterManager){
      this.filterManager = filterManager;
   }

   public void sendRequest(String request){
      filterManager.filterRequest(request);
   }
}

Schritt 7

Verwenden Sie den Client , um das Intercepting Filter Design Pattern zu demonstrieren.

FrontControllerPatternDemo.java

public class InterceptingFilterDemo {
   public static void main(String[] args) {
      FilterManager filterManager = new FilterManager(new Target());
      filterManager.setFilter(new AuthenticationFilter());
      filterManager.setFilter(new DebugFilter());

      Client client = new Client();
      client.setFilterManager(filterManager);
      client.sendRequest("HOME");
   }
}

Schritt 8

Überprüfen Sie die Ausgabe.

Authenticating request: HOME
request log: HOME
Executing request: HOME

Das Service Locator-Entwurfsmuster wird verwendet, wenn verschiedene Services mithilfe der JNDI-Suche gesucht werden sollen. In Anbetracht der hohen Kosten für die Suche nach JNDI für einen Dienst verwendet das Service Locator-Muster die Caching-Technik. Wenn zum ersten Mal ein Dienst erforderlich ist, sucht Service Locator in JNDI und speichert das Dienstobjekt zwischen. Eine weitere Suche oder derselbe Dienst über Service Locator erfolgt in seinem Cache, wodurch die Leistung der Anwendung erheblich verbessert wird. Im Folgenden sind die Entitäten dieser Art von Entwurfsmuster aufgeführt.

  • Service- Tatsächlicher Service, der die Anfrage bearbeitet. Die Referenz eines solchen Dienstes ist auf dem JNDI-Server zu sehen.

  • Context / Initial Context -JNDI Context enthält den Verweis auf den Dienst, der für Suchzwecke verwendet wird.

  • Service Locator - Service Locator ist eine zentrale Anlaufstelle, um Dienste per JNDI-Suche abzurufen und die Dienste zwischenzuspeichern.

  • Cache - Cache zum Speichern von Referenzen von Diensten, um sie wiederzuverwenden

  • Client - Client ist das Objekt, das die Dienste über ServiceLocator aufruft.

Implementierung

Wir werden einen ServiceLocator , InitialContext , Cache , Service als verschiedene Objekte erstellen , die unsere Entitäten darstellen. Service1 und Service2 stehen für konkrete Services.

ServiceLocatorPatternDemo , unsere Demo-Klasse, fungiert hier als Client und verwendet ServiceLocator , um das Service Locator-Entwurfsmuster zu demonstrieren.

Schritt 1

Serviceschnittstelle erstellen.

Service.java

public interface Service {
   public String getName();
   public void execute();
}

Schritt 2

Erstellen Sie konkrete Dienstleistungen.

Service1.java

public class Service1 implements Service {
   public void execute(){
      System.out.println("Executing Service1");
   }

   @Override
   public String getName() {
      return "Service1";
   }
}

Service2.java

public class Service2 implements Service {
   public void execute(){
      System.out.println("Executing Service2");
   }

   @Override
   public String getName() {
      return "Service2";
   }
}

Schritt 3

Erstellen Sie InitialContext für die JNDI-Suche

InitialContext.java

public class InitialContext {
   public Object lookup(String jndiName){
      if(jndiName.equalsIgnoreCase("SERVICE1")){
         System.out.println("Looking up and creating a new Service1 object");
         return new Service1();
      }else if (jndiName.equalsIgnoreCase("SERVICE2")){
         System.out.println("Looking up and creating a new Service2 object");
         return new Service2();
      }
      return null;		
   }
}

Schritt 4

Cache erstellen

Cache.java

import java.util.ArrayList;
import java.util.List;

public class Cache {

   private List<Service> services;

   public Cache(){
      services = new ArrayList<Service>();
   }

   public Service getService(String serviceName){
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(serviceName)){
            System.out.println("Returning cached  "+serviceName+" object");
            return service;
         }
      }
      return null;
   }

   public void addService(Service newService){
      boolean exists = false;
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(newService.getName())){
            exists = true;
         }
      }
      if(!exists){
         services.add(newService);
      }
   }
}

Schritt 5

Service Locator erstellen

ServiceLocator.java

public class ServiceLocator {
   private static Cache cache;

   static {
      cache = new Cache();		
   }

   public static Service getService(String jndiName){

      Service service = cache.getService(jndiName);

      if(service != null){
         return service;
      }

      InitialContext context = new InitialContext();
      Service service1 = (Service)context.lookup(jndiName);
      cache.addService(service1);
      return service1;
   }
}

Schritt 6

Verwenden Sie den ServiceLocator , um das Entwurfsmuster des Service Locator zu demonstrieren.

ServiceLocatorPatternDemo.java

public class ServiceLocatorPatternDemo {
   public static void main(String[] args) {
      Service service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();
      service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();		
   }
}

Schritt 7

Überprüfen Sie die Ausgabe.

Looking up and creating a new Service1 object
Executing Service1
Looking up and creating a new Service2 object
Executing Service2
Returning cached  Service1 object
Executing Service1
Returning cached  Service2 object
Executing Service2

Das Muster "Objekt übertragen" wird verwendet, wenn Daten mit mehreren Attributen auf einmal vom Client an den Server übergeben werden sollen. Das Übertragungsobjekt wird auch als Wertobjekt bezeichnet. Transfer Object ist eine einfache POJO-Klasse mit Getter / Setter-Methoden und kann serialisiert werden, damit sie über das Netzwerk übertragen werden kann. Es hat kein Verhalten. Die serverseitige Business Class ruft normalerweise Daten aus der Datenbank ab, füllt das POJO und sendet es an den Client oder übergibt es als Wert. Für den Client ist das Übertragungsobjekt schreibgeschützt. Der Client kann ein eigenes Übertragungsobjekt erstellen und an den Server übergeben, um die Werte in der Datenbank auf einmal zu aktualisieren. Im Folgenden sind die Entitäten dieser Art von Entwurfsmuster aufgeführt.

  • Business Object - Business Service, der das Übertragungsobjekt mit Daten füllt.

  • Transfer Object -Einfaches POJO mit Methoden zum Festlegen / Abrufen von Attributen.

  • Client - Der Client fordert das Übertragungsobjekt an oder sendet es an das Geschäftsobjekt.

Implementierung

Wir werden ein StudentBO als Geschäftsobjekt und ein Student als Übertragungsobjekt erstellen , das unsere Entitäten darstellt.

TransferObjectPatternDemo , unsere Demo-Klasse, fungiert hier als Client und verwendet StudentBO und Student , um das Entwurfsmuster für Übertragungsobjekte zu demonstrieren.

Schritt 1

Übertragungsobjekt erstellen.

StudentVO.java

public class StudentVO {
   private String name;
   private int rollNo;

   StudentVO(String name, int rollNo){
      this.name = name;
      this.rollNo = rollNo;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getRollNo() {
      return rollNo;
   }

   public void setRollNo(int rollNo) {
      this.rollNo = rollNo;
   }
}

Schritt 2

Geschäftsobjekt erstellen.

StudentBO.java

import java.util.ArrayList;
import java.util.List;

public class StudentBO {
	
   //list is working as a database
   List<StudentVO> students;

   public StudentBO(){
      students = new ArrayList<StudentVO>();
      StudentVO student1 = new StudentVO("Robert",0);
      StudentVO student2 = new StudentVO("John",1);
      students.add(student1);
      students.add(student2);		
   }
   public void deleteStudent(StudentVO student) {
      students.remove(student.getRollNo());
      System.out.println("Student: Roll No " 
      + student.getRollNo() +", deleted from database");
   }

   //retrive list of students from the database
   public List<StudentVO> getAllStudents() {
      return students;
   }

   public StudentVO getStudent(int rollNo) {
      return students.get(rollNo);
   }

   public void updateStudent(StudentVO student) {
      students.get(student.getRollNo()).setName(student.getName());
      System.out.println("Student: Roll No " 
      + student.getRollNo() +", updated in the database");
   }
}

Schritt 3

Verwenden Sie das StudentBO , um das Entwurfsmuster für Übertragungsobjekte zu demonstrieren.

TransferObjectPatternDemo.java

public class TransferObjectPatternDemo {
   public static void main(String[] args) {
      StudentBO studentBusinessObject = new StudentBO();

      //print all students
      for (StudentVO student : studentBusinessObject.getAllStudents()) {
         System.out.println("Student: [RollNo : "
         +student.getRollNo()+", Name : "+student.getName()+" ]");
      }

      //update student
      StudentVO student =studentBusinessObject.getAllStudents().get(0);
      student.setName("Michael");
      studentBusinessObject.updateStudent(student);

      //get the student
      studentBusinessObject.getStudent(0);
      System.out.println("Student: [RollNo : "
      +student.getRollNo()+", Name : "+student.getName()+" ]");
   }
}

Schritt 4

Überprüfen Sie die Ausgabe.

Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]