How to Change Level Designs Using Java

Practical use of Design Patterns in Java

ArtWithCode

If you are a newbie programmer or a senior programmer , you have probably heard or used design patterns in your programming career.

This blog post is dedicated to helping you understand and learn about the most used design patterns and how to apply them in practice.

To take your programming skills to the next level , knowing even a little bit of design pattern theory is beneficial in the long run for your career.

Design patterns are used with object-oriented programming paradigms which helps programmers to solve common object-oriented programming problems. When you use design patterns in your own software projects it ensures that your code is robust and bug-free .

All the code would be done using Java and the code is super simple to read and understand.

Different Types of Design Patterns

Design patterns fall into 3 main categories.

Creational Patterns

Creational Patterns are patterns that design the process of creating different objects. They try to create objects in a manner that is beneficial and efficient for a given situation.

Structural Patterns

Structural Patterns are patterns that provide ways to create different relationships between classes and objects.

Behavioral Patterns

Behavioral Patterns identify common communication problems between different classes and try to come up with several solutions in order to fix such problems and solve them efficiently.

Factory Design Pattern

A factory design pattern is a creational pattern used to solve the problem of creating objects without having to specify the exact class of the object that would be created.

For example, let's say that you are creating a weapon class and the user doesn't know the specificity when it comes to creating different weapons. The user specifies the name of the weapon and a factory class creates the specified weapon.

Therefore the user would make a call such as this in the main class

                      public class DemoFactoryPattern {
public static void main(String[] args) {
//Create a weapon gun using the weapon factory
Weapon weapon = new WeaponFactory().createWeapon("Gun");

//Use the weapon
weapon.use();
}
}

OUTPUT: Shooting using the gun.

The WeaponFactory class is responsible for the creation of different weapons and passing it to the user for use.

Each individual weapon implements an interface called Weapon

                      interface Weapon {
void use();
}

The use() function in the interface should be overridden by the Gun and the Crossbow class when they implement the Weapon interface.

The Gun class

                      public class Gun implements Weapon {                                              @Override
public void use() {
System.out.println("Shooting using the gun.");
}

}

The Crossbow class

                      public class Crossbow implements Weapon {                                              @Override
public void use() {
System.out.println("Firing arrows using the crossbow.");
}

}

Since the method is overridden the classes provide their own implementation of the use() method.

The WeaponFactory class is regarded as the middleman in creating and instantiating objects specified by the user. Therefore it is implemented as follows,

                      public class WeaponFactory{
Weapon createWeapon(String weaponCode){
if (weaponCode.equals("Gun")) {
return new Gun();
} else if (weaponCode.equals("Crossbow")) {
return new Crossbow();
}else {
return null;
}
}
}

Using conditional statements the specific type of weapon is provided to the user by the createWeapon function.

If the user specifies a "Gun" as the parameter to the method, the user receives a Gun weapon, likewise, if the user specifies a "Crossbow" as the parameter, the user receives a Crossbow weapon.

Adapter Design Pattern

An adapter pattern is a structural design pattern, which allows existing classes to work with other classes without modifying their source code.

Think of the latest iPhone. The phone doesn't have an earplug socket. Therefore to connect earphones into the device we need an adapter that can connect to both the Lightning jack and the 3.5mm earphone jack. Like so,

Adapter Diagram (Overview)

The phone socket (Socket.java) is an interface which allows devices to be connected to the phone using the connect method.

                      interface Socket {
public void connect();
}

The Charging Cable is a device that can connect directly into the socket since it implements the Socket interface and overrides the connect method.

                      public class ChargingCable implements Socket{              
public void connect(){
System.out.println("Charging device...");
}
}

The EarPlug Adapter class allows Earplugs to be connected to the adapter, and the Earplug adapter can connect to the device directly because it also implements the Socket interface.

                      public class EarplugAdapter implements Socket{
private Earplug earPlug;

public EarplugAdapter(Earplug e) {
this.Earplug = e;
}

@Override
public void connect() {
this.earPlug.plugIn();
}
}

The Adapter holds an instance variable of the Earplug and then in the connect method, it invokes the Earplug's own connect method.

                      public class Earplug {              
public void plugIn(){
System.out.println("Earplugs connected to device");
}
}

Therefore we can use the above adapter class in the main class like so,

                      Socket connector = new ChargingCable();              
connector.connect();
connector = new HeadphoneAdapter(new Headphone());
connector.connect();
OUTPUT:
Charging phone...
Earplugs connected to device

State Pattern

This is a design pattern that allows the object to change its functionality as the state of the object changes.

For example, let's say that you need to create Pokemon class and the stats of the Pokemon must change as the Pokemon level ups. We can implement such behavior using a state pattern.

