diff --git a/pom.xml b/pom.xml index e7849da..5c2a7e1 100644 --- a/pom.xml +++ b/pom.xml @@ -14,4 +14,18 @@ UTF-8 + + + org.projectlombok + lombok + 1.18.36 + provided + + + org.springframework.boot + spring-boot-starter-web + 3.4.5 + + + \ No newline at end of file diff --git a/src/main/java/strategy/App.java b/src/main/java/strategy/App.java new file mode 100644 index 0000000..7bee699 --- /dev/null +++ b/src/main/java/strategy/App.java @@ -0,0 +1,11 @@ +package strategy; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class App { + public static void main(String[] args) { + SpringApplication.run(App.class); + } +} diff --git a/src/main/java/strategy/annotation/SupportAttackType.java b/src/main/java/strategy/annotation/SupportAttackType.java new file mode 100644 index 0000000..eb358be --- /dev/null +++ b/src/main/java/strategy/annotation/SupportAttackType.java @@ -0,0 +1,14 @@ +package strategy.annotation; + +import strategy.enums.AttackType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface SupportAttackType { + AttackType value(); +} diff --git a/src/main/java/strategy/constant/AttackTypeValue.java b/src/main/java/strategy/constant/AttackTypeValue.java new file mode 100644 index 0000000..4d75e84 --- /dev/null +++ b/src/main/java/strategy/constant/AttackTypeValue.java @@ -0,0 +1,7 @@ +package strategy.constant; + +public class AttackTypeValue { + public static final int PHYSIC_ATTACK_VALUE = 1; + public static final int MAGIC_ATTACK_VALUE = 2; + public static final int POISON_ATTACK_VALUE = 3; +} diff --git a/src/main/java/strategy/controller/AttackController.java b/src/main/java/strategy/controller/AttackController.java new file mode 100644 index 0000000..973daa0 --- /dev/null +++ b/src/main/java/strategy/controller/AttackController.java @@ -0,0 +1,55 @@ +package strategy.controller; + +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import strategy.annotation.SupportAttackType; +import strategy.enums.AttackType; +import strategy.service.AttackService; +import strategy.service.DefaultAttack; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@RestController +public class AttackController { + private Map attackServiceMap; + + @Autowired + private DefaultAttack defaultAttackService; + +// @Autowired +// private List attackServices; + + @GetMapping("/attack/{type}") + public String attack(@PathVariable(value = "type") int type) { + AttackType attackType = AttackType.typeOf(type); + AttackService attackService = attackServiceMap.getOrDefault(attackType, defaultAttackService); + return attackService.attack(); + } + + @Autowired + private void setAttackServiceMap(List attackServiceList) { + this.attackServiceMap = attackServiceList.stream() + .filter(attackService -> attackService.getClass().isAnnotationPresent(SupportAttackType.class)) + .collect(Collectors.toMap(AttackService::getAttackTypeByService, Function.identity())); + if (this.attackServiceMap.size() != AttackType.values().length) { + throw new IllegalArgumentException("some attack types are not supported"); + } + } + + //The following code completes the same task as setAttackServiceMap(List) + /*@PostConstruct + private void initAttackServiceMap() { + this.attackServiceMap = attackServices.stream() + .filter(attackService -> attackService.getClass().isAnnotationPresent(SupportAttackType.class)) + .collect(Collectors.toMap(AttackService::getAttackTypeByService, Function.identity())); + if (this.attackServiceMap.size() != AttackType.values().length) { + throw new IllegalArgumentException("some attack types are not supported"); + } + }*/ +} diff --git a/src/main/java/strategy/enums/AttackType.java b/src/main/java/strategy/enums/AttackType.java new file mode 100644 index 0000000..5726dfd --- /dev/null +++ b/src/main/java/strategy/enums/AttackType.java @@ -0,0 +1,26 @@ +package strategy.enums; + +import java.util.Arrays; +import java.util.function.IntPredicate; + +import static strategy.constant.AttackTypeValue.*; + +public enum AttackType { + PhysicalAttack(attackType -> attackType == PHYSIC_ATTACK_VALUE), + MagicAttack(attackType -> attackType == MAGIC_ATTACK_VALUE), + PoisonAttack(attackType -> attackType == POISON_ATTACK_VALUE), + ; + + private final IntPredicate route; + + AttackType(IntPredicate route) { + this.route = route; + } + + public static AttackType typeOf(int attackType) { + return Arrays.stream(values()) + .filter(value -> value.route.test(attackType)) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/strategy/service/AttackService.java b/src/main/java/strategy/service/AttackService.java new file mode 100644 index 0000000..59ddc35 --- /dev/null +++ b/src/main/java/strategy/service/AttackService.java @@ -0,0 +1,17 @@ +package strategy.service; + +import strategy.annotation.SupportAttackType; +import strategy.enums.AttackType; + +public interface AttackService { + + String attack(); + + default AttackType getAttackTypeByService() { + SupportAttackType annotation = this.getClass().getAnnotation(SupportAttackType.class); + if (annotation != null) { + return annotation.value(); + } + throw new IllegalStateException("AttackService implementation must be annotated with @SupportAttackType"); + } +} diff --git a/src/main/java/strategy/service/DefaultAttack.java b/src/main/java/strategy/service/DefaultAttack.java new file mode 100644 index 0000000..8c9c224 --- /dev/null +++ b/src/main/java/strategy/service/DefaultAttack.java @@ -0,0 +1,11 @@ +package strategy.service; + +import org.springframework.stereotype.Service; + +@Service +public class DefaultAttack implements AttackService { + @Override + public String attack() { + return "No Attack"; + } +} diff --git a/src/main/java/strategy/service/MagicAttack.java b/src/main/java/strategy/service/MagicAttack.java new file mode 100644 index 0000000..2300395 --- /dev/null +++ b/src/main/java/strategy/service/MagicAttack.java @@ -0,0 +1,15 @@ +package strategy.service; + +import org.springframework.stereotype.Service; +import strategy.annotation.SupportAttackType; +import strategy.enums.AttackType; + +@Service +@SupportAttackType(AttackType.MagicAttack) +public class MagicAttack implements AttackService { + @Override + public String attack() { + System.out.println("Magic Attack"); + return "Magic Attack"; + } +} diff --git a/src/main/java/strategy/service/PhysicalAttack.java b/src/main/java/strategy/service/PhysicalAttack.java new file mode 100644 index 0000000..3356a6d --- /dev/null +++ b/src/main/java/strategy/service/PhysicalAttack.java @@ -0,0 +1,15 @@ +package strategy.service; + +import org.springframework.stereotype.Service; +import strategy.annotation.SupportAttackType; +import strategy.enums.AttackType; + +@Service +@SupportAttackType(AttackType.PhysicalAttack) +public class PhysicalAttack implements AttackService { + @Override + public String attack() { + System.out.println("Physical Attack"); + return "Physical Attack"; + } +} diff --git a/src/main/java/strategy/service/PoisonAttack.java b/src/main/java/strategy/service/PoisonAttack.java new file mode 100644 index 0000000..4a55d3e --- /dev/null +++ b/src/main/java/strategy/service/PoisonAttack.java @@ -0,0 +1,15 @@ +package strategy.service; + +import org.springframework.stereotype.Service; +import strategy.annotation.SupportAttackType; +import strategy.enums.AttackType; + +@Service +@SupportAttackType(value = AttackType.PoisonAttack) +public class PoisonAttack implements AttackService { + @Override + public String attack() { + System.out.println("Poison Attack"); + return "Poison Attack"; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..c57fe8b --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=JavaDesignPatterns \ No newline at end of file