Observer Pattern in Java

Observer Pattern in Java Homework Sample

The observer pattern is used to respond to events, you need to extend the code provided to add in observers that play the car number plate game. Say you want to find the word CAT, you look for number plates with the letters A, C, T on them, and once you have all 3 letters you complete the challenge. The simulation provided drives a car around a city, and there are other moving vehicles, you need to find the requested word by looking at the plates that are close to you. You need to implement the code from scratch without using Java.util.Observer and Java.util.Observable. For more Java programming assignments contact us for a quote.

Solution:

Observer.java

package lab5tourists.observer;

import lab5tourists.event.TagEvent;

// Observer generic interface with event parameter
public interface Observer<T extends TagEvent> {
// instance of observer can be updated with appropriate type of event
void update(T tagEvent);
}

Challenge.java

package lab5tourists.observer;

import javafx.scene.text.TextFlow;
import lab5tourists.event.TagEvent;

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

// Abstract generic class for representing challenges. This class also implements Observer interface.
// So, it can be update when observable objects notify it
public abstract class Challenge<T extends TagEvent> implements Observer<T> {
// Shows, if this challenge is completed or not
private boolean completed;

// Element of java FX interface, which is updated with this challeng
private TextFlow textFlow;

// In general case: one challenge can lock others:
// For example in this game, bus challenge (to tag the bus) locks BUS letters challenge (Before open one challenge you must complete another)
private List<Challenge<? extends TagEvent>> lock;

// Number of challengers, from which current one depends on (are locked by).
// In this game, BUS letters challenge dependsOn 1 challenge (Bus tag challenge)
private int dependsOn;

// Constructors, instantiating challenge from different set of params

public Challenge(TextFlow textFlow, List<Challenge<? extends TagEvent>> lock, int dependsOn) {
this.textFlow = textFlow;
this.lock = lock;
this.dependsOn = dependsOn;
}

public Challenge(TextFlow textFlow, List<Challenge<? extends TagEvent>> lock) {
this(textFlow, lock, 0);
}

public Challenge(TextFlow textFlow, int dependsOn) {
this(textFlow, new ArrayList<>(), dependsOn);
}

public Challenge(List<Challenge<? extends TagEvent>> lock) {
this(null, lock, 0);
}

// Base method for challenge update. It is finally called from children class, after overriding method
@Override
public void update(T tagEvent) {
updateView(textFlow);
}

// Initializing method for creating appropriate textFlow object
protected void init() {
updateView(textFlow);
}

// Method for updating java fx interface. it is overriden by child classes
protected void updateView(TextFlow textFlow) {}

// Method for checking is this challenge is still locked or not
protected boolean checkDependencies() {
return dependsOn == 0;
}

// When one challenge is completed, it calls unlockDependency method for all challenges, that it locks
protected void unlockDependency() {
dependsOn–;
if (dependsOn == 0) {
init();
}
}

// Getter for completed field
public boolean isCompleted() {
return completed;
}

// Method for setting challenge as completed
public void setCompleted() {
this.completed = true;
for (Challenge<? extends TagEvent> challenge : lock) {
challenge.unlockDependency();
}
}

public TextFlow getTextFlow() {
return textFlow;
}
}

PlateChallenge.java

package lab5tourists.observer;

import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import lab5tourists.event.PlateEvent;
import lab5tourists.event.TagEvent;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class PlateChallenge extends Challenge<PlateEvent> {
// Word for this Plate challenge
private String word;

// Set of letters previously seen by player
private Set<Character> lettersSeen;

// Current mask (representation of state with ‘*’ symkbols)
private String mask;

public PlateChallenge(TextFlow textFlow, int dependsOn, String word) {
super(textFlow, dependsOn);
this.word = word;
this.lettersSeen = new HashSet<>();
this.mask = getMask();

init();
}

public PlateChallenge(TextFlow textFlow, String word) {
this(textFlow, 0, word);
this.word = word;
this.lettersSeen = new HashSet<>();
this.mask = getMask();

init();
}

// Updating challenge
@Override
public void update(PlateEvent event) {
if (isCompleted()) {
return;
}

// Adding new letters to seen set
String plate = event.getPlateSeen();
for (char c : plate.toCharArray()) {
lettersSeen.add(c);
}

// Generating new mask
mask = getMask();
super.update(event);
}

// Formatting text flow for Java FX GUI
@Override
public void updateView(TextFlow textFlow) {
textFlow.getChildren().clear();

if (!checkDependencies()) {
return;
}

Text line1 = new Text(“Challenge: Find all the letters in ” + word + “\n”);
Text line2 = new Text(“Goal: ” + word + “\n”);
Text line3 = new Text(“Found: ” + mask + “\n”);
textFlow.getChildren().addAll(line1, line2, line3);
if (isCompleted()) {
Text line4 = new Text(“CHALLENGE COMPLETED\n”);
textFlow.getChildren().add(line4);
}
Text breakline = new Text(“\n\n\n”);
textFlow.getChildren().add(breakline);

}

// Creating mask, depending on letters, previously seen
private String getMask() {
StringBuilder builder = new StringBuilder();
boolean isFound = true;
for (char c : word.toCharArray()) {
if (lettersSeen.contains(c)) {
builder.append(c);
}
else {
isFound = false;
builder.append(“*”);
}
}
if (isFound) {
setCompleted();
}
return builder.toString();
}
}

ArtChallenge.java

package lab5tourists.observer;

import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import lab5tourists.CityMap;
import lab5tourists.event.ArtEvent;
import lab5tourists.event.TagEvent;

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

public class ArtChallenge extends Challenge<ArtEvent>{
private static final Image artImage;
static {
artImage = new Image(CityMap.class.getResource(“img/wood-gatherer.png”).toString());
}

public ArtChallenge(TextFlow textFlow, List<Challenge<? extends TagEvent>> dependsOn) {
super(textFlow, dependsOn);
init();
}

public ArtChallenge(TextFlow textFlow) {
this(textFlow, new ArrayList<>());
}

// Any update completes this challenge
@Override
public void update(ArtEvent event) {
if (isCompleted()) {
return;
}

setCompleted();
super.update(event);
}

// Formatting text flow for GUI
@Override
public void updateView(TextFlow textFlow) {
textFlow.getChildren().clear();

Text line1 = new Text(“Challenge: Find art\n”);
textFlow.getChildren().add(line1);
if (isCompleted()) {
Text line2 = new Text(“Artistic works found\n”);
ImageView imageView = new ImageView(artImage);
imageView.setPreserveRatio(true);
imageView.setFitHeight(70);
textFlow.getChildren().addAll(line2, imageView);
}
Text breakline = new Text(“\n\n\n”);
textFlow.getChildren().add(breakline);

}
}

BusChallenge.java

package lab5tourists.observer;

import lab5tourists.event.TagEvent;
import lab5tourists.mobileEntities.Bus;

import java.util.List;

public class BusChallenge extends Challenge<TagEvent> {
public BusChallenge(List<Challenge<? extends TagEvent>> lock) {
super(lock);
}

// Any update completes concerning bus complete this challenge
@Override
public void update(TagEvent tagEvent) {
if (isCompleted()) {
return;
}

if (!checkDependencies()) {
return;
}

if (tagEvent.getTaggable() instanceof Bus) {
setCompleted();
}
}
}