The Level is an abstract class which defines a constructor to be overridden and it defines instance variables to hold the attack and defense points.

                      public abstract class Level {                                protected int attackPts;
protected int defensePts;
public Level(){
this.attackPts = 0;
this.defensePts = 0;
}
public int getAttack () {return this.attackPts; }
public int getDefense() {return this.defensePts; }
}

Using this abstract class we can create subclasses to inherit functionality like so,

Level One class

                      public class Level1 extends Level{
public Level1(){
this.attackPts = 15;
this.defensePts = 15;
}
}

Level Two class

                      public class Level2 extends Level{

public Level2(){
this.attackPts = 20;
this.defensePts = 20;
}

}

The Pokemon class holds all three subclasses as instance variables and the user is allowed to change the current Level of the pokemon using the changeLevel function. An instance variable called 'currentLevel' stores the current Level or state of the Pokemon. The 'printStat' function prints the attack and defense points of the Pokemon.

                      public class Pokemon {
private Level level1, level2, level3, currentLevel;

public Pokemon(){
level1 = new Level1();
level2 = new Level2();
level3 = new Level3();
currentLevel = level1;
}

public void changeLevel(Level lvl) {
this.currentLevel = lvl;
}

public void printStats() {
System.out.println("Attack : " + currentLevel.getAttack() + "\tDefense: "


+ currentLevel.getDefense());
}

public Level getLevel1() { return this.level1; }
public Level getLevel2() { return this.level2; }
public Level getLevel3() { return this.level3; }

}

Using the Demo class we can see the State pattern in action,

                      public class Demo {
public static void main(String[] args) {
Pokemon pokemon = new Pokemon();

//Level 1 Stats (Default level)
pokemon.printStats();

//Changing to level 2
pokemon.changeLevel(pokemon.getLevel2());

//Level 2 Stats
pokemon.printStats();

//Changing to level 3
pokemon.changeLevel(pokemon.getLevel3());

//Level 3 Stats
pokemon.printStats();
}
}

OUTPUT:
Attack : 15 Defense: 15
Attack : 20 Defense: 20
Attack : 25 Defense: 25

I hoped you enjoyed the article and keep coding!

Originally published at artwithcode.com on September 6, 2018.

Practical use of Design Patterns in Java

If you are a newbie programmer or a senior programmer , you have probably heard or used design patterns in your programming career.

This blog post is dedicated to helping you understand and learn about the most used design patterns and how to apply them in practice.

To take your programming skills to the next level , knowing even a little bit of design pattern theory is beneficial in the long run for your career.

Design patterns are used with object-oriented programming paradigms which helps programmers to solve common object-oriented programming problems. When you use design patterns in your own software projects it ensures that your code is robust and bug-free .

All the code would be done using Java and the code is super simple to read and understand.

Different Types of Design Patterns

Design patterns fall into 3 main categories.

Creational Patterns

Creational Patterns are patterns that design the process of creating different objects. They try to create objects in a manner that is beneficial and efficient for a given situation.

Structural Patterns

Structural Patterns are patterns that provide ways to create different relationships between classes and objects.

Behavioral Patterns

Behavioral Patterns identify common communication problems between different classes and try to come up with several solutions in order to fix such problems and solve them efficiently.

Factory Design Pattern

A factory design pattern is a creational pattern used to solve the problem of creating objects without having to specify the exact class of the object that would be created.

For example, let's say that you are creating a weapon class and the user doesn't know the specificity when it comes to creating different weapons. The user specifies the name of the weapon and a factory class creates the specified weapon.

Therefore the user would make a call such as this in the main class

                      public class DemoFactoryPattern {
public static void main(String[] args) {
//Create a weapon gun using the weapon factory
Weapon weapon = new WeaponFactory().createWeapon("Gun");

//Use the weapon
weapon.use();
}
}

OUTPUT: Shooting using the gun.

The WeaponFactory class is responsible for the creation of different weapons and passing it to the user for use.

Each individual weapon implements an interface called Weapon

                      interface Weapon {
void use();
}

The use() function in the interface should be overridden by the Gun and the Crossbow class when they implement the Weapon interface.

The Gun class

                      public class Gun implements Weapon {

@Override
public void use() {
System.out.println("Shooting using the gun.");
}

}

The Crossbow class

                      public class Crossbow implements Weapon {

@Override
public void use() {
System.out.println("Firing arrows using the crossbow.");
}

}

Since the method is overridden the classes provide their own implementation of the use() method.

