作业要求
寻找一个合理的场景适合实现简单工厂模式扩展。
1、画出该场景的UML图。
2、给出源代码。
3、给出源代码的运行结果。
解
简单工厂模式
在简单工厂模式中,工厂类根据工厂方法所传入的参数来动态决定应该创建出哪一个产品类的实例。
简单工厂模式的一种扩展
在有些情况下工厂类可以由抽象产品角色扮演,一个抽象产品类同时也是子类的工厂,也就是说把静态工厂方法写到抽象产品类中。
场景
超能力者量产计划!
工厂负责大规模生产指定的超能力者的克隆体,终极目标是能够批量复制学园都市(Academy City)的 7 位超能力者(Level 5)。
目前还无法复制出能力等级达到 5 的克隆体。复制人的能力等级一般远远不及其本体(original),通常只能达到 Level 2。
UML图
如图,可见:抽象类 EsperClone 和由它派生出来的 7 个子类(对应 7 个超能力者的克隆体)构成简单工厂模式的扩展。EsperClone 作为抽象产品类的同时,也是子类的工厂。
源代码
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Bank.prepareToRetrieve();
Scanner scanner = new Scanner(System.in, "utf-8");
while (scanner.hasNextLine()) {
EsperClone.produceEsper(scanner.nextLine());
}
scanner.close();
}
}
abstract class EsperClone {
private static final Random random = new Random(Instant.now().getEpochSecond());
private static final double[] CDF = {
0, 0.0001, 0.001, 0.99, 0.999, 1 };
public static final int MAX_LEVEL = 5;
private int level;
public EsperClone() {
// The level of esp.
double r = random.nextDouble();
for (int i = 1; i <= MAX_LEVEL; ++i) {
if (CDF[i] > r) {
level = i - 1;
return;
}
}
level = 5;
}
public static void produceEsper(final String param) {
int r = Bank.getRank(param);
EsperClone clone = null;
switch (r) {
case 0:
return;
case 1:
clone = new AcceleratorClone();
break;
case 2:
clone = new KakineTeitokuClone();
break;
case 3:
clone = new MisakaMikotoClone();
break;
case 4:
clone = new MuginoShizuriClone();
break;
case 5:
clone = new ShokuhouMisakiClone();
break;
case 6:
System.out.println("ERROR: The factory can't duplicate " + param + " due to the absence of his/her bioinformation.");
return;
case 7:
clone = new SogiitaGunhaClone();
break;
}
System.out.println("Canonical original name: " + clone.getCanonicalOriginalName());
System.out.println("LEVEL " + clone.getLevel());
}
public abstract String getCanonicalOriginalName();
public int getLevel() {
return level;
}
}
// The Bank (書庫 Shoko (Banku), lit. "Archive", Yen Press: Data Banks) is a comprehensive database in Academy City which is said to hold all of Academy City's data.
class Bank {
// 7 LEVEL-5 in Academy City.
private static final String[][] synonym = {
{
"一方通行", "一方 通行", "Accelerator", "Ippou Tsuukou", "Tsuukou Ippou" },
{
"垣根帝督", "垣根 帝督", "Kakine Teitoku", "Teitoku Kakine" },
{
"御坂美琴", "御坂 美琴", "Misaka Mikoto", "Mikoto Misaka" },
{
"麦野沉利", "麦野 沈利", "Mugino Shizuri", "Shizuri Mugino" },
{
"食蜂操祈", "食蜂 操祈", "Shokuhou Misaki", "Misaki Shokuhou" },
{
"蓝花悦", "藍花 悦", "Aihana Etsu", "Etsu Aihana" },
{
"削板军霸", "削板 軍覇", "Sogiita Gunha", "Gunha Sogiita" }
};
public static final int NUMBER_OF_LEVEL_5 = 7;
private static final HashMap<String, Integer> rank = new HashMap<>();
public static void prepareToRetrieve() {
for (int i = 1; i <= NUMBER_OF_LEVEL_5; ++i)
for (int j = 0; j < synonym[i - 1].length; ++j)
rank.put(synonym[i - 1][j], i);
}
public static int getRank(final String alias) {
Integer r = rank.get(alias);
if (r == null) {
String[] tempWords = alias.split("(\\s+)");
ArrayList<String> words = new ArrayList<>();
for (String word: tempWords) {
if (word.isBlank() == false) words.add(word);
}
String s = "";
try {
s = words.get(0).substring(0, 1).toUpperCase() + words.get(0).substring(1).toLowerCase();
for (int i = 1; i < words.size(); ++i) {
s += ' ' + words.get(i).substring(0, 1).toUpperCase() + words.get(i).substring(1).toLowerCase();
}
r = rank.get(s);
if (r == null) {
System.out.println("ERROR: The information of " + s + " doesn't exist in the archive.");
return 0;
}
}
catch (Exception e) {
System.out.println("EXCEPTION: The information of " + s + " doesn't exist in the archive.");
return 0;
}
}
return r;
}
}
class AcceleratorClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Accelerator";
}
}
class KakineTeitokuClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Kakine Teitoku";
}
}
class MisakaMikotoClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Misaka Mikoto";
}
}
class MuginoShizuriClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Mugino Shizuri";
}
}
class ShokuhouMisakiClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Shokuhou Misaki";
}
}
class AihanaEtsuClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Aihana Etsu";
}
}
class SogiitaGunhaClone extends EsperClone {
public String getCanonicalOriginalName() {
return "Sogiita Gunha";
}
}
运行结果
"D:\Program Files\Java\jdk\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA Community\lib\idea_rt.jar=5507:D:\Program Files\JetBrains\IntelliJ IDEA Community\bin" -Dfile.encoding=UTF-8 -classpath D:\Userdata\repos\JavaDemo\out\production\JavaDemo Main
一方通行
Canonical original name: Accelerator
LEVEL 2
teitoku kakine
Canonical original name: Kakine Teitoku
LEVEL 2
MISAKA MIKOTO
Canonical original name: Misaka Mikoto
LEVEL 2
麦野 沈利
Canonical original name: Mugino Shizuri
LEVEL 2
shokuhou misaki
Canonical original name: Shokuhou Misaki
LEVEL 2
藍花 悦
ERROR: The factory can't duplicate 藍花 悦 due to the absence of his/her bioinformation.
Sogiita Gunha
Canonical original name: Sogiita Gunha
LEVEL 2
Shirai Kuroko
ERROR: The information of Shirai Kuroko doesn't exist in the archive.
参考
https://toarumajutsunoindex.fandom.com/wiki/Toaru_Majutsu_no_Index_Wiki