The WeaponFactory class is regarded as the middleman in creating and instantiating objects specified by the user. Therefore it is implemented as follows,

                      public class WeaponFactory{
Weapon createWeapon(String weaponCode){
if (weaponCode.equals("Gun")) {
return new Gun();
} else if (weaponCode.equals("Crossbow")) {
return new Crossbow();
}else {
return null;
}
}
}

Using conditional statements the specific type of weapon is provided to the user by the createWeapon function.

If the user specifies a "Gun" as the parameter to the method, the user receives a Gun weapon, likewise, if the user specifies a "Crossbow" as the parameter, the user receives a Crossbow weapon.

Adapter Design Pattern

An adapter pattern is a structural design pattern, which allows existing classes to work with other classes without modifying their source code.

Think of the latest iPhone. The phone doesn't have an earplug socket. Therefore to connect earphones into the device we need an adapter that can connect to both the Lightning jack and the 3.5mm earphone jack. Like so,

Adapter Diagram (Overview)

The phone socket (Socket.java) is an interface which allows devices to be connected to the phone using the connect method.

                      interface Socket {
public void connect();
}

The Charging Cable is a device that can connect directly into the socket since it implements the Socket interface and overrides the connect method.

                      public class ChargingCable implements Socket{              
public void connect(){
System.out.println("Charging device...");
}
}

The EarPlug Adapter class allows Earplugs to be connected to the adapter, and the Earplug adapter can connect to the device directly because it also implements the Socket interface.

                      public class EarplugAdapter implements Socket{
private Earplug earPlug;

public EarplugAdapter(Earplug e) {
this.Earplug = e;
}

@Override
public void connect() {
this.earPlug.plugIn();
}
}

The Adapter holds an instance variable of the Earplug and then in the connect method, it invokes the Earplug's own connect method.

                      public class Earplug {              
public void plugIn(){
System.out.println("Earplugs connected to device");
}
}

Therefore we can use the above adapter class in the main class like so,

                      Socket connector = new ChargingCable();              
connector.connect();
connector = new HeadphoneAdapter(new Headphone());
connector.connect();
OUTPUT:
Charging phone...
Earplugs connected to device

State Pattern

This is a design pattern that allows the object to change its functionality as the state of the object changes.

For example, let's say that you need to create Pokemon class and the stats of the Pokemon must change as the Pokemon level ups. We can implement such behavior using a state pattern.

The Level is an abstract class which defines a constructor to be overridden and it defines instance variables to hold the attack and defense points.

                      public abstract class Level {                                              protected int attackPts;
protected int defensePts;
public Level(){
this.attackPts = 0;
this.defensePts = 0;
}
public int getAttack () {return this.attackPts; }
public int getDefense() {return this.defensePts; }
}

Using this abstract class we can create subclasses to inherit functionality like so,

Level One class

                      public class Level1 extends Level{
public Level1(){
this.attackPts = 15;
this.defensePts = 15;
}
}

Level Two class

                      public class Level2 extends Level{

public Level2(){
this.attackPts = 20;
this.defensePts = 20;
}

}

The Pokemon class holds all three subclasses as instance variables and the user is allowed to change the current Level of the pokemon using the changeLevel function. An instance variable called 'currentLevel' stores the current Level or state of the Pokemon. The 'printStat' function prints the attack and defense points of the Pokemon.

                      public class Pokemon {
private Level level1, level2, level3, currentLevel;

public Pokemon(){
level1 = new Level1();
level2 = new Level2();
level3 = new Level3();
currentLevel = level1;
}

public void changeLevel(Level lvl) {
this.currentLevel = lvl;
}

public void printStats() {
System.out.println("Attack : " + currentLevel.getAttack() + "\tDefense: "


+ currentLevel.getDefense());
}

public Level getLevel1() { return this.level1; }
public Level getLevel2() { return this.level2; }
public Level getLevel3() { return this.level3; }

}

Using the Demo class we can see the State pattern in action,

                      public class Demo {
public static void main(String[] args) {
Pokemon pokemon = new Pokemon();

//Level 1 Stats (Default level)
pokemon.printStats();

//Changing to level 2
pokemon.changeLevel(pokemon.getLevel2());

//Level 2 Stats
pokemon.printStats();

//Changing to level 3
pokemon.changeLevel(pokemon.getLevel3());

//Level 3 Stats
pokemon.printStats();
}
}

OUTPUT:
Attack : 15 Defense: 15
Attack : 20 Defense: 20
Attack : 25 Defense: 25

I hoped you enjoyed the article and keep coding!

How to Change Level Designs Using Java

Source: https://medium.datadriveninvestor.com/practical-use-of-design-patterns-in-java-1c73f7cbd6ca

0 Response to "How to Change Level Designs Using Java"

Enregistrer un commentaire

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel