├── .gitignore ├── .idea ├── .gitignore ├── checkstyle-idea.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── wsa-design-pattern.iml ├── README.md ├── c1-物件導向之不新手的新手村 └── OOP-技法 │ ├── Main.java │ ├── abstractclass │ ├── AI.java │ ├── Decision.java │ ├── Game.java │ ├── Human.java │ ├── OOAD.png │ ├── Player.java │ └── Test.java │ ├── hero │ ├── Fruit.java │ ├── Guild.java │ ├── Hero.java │ ├── LevelSheet.java │ ├── Pet.java │ ├── Test.java │ ├── Test2.java │ ├── Test3.java │ ├── case1.png │ ├── case2.png │ └── case3.png │ ├── lecture │ ├── Lecture.java │ ├── LectureAttendance.java │ ├── Student.java │ ├── Test4.java │ └── case4.png │ └── utils │ └── ValidationUtils.java ├── c2-Christopher-Alexander-設計模式 ├── 景點-樣板方法 │ ├── .gitignore │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── compiler.xml │ │ ├── jarRepositories.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── vcs.xml │ ├── astah.asta │ ├── c2m2s1-樣板方法.iml │ ├── common │ │ ├── Group.java │ │ ├── GroupingStrategy.java │ │ ├── ReadStudents.java │ │ ├── Student.java │ │ ├── StudentGenerations.java │ │ └── Utils.java │ ├── pom.xml │ ├── student.data │ ├── v0 │ │ ├── LanguageBasedGroupingStrategy.java │ │ └── Main.java │ ├── v1 │ │ ├── LanguageBasedGroupingStrategy.java │ │ ├── Main.java │ │ └── TimeSlotsBasedGroupingStrategy.java │ ├── v2 │ │ ├── CutBasedGroupingStrategy.java │ │ ├── JobTitleBasedGroupingStrategy.java │ │ ├── LanguageBasedGroupingStrategy.java │ │ ├── Main.java │ │ └── TimeSlotsBasedGroupingStrategy.java │ └── v3 │ │ ├── CutBasedGroupingStrategy.java │ │ ├── JobTitleBasedGroupingStrategy.java │ │ ├── LanguageBasedGroupingStrategy.java │ │ ├── Main.java │ │ └── TimeSlotsBasedGroupingStrategy.java ├── 景點-策略模式 │ ├── .gitignore │ ├── astah.asta │ ├── commons │ │ └── Utils.java │ ├── v1 │ │ ├── Game.java │ │ ├── Hero.java │ │ └── Main.java │ └── v2 │ │ ├── AttackType.java │ │ ├── Earth.java │ │ ├── Fireball.java │ │ ├── Game.java │ │ ├── Hero.java │ │ ├── Main.java │ │ ├── Powerball.java │ │ └── Waterball.java └── 景點-責任鏈模式 │ ├── .gitignore │ ├── .idea │ ├── .gitignore │ ├── .name │ ├── checkstyle-idea.xml │ ├── compiler.xml │ ├── jarRepositories.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml │ ├── C2M3S1.asta │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── tw │ │ └── waterballsa │ │ └── degisnpattern │ │ └── c2m3s1 │ │ ├── v1 │ │ ├── Main.java │ │ └── WaterballBot.java │ │ ├── v2 │ │ ├── CurrencyHandler.java │ │ ├── DcardHandler.java │ │ ├── HelpHandler.java │ │ ├── Main.java │ │ ├── MessageHandler.java │ │ └── WaterballBot.java │ │ └── v3 │ │ ├── CurrencyHandler.java │ │ ├── DcardHandler.java │ │ ├── HelpMessageHandler.java │ │ ├── Main.java │ │ ├── MessageHandler.java │ │ └── WaterballBot.java │ └── resources │ ├── .gitignore │ └── token.example.properties ├── c3-掌握所有複雜行為變動 ├── 景點-指令模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── inspectionProfiles │ │ │ └── Project_Default.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── uiDesigner.xml │ │ └── vcs.xml │ ├── commons │ │ ├── AirConditioner.java │ │ ├── Fan.java │ │ └── Television.java │ ├── v1a │ │ └── Controller.java │ ├── v1b │ │ ├── Controller.java │ │ └── Main.java │ ├── v2 │ │ ├── Command.java │ │ ├── Controller.java │ │ ├── FanNextLevelCommand.java │ │ ├── FanPreviousLevelCommand.java │ │ ├── Main.java │ │ ├── TurnOffAirConditionerCommand.java │ │ ├── TurnOffTvCommand.java │ │ ├── TurnOnAirConditionerCommand.java │ │ └── TurnOnTvCommand.java │ └── v3 │ │ ├── Command.java │ │ ├── Controller.java │ │ ├── FanNextLevelCommand.java │ │ ├── FanPreviousLevelCommand.java │ │ ├── Main.java │ │ ├── TurnOffAirConditionerCommand.java │ │ ├── TurnOffTvCommand.java │ │ ├── TurnOnAirConditionerCommand.java │ │ └── TurnOnTvCommand.java ├── 景點-狀態模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── inspectionProfiles │ │ │ └── Project_Default.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── uiDesigner.xml │ │ └── vcs.xml │ ├── img_1.png │ ├── v0 │ │ ├── Main.java │ │ └── TicketSystem.java │ ├── v1 │ │ ├── Main.java │ │ └── TicketSystem.java │ └── v2 │ │ ├── Main.java │ │ └── ticketsystem │ │ ├── EnoughCoinsState.java │ │ ├── InStockState.java │ │ ├── SoldOutState.java │ │ ├── State.java │ │ └── TicketSystem.java └── 景點-觀察者模式 │ ├── .gitignore │ ├── .idea │ ├── c3m1s1-觀察者模式.iml │ ├── checkstyle-idea.xml │ ├── compiler.xml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── jarRepositories.xml │ ├── misc.xml │ ├── modules.xml │ ├── uiDesigner.xml │ └── vcs.xml │ ├── common │ ├── BarChart.java │ ├── PieChart.java │ ├── ReadStudents.java │ ├── Student.java │ └── Utils.java │ ├── pom.xml │ ├── student.data │ ├── v1 │ ├── Main.java │ ├── StudentDataFile.java │ ├── StudentDataFileBackup.java │ ├── StudentJobTitlePieChart.java │ └── StudentLanguageBarChart.java │ ├── v2pull │ ├── Main.java │ ├── StudentDataFile.java │ ├── StudentDataFileBackup.java │ ├── StudentDataObserver.java │ ├── StudentJobTitlePieChart.java │ └── StudentLanguageBarChart.java │ ├── v3push │ ├── Main.java │ ├── StudentDataFile.java │ ├── StudentDataFileBackup.java │ ├── StudentDataObserver.java │ ├── StudentJobTitlePieChart.java │ └── StudentLanguageBarChart.java │ └── xchart-3.8.1.jar ├── c4-規模化架構思維 ├── 景點-代理人模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── compiler.xml │ │ ├── discord.xml │ │ ├── jarRepositories.xml │ │ ├── libraries │ │ │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml │ │ │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_13_2.xml │ │ │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml │ │ │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_13_3.xml │ │ │ └── Maven__org_apache_commons_commons_csv_1_9_0.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── vcs.xml │ ├── expenses.json │ ├── food.ls │ ├── img.png │ ├── pom.xml │ ├── utils │ │ └── ScannerUtils.java │ ├── v1 │ │ ├── Expense.java │ │ ├── ExpenseTrackingCLI.java │ │ ├── ExpenseTrackingSystem.java │ │ ├── Main.java │ │ └── SuperExpenseTrackingSystem.java │ ├── v2 │ │ ├── Main.java │ │ └── VirtualSuperExpenseTrackingSystemProxy.java │ └── v3 │ │ ├── Main.java │ │ └── TrialVersionSuperExpenseTrackingSystemProxy.java ├── 景點-裝飾者模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── discord.xml │ │ ├── inspectionProfiles │ │ │ └── Project_Default.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── uiDesigner.xml │ │ └── vcs.xml │ ├── commons │ │ ├── Email.java │ │ ├── Message.java │ │ ├── User.java │ │ └── ValidationUtils.java │ ├── img.png │ ├── v1 │ │ ├── EmailFormattingAndParagraphingMessenger.java │ │ ├── EmailHidingAndParagraphingMessenger.java │ │ ├── Main.java │ │ └── Messenger.java │ ├── v2 │ │ ├── ConsoleMessenger.java │ │ ├── DiscordMessenger.java │ │ ├── EmailFormatting.java │ │ ├── HideEmails.java │ │ ├── Main.java │ │ ├── MessageProcessor.java │ │ ├── Messenger.java │ │ ├── Paragraphing.java │ │ └── SendMessagesRequest.java │ └── wsa.mail ├── 景點-複合模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── discord.xml │ │ ├── inspectionProfiles │ │ │ └── Project_Default.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── vcs.xml │ ├── utils │ │ └── ValidationUtils.java │ ├── v1 │ │ ├── CLI.java │ │ ├── Directory.java │ │ ├── File.java │ │ └── Main.java │ └── v2 │ │ ├── CLI.java │ │ ├── Directory.java │ │ ├── File.java │ │ ├── Item.java │ │ └── Main.java ├── 景點-轉接器模式 │ ├── .idea │ │ ├── .gitignore │ │ ├── checkstyle-idea.xml │ │ ├── compiler.xml │ │ ├── discord.xml │ │ ├── inspectionProfiles │ │ │ └── Project_Default.xml │ │ ├── jarRepositories.xml │ │ ├── libraries │ │ │ └── Maven__org_jsoup_jsoup_1_15_2.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── uiDesigner.xml │ │ └── vcs.xml │ ├── pom.xml │ └── v1and2 │ │ ├── Main.java │ │ ├── VocabCrawlerAdapter.java │ │ ├── VocabDictionary.java │ │ ├── VocabLookupCLI.java │ │ ├── Word.java │ │ ├── WordNotExistsException.java │ │ └── crawler │ │ ├── SuperVocabCrawler.java │ │ ├── SuperWORD.java │ │ └── YouSpellItWrongException.java └── 景點-門面模式 │ ├── .idea │ ├── .gitignore │ ├── checkstyle-idea.xml │ ├── discord.xml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── uiDesigner.xml │ └── vcs.xml │ ├── data.table │ ├── v1 │ ├── Main.java │ └── lib │ │ ├── CountRows.java │ │ ├── MarkdownParser.java │ │ ├── StatsOperation.java │ │ ├── Table.java │ │ ├── TableStatsPerformer.java │ │ └── TotalColumn.java │ └── v2 │ ├── Main.java │ ├── StatsFacade.java │ └── lib │ ├── CountRows.java │ ├── MarkdownParser.java │ ├── StatsOperation.java │ ├── Table.java │ ├── TableStatsPerformer.java │ └── TotalColumn.java ├── c5-生命週期及控制反轉 ├── 景點-單體模式 │ ├── pom.xml │ ├── remaining-budget │ ├── script.json │ └── src │ │ ├── main │ │ ├── java │ │ │ ├── Main.java │ │ │ ├── app │ │ │ │ ├── discord │ │ │ │ │ ├── Channel.java │ │ │ │ │ ├── ChatMessageResponse.java │ │ │ │ │ ├── Events.java │ │ │ │ │ └── Platform.java │ │ │ │ ├── fb │ │ │ │ │ ├── Bot.java │ │ │ │ │ ├── Cart.java │ │ │ │ │ ├── Client.java │ │ │ │ │ ├── ECommercePlatformBot.java │ │ │ │ │ └── Events.java │ │ │ │ └── sdk │ │ │ │ │ ├── v1 │ │ │ │ │ └── ChatBot.java │ │ │ │ │ ├── v2 │ │ │ │ │ ├── ChatBot.java │ │ │ │ │ └── Main.java │ │ │ │ │ └── v3 │ │ │ │ │ └── ChatBot.java │ │ │ └── lib │ │ │ │ ├── commands │ │ │ │ └── AndCommand.java │ │ │ │ ├── ioc │ │ │ │ ├── Command.java │ │ │ │ ├── CommandInterpreter.java │ │ │ │ ├── CommandLine.java │ │ │ │ ├── DuplicateInstanceTypeException.java │ │ │ │ ├── Instantiator.java │ │ │ │ └── WaterballContainer.java │ │ │ │ └── utils │ │ │ │ └── IteratorUtils.java │ │ └── resources │ │ │ └── .gitignore │ │ └── test │ │ └── java │ │ └── lib │ │ ├── commands │ │ ├── EchoCommandTask.java │ │ └── RepeatCommandTask.java │ │ └── ioc │ │ └── WaterballContainerTest.java ├── 景點-工廠方法 │ └── src │ │ ├── tunnel │ │ ├── Tunnel.java │ │ └── WaterballTunnel.java │ │ ├── v1 │ │ └── ChatRoomServer.java │ │ ├── v2 │ │ ├── ChatRoomServer.java │ │ ├── Main.java │ │ └── WaterballChatRoomServer.java │ │ └── v3 │ │ ├── ChatRoomServer.java │ │ ├── Database.java │ │ ├── DatabaseFactory.java │ │ ├── Main.java │ │ ├── TunnelFactory.java │ │ └── WaterballTunnelFactory.java └── 景點-抽象工廠 │ ├── c5m3s1.iml │ ├── floor1.questions │ ├── floor2.questions │ ├── floor3.questions │ ├── requirement.md │ ├── v1 │ ├── Floor.java │ ├── Game.java │ ├── Main.java │ ├── Player.java │ ├── Portable.java │ ├── Portal.java │ ├── Question.java │ ├── Region.java │ ├── Stage.java │ └── TopFloor.java │ ├── v2 │ ├── BasePortal.java │ ├── BaseRegion.java │ ├── BaseStage.java │ ├── Floor.java │ ├── Game.java │ ├── Main.java │ ├── Player.java │ ├── Portable.java │ ├── Portal.java │ ├── PortalDecorator.java │ ├── Question.java │ ├── Region.java │ ├── RegionDecorator.java │ ├── Stage.java │ ├── TopFloor.java │ ├── defaults │ │ ├── BasePortalFactory.java │ │ ├── BaseRegionFactory.java │ │ └── BaseStageFactory.java │ ├── factories │ │ ├── PortalFactory.java │ │ ├── RegionFactory.java │ │ └── StageFactory.java │ └── thirdparty │ │ ├── SuperPortal.java │ │ ├── SuperPortalFactory.java │ │ ├── SuperRegion.java │ │ ├── SuperRegionFactory.java │ │ ├── SuperStage.java │ │ └── SuperStageFactory.java │ ├── v3 │ ├── BasePortal.java │ ├── BaseRegion.java │ ├── BaseStage.java │ ├── Floor.java │ ├── Game.java │ ├── Main.java │ ├── Player.java │ ├── Portable.java │ ├── Portal.java │ ├── PortalDecorator.java │ ├── PortalFactory.java │ ├── Question.java │ ├── Region.java │ ├── RegionDecorator.java │ ├── RegionFactory.java │ ├── Stage.java │ ├── StageFactory.java │ ├── SuperPortal.java │ ├── SuperRegion.java │ ├── SuperStage.java │ ├── TopFloor.java │ ├── defaults │ │ └── BaseFloorAbstractFactory.java │ ├── factories │ │ └── FloorAbstractFactory.java │ └── thirdparty │ │ ├── SuperFloorAbstractFactory.java │ │ ├── SuperPortal.java │ │ ├── SuperRegion.java │ │ └── SuperStage.java │ └── waterball.questions └── wsa-design-pattern.iml /.gitignore: -------------------------------------------------------------------------------- 1 | overs JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | # User-specific stuff 4 | .idea/**/workspace.xml 5 | .idea/**/tasks.xml 6 | .idea/**/usage.statistics.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | .idea/gradle.xml 10 | .idea/libraries 11 | 12 | 13 | # AWS User-specific 14 | .idea/**/aws.xml 15 | 16 | 17 | # IntelliJ 18 | out/ 19 | 20 | # Maven 21 | target/ 22 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/wsa-design-pattern.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 軟體設計模式精通之旅:影片範例程式 2 | 3 | 大家好,這是「[軟體設計模式精通之旅](https://waterballsa.tw/design-pattern)」這門課所有影片的範例程式碼! 4 | 5 | 各位學員菁英們,若發現有教材上的疑問或勘誤,歡迎提出。 6 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/Main.java: -------------------------------------------------------------------------------- 1 | public class Main { 2 | public static void main(String[] args) { 3 | System.out.println("Hello world!"); 4 | } 5 | } -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/AI.java: -------------------------------------------------------------------------------- 1 | package abstractclass; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class AI extends Player { 7 | public AI(int number) { 8 | super(number); 9 | } 10 | 11 | @Override 12 | public Decision decide() { 13 | int randomNum = (int) (Math.random() * 3); 14 | switch (randomNum) { 15 | case 0: 16 | return Decision.SCISSORS; 17 | case 1: 18 | return Decision.PAPER; 19 | default: 20 | return Decision.STONE; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/Decision.java: -------------------------------------------------------------------------------- 1 | package abstractclass; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public enum Decision { 7 | PAPER("布"), SCISSORS("剪刀"), STONE("石頭"); 8 | 9 | private final String name; 10 | 11 | Decision(String name) { 12 | this.name = name; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/Human.java: -------------------------------------------------------------------------------- 1 | package abstractclass; 2 | 3 | import java.util.Scanner; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class Human extends Player { 9 | private final static Scanner in = new Scanner(System.in); 10 | 11 | public Human(int number) { 12 | super(number); 13 | } 14 | 15 | @Override 16 | public Decision decide() { 17 | System.out.println("請出拳 (1) 剪刀 (2) 拳頭 (3) 布:"); 18 | int num = in.nextInt(); 19 | switch (num) { 20 | case 1: 21 | return Decision.SCISSORS; 22 | case 2: 23 | return Decision.STONE; 24 | case 3: 25 | return Decision.PAPER; 26 | default: 27 | System.out.println("只能輸入範圍 1~3 的數字,請再輸入一次。"); 28 | return decide(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/OOAD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c1-物件導向之不新手的新手村/OOP-技法/abstractclass/OOAD.png -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/Player.java: -------------------------------------------------------------------------------- 1 | package abstractclass; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public abstract class Player { 7 | private final int number; 8 | 9 | public Player(int number) { 10 | this.number = number; 11 | } 12 | 13 | public abstract Decision decide(); 14 | 15 | public int getNumber() { 16 | return number; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/abstractclass/Test.java: -------------------------------------------------------------------------------- 1 | package abstractclass; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Test { 7 | public static void main(String[] args) { 8 | Game game = new Game(new Human(2), new AI(2)); 9 | game.start(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/Fruit.java: -------------------------------------------------------------------------------- 1 | package hero; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Fruit { 7 | } 8 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/LevelSheet.java: -------------------------------------------------------------------------------- 1 | package hero; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class LevelSheet { 7 | public int queryLevel(int totalExp) { 8 | return totalExp / 1000 + 1; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/Pet.java: -------------------------------------------------------------------------------- 1 | package hero; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class Pet { 9 | private final String name; 10 | 11 | @Nullable 12 | private Hero owner; 13 | 14 | public Pet(String name) { 15 | this.name = name; 16 | } 17 | 18 | public void eat(Fruit fruit) { 19 | System.out.println("寵物吃水果⋯⋯"); 20 | 21 | if (owner != null) { 22 | owner.setHp(owner.getHp() + 10); 23 | } 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setOwner(@Nullable Hero owner) { 31 | this.owner = owner; 32 | } 33 | 34 | public Hero getOwner() { 35 | return owner; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/Test.java: -------------------------------------------------------------------------------- 1 | package hero; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Test { 7 | 8 | public static void main(String[] args) { 9 | Hero hero = new Hero(); 10 | LevelSheet levelSheet = new LevelSheet(); 11 | 12 | hero.gainExp(0, levelSheet); 13 | hero.gainExp(100, levelSheet); 14 | hero.gainExp(900, levelSheet); 15 | 16 | hero.gainExp(-200, levelSheet); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/Test2.java: -------------------------------------------------------------------------------- 1 | package hero; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Test2 { 7 | public static void main(String[] args) { 8 | Hero hero = new Hero(); 9 | Pet cat = new Pet("Cat"); 10 | hero.setPet(cat); 11 | 12 | System.out.printf("Hero 目前血量: %d\n", hero.getHp()); 13 | assert hero.getPet() != null; 14 | System.out.printf("Hero's 寵物名稱: %s\n", hero.getPet().getName()); 15 | 16 | for (int i = 0; i < 5; i++) { 17 | cat.eat(new Fruit()); 18 | } 19 | 20 | hero.removePet(); 21 | 22 | for (int i = 0; i < 5; i++) { 23 | cat.eat(new Fruit()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/case1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c1-物件導向之不新手的新手村/OOP-技法/hero/case1.png -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/case2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c1-物件導向之不新手的新手村/OOP-技法/hero/case2.png -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/hero/case3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c1-物件導向之不新手的新手村/OOP-技法/hero/case3.png -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/lecture/LectureAttendance.java: -------------------------------------------------------------------------------- 1 | package lecture; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import static utils.ValidationUtils.shouldBeWithinRange; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public class LectureAttendance { 11 | private final Student student; 12 | private final Lecture lecture; 13 | 14 | @Nullable 15 | private Integer grade; 16 | 17 | public LectureAttendance(Student student, Lecture lecture) { 18 | this.student = student; 19 | this.lecture = lecture; 20 | } 21 | 22 | public void receiveGrade(int grade) { 23 | this.grade = shouldBeWithinRange("Grade", grade, 0, 100); 24 | System.out.printf("在 '%s' 課程中,學生 '%s' 拿了 '%d' 分。\n", 25 | lecture.getName(), student.getName(), grade); 26 | } 27 | 28 | @Nullable 29 | public Integer getGrade() { 30 | return grade; 31 | } 32 | 33 | public Student getStudent() { 34 | return student; 35 | } 36 | 37 | public Lecture getLecture() { 38 | return lecture; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/lecture/Student.java: -------------------------------------------------------------------------------- 1 | package lecture; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import static java.util.Collections.unmodifiableList; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class Student { 12 | private final String name; 13 | 14 | private final List lectureAttendances = new ArrayList<>(); // 代表他修了哪些課 (0..*) 15 | 16 | public Student(String name) { 17 | this.name = name; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public List getLectureAttendances() { 25 | return unmodifiableList(lectureAttendances); 26 | } 27 | 28 | public void addLectureAttendance(LectureAttendance lectureAttendance) { 29 | lectureAttendances.add(lectureAttendance); 30 | } 31 | 32 | public void removeLectureAttendance(LectureAttendance lectureAttendance) { 33 | lectureAttendances.remove(lectureAttendance); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/lecture/Test4.java: -------------------------------------------------------------------------------- 1 | package lecture; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Test4 { 7 | public static void main(String[] args) { 8 | Student student1 = new Student("Johnny"); 9 | Student student2 = new Student("Peter"); 10 | Lecture lecture1 = new Lecture("軟體設計模式精通之旅"); 11 | Lecture lecture2 = new Lecture("GenAI 工程師產能爆發之路"); 12 | 13 | lecture1.signUp(student1); 14 | lecture2.signUp(student1); 15 | lecture2.signUp(student2); 16 | 17 | try { 18 | lecture1.signUp(student1); 19 | } catch (Exception err) { 20 | System.out.println("不能重複註冊!"); 21 | } 22 | 23 | for (LectureAttendance attendance : lecture1.getLectureAttendances()) { 24 | attendance.receiveGrade(60); // 打分數 25 | } 26 | 27 | for (LectureAttendance attendance : lecture2.getLectureAttendances()) { 28 | attendance.receiveGrade(100); // 打分數 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/lecture/case4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c1-物件導向之不新手的新手村/OOP-技法/lecture/case4.png -------------------------------------------------------------------------------- /c1-物件導向之不新手的新手村/OOP-技法/utils/ValidationUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class ValidationUtils { 9 | 10 | public static int shouldBeGreaterThanOrEqual(String name, int num, int target) { 11 | if (num < target) { 12 | throw new IllegalArgumentException(format("'%s' must be greater than or equal %d.", name, target)); 13 | } 14 | return num; 15 | } 16 | 17 | public static int shouldBeWithinRange(String name, int num, int min, int max) { 18 | if (min > max) { 19 | throw new IllegalArgumentException("Min must be <= Max!"); 20 | } 21 | if (num < min || num > max) { 22 | throw new IllegalArgumentException(format("'%s' must be within 0~100.", name)); 23 | } 24 | return num; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.gitignore: -------------------------------------------------------------------------------- 1 | overs JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | # User-specific stuff 4 | .idea/**/workspace.xml 5 | .idea/**/tasks.xml 6 | .idea/**/usage.statistics.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | .idea/gradle.xml 10 | .idea/libraries 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | 16 | # IntelliJ 17 | out/ 18 | 19 | # Maven 20 | target/ 21 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/astah.asta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c2-Christopher-Alexander-設計模式/景點-樣板方法/astah.asta -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/c2m2s1-樣板方法.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/common/GroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public interface GroupingStrategy { 9 | List group(List students); 10 | } 11 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/common/Utils.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Utils { 9 | public static void printGroups(List groups) { 10 | for (Group group : groups) { 11 | System.out.print("["); 12 | for (int i = 0; i < group.size(); i++) { 13 | if (i % 2 == 0) { 14 | System.out.print(group.get(i)); 15 | } else { 16 | System.out.printf(", %s", group.get(i)); 17 | if (i != group.size() - 1) { 18 | System.out.println(); 19 | } 20 | } 21 | } 22 | System.out.print("]\n\n"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | tw.waterballsa 8 | c2m2s1 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 11 13 | 11 14 | 15 | 16 | 17 | 18 | com.github.javafaker 19 | javafaker 20 | 0.12 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v0/Main.java: -------------------------------------------------------------------------------- 1 | package v0; 2 | 3 | import common.Group; 4 | import common.GroupingStrategy; 5 | import common.ReadStudents; 6 | import common.Student; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import static common.Utils.printGroups; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class Main { 17 | public static void main(String[] args) throws IOException { 18 | LanguageBasedGroupingStrategy groupingStrategy = new LanguageBasedGroupingStrategy(); 19 | 20 | List students = ReadStudents.fromFile("student.data"); 21 | List groups = groupingStrategy.group(students); 22 | 23 | printGroups(groups); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v1/LanguageBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.Group; 4 | import common.GroupingStrategy; 5 | import common.Student; 6 | import v2.CutBasedGroupingStrategy; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class LanguageBasedGroupingStrategy extends CutBasedGroupingStrategy { 17 | 18 | @Override 19 | protected Object cutBy(Student student) { 20 | return student.getLanguage(); 21 | } 22 | 23 | @Override 24 | protected boolean meetMergeCriteria(Group nonFullGroup, Group fullGroup) { 25 | return nonFullGroup.get(0).getLanguage().equals(fullGroup.get(0).getLanguage()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.Group; 4 | import common.GroupingStrategy; 5 | import common.ReadStudents; 6 | import common.Student; 7 | import v2.JobTitleBasedGroupingStrategy; 8 | 9 | import java.io.IOException; 10 | import java.util.List; 11 | 12 | import static common.Utils.printGroups; 13 | 14 | /** 15 | * @author - johnny850807@gmail.com (Waterball) 16 | */ 17 | public class Main { 18 | public static void main(String[] args) throws IOException { 19 | GroupingStrategy groupingStrategy = new JobTitleBasedGroupingStrategy(); 20 | List students = ReadStudents.fromFile("student.data"); 21 | List groups = groupingStrategy.group(students); 22 | 23 | printGroups(groups); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v1/TimeSlotsBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.Student; 4 | import v2.CutBasedGroupingStrategy; 5 | 6 | import static java.lang.String.format; 7 | 8 | /** 9 | * @author - johnny850807@gmail.com (Waterball) 10 | */ 11 | public class TimeSlotsBasedGroupingStrategy extends CutBasedGroupingStrategy { 12 | 13 | @Override 14 | protected Object cutBy(Student student) { 15 | return hashMemberTimeSlots(student); 16 | } 17 | 18 | private String hashMemberTimeSlots(Student student) { 19 | // Hash to four s 9AM-12AM 1PM-4PM 5PM-7PM 8PM-9PM 20 | boolean[] s = student.getAvailableTimeSlots(); 21 | return format("%d%d%d%d", convertBooleanToNumber(s[0] && s[1] && s[2] && s[3]), 22 | convertBooleanToNumber(s[4] & s[5] & s[6] & s[7]), 23 | convertBooleanToNumber(s[8] && s[9] && s[10]), 24 | convertBooleanToNumber(s[11] && s[12])); 25 | } 26 | 27 | private int convertBooleanToNumber(boolean b) { 28 | return b ? 1 : 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v2/JobTitleBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import common.Group; 4 | import common.Student; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class JobTitleBasedGroupingStrategy extends CutBasedGroupingStrategy { 10 | @Override 11 | protected Object cutBy(Student student) { 12 | return student.getJobTitle(); 13 | } 14 | 15 | @Override 16 | protected boolean meetMergeCriteria(Group nonFullGroup, Group fullGroup) { 17 | return nonFullGroup.get(0).getJobTitle().equals(fullGroup.get(0).getJobTitle()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import common.Group; 4 | import common.GroupingStrategy; 5 | import common.ReadStudents; 6 | import common.Student; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import static common.Utils.printGroups; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class Main { 17 | public static void main(String[] args) throws IOException { 18 | GroupingStrategy groupingStrategy = new LanguageBasedGroupingStrategy(); 19 | 20 | List students = ReadStudents.fromFile("student.data"); 21 | List groups = groupingStrategy.group(students); 22 | 23 | printGroups(groups); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v3/JobTitleBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import common.Group; 4 | import common.Student; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class JobTitleBasedGroupingStrategy extends CutBasedGroupingStrategy { 10 | 11 | protected JobTitleBasedGroupingStrategy(int groupMinSize) { 12 | super(groupMinSize); 13 | } 14 | 15 | @Override 16 | protected Object cutGroupBy(Student student) { 17 | return student.getJobTitle(); 18 | } 19 | 20 | @Override 21 | protected boolean meetMergeCriterial(Group nonFullGroup, Group fullGroup) { 22 | return nonFullGroup.get(0).getJobTitle().equals(fullGroup.get(0).getJobTitle()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v3/LanguageBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import common.Group; 4 | import common.Student; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class LanguageBasedGroupingStrategy extends CutBasedGroupingStrategy { 10 | 11 | protected LanguageBasedGroupingStrategy() { 12 | super(6); 13 | } 14 | 15 | @Override 16 | protected Object cutGroupBy(Student student) { 17 | return student.getLanguage(); 18 | } 19 | 20 | @Override 21 | protected boolean meetMergeCriterial(Group nonFullGroup, Group fullGroup) { 22 | return nonFullGroup.get(0).getLanguage().equals(fullGroup.get(0).getLanguage()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v3/Main.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import common.Group; 4 | import common.GroupingStrategy; 5 | import common.Student; 6 | import common.ReadStudents; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import static common.Utils.printGroups; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class Main { 17 | public static void main(String[] args) throws IOException { 18 | GroupingStrategy groupingStrategy = new TimeSlotsBasedGroupingStrategy(); 19 | 20 | List students = ReadStudents.fromFile("student.data"); 21 | List groups = groupingStrategy.group(students); 22 | 23 | printGroups(groups); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-樣板方法/v3/TimeSlotsBasedGroupingStrategy.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import common.Student; 4 | 5 | import static java.lang.String.format; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class TimeSlotsBasedGroupingStrategy extends CutBasedGroupingStrategy { 11 | 12 | protected TimeSlotsBasedGroupingStrategy() { 13 | super(6); 14 | } 15 | 16 | @Override 17 | protected Object cutGroupBy(Student student) { 18 | return hashMemberTimeSlots(student); 19 | } 20 | 21 | private String hashMemberTimeSlots(Student student) { 22 | // Hash to four s 9AM-12AM 1PM-4PM 5PM-7PM 8PM-9PM 23 | boolean[] s = student.getAvailableTimeSlots(); 24 | return format("%d%d%d%d", convertBooleanToNumber(s[0] && s[1] && s[2] && s[3]), 25 | convertBooleanToNumber(s[4] & s[5] & s[6] & s[7]), 26 | convertBooleanToNumber(s[8] && s[9] && s[10]), 27 | convertBooleanToNumber(s[11] && s[12])); 28 | } 29 | 30 | private int convertBooleanToNumber(boolean b) { 31 | return b ? 1 : 0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | # User-specific stuff 4 | .idea/**/workspace.xml 5 | .idea/**/tasks.xml 6 | .idea/**/usage.statistics.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | 10 | # AWS User-specific 11 | .idea/**/aws.xml 12 | 13 | 14 | # IntelliJ 15 | out/ -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/astah.asta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c2-Christopher-Alexander-設計模式/景點-策略模式/astah.asta -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/commons/Utils.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Utils { 7 | public static void printf(String format, Object... args) { 8 | System.out.printf(format, args); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v1/Game.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import java.util.List; 4 | 5 | import static java.util.Arrays.asList; 6 | import static java.util.Collections.swap; 7 | import static commons.Utils.printf; 8 | 9 | public class Game { 10 | private final List heroes; 11 | 12 | public Game(Hero hero1, Hero hero2) { 13 | this.heroes = asList(hero1, hero2); 14 | } 15 | 16 | public void start() { 17 | nextTurn(); 18 | } 19 | 20 | private void nextTurn() { 21 | Hero attacker = heroes.get(0); 22 | Hero attacked = heroes.get(1); 23 | attacker.attack(attacked); 24 | swap(heroes, 0, 1); 25 | if (attacked.isDead()) { 26 | printf("英雄 %s 死亡!%s 獲勝!\n", attacked.getName(), attacker.getName()); 27 | } else { 28 | nextTurn(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | Hero hero1 = new Hero("水之球", "Waterball"); 9 | Hero hero2 = new Hero("大潘", "Fireball"); 10 | Game game = new Game(hero1, hero2); 11 | game.start(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/AttackType.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | public interface AttackType { 4 | void attack(Hero attacker, Hero attacked); 5 | } 6 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Earth.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | public class Earth implements AttackType { 4 | 5 | public void attack(Hero attacker, Hero attacked) { 6 | for (int i = 0; i < 10; i++) { 7 | attacked.damage(20); 8 | } 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Fireball.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | public class Fireball implements AttackType { 4 | 5 | public void attack(Hero attacker, Hero attacked) { 6 | for (int i = 0; i < 3; i++) { 7 | attacked.damage(50); 8 | } 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Game.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.List; 4 | 5 | import static java.util.Arrays.asList; 6 | import static java.util.Collections.swap; 7 | import static commons.Utils.printf; 8 | 9 | public class Game { 10 | private final List heroes; 11 | 12 | public Game(Hero hero1, Hero hero2) { 13 | this.heroes = asList(hero1, hero2); 14 | } 15 | 16 | public void start() { 17 | nextTurn(); 18 | } 19 | 20 | private void nextTurn() { 21 | Hero attacker = heroes.get(0); 22 | Hero attacked = heroes.get(1); 23 | attacker.attack(attacked); 24 | swap(heroes, 0, 1); 25 | if (attacked.isDead()) { 26 | printf("英雄 %s 死亡!%s 獲勝!\n", attacked.getName(), attacker.getName()); 27 | } else { 28 | nextTurn(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Hero.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import static commons.Utils.printf; 4 | import static java.lang.Math.max; 5 | 6 | public class Hero { 7 | private int hp = 500; 8 | private final String name; 9 | private final AttackType attackType; 10 | 11 | public Hero(String name, AttackType attackType) { 12 | this.name = name; 13 | this.attackType = attackType; 14 | } 15 | 16 | public void attack(Hero hero) { 17 | attackType.attack(this, hero); 18 | } 19 | 20 | public void damage(int damage) { 21 | setHp(getHp() - damage); 22 | printf("英雄 %s 受到了 %d 點傷害,生命值剩下 %d。\n", name, damage, hp); 23 | } 24 | 25 | public boolean isDead() { 26 | return hp <= 0; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setHp(int hp) { 34 | this.hp = max(0, hp); 35 | } 36 | 37 | public int getHp() { 38 | return hp; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | Hero hero1 = new Hero("水之球", new Powerball()); 9 | Hero hero2 = new Hero("大潘", new Earth()); 10 | Game game = new Game(hero1, hero2); 11 | game.start(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Powerball.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Powerball implements AttackType { 7 | @Override 8 | public void attack(Hero attacker, Hero attacked) { 9 | attacked.damage(500); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-策略模式/v2/Waterball.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | public class Waterball implements AttackType { 4 | 5 | public void attack(Hero attacker, Hero attacked) { 6 | attacked.damage((int) (attacker.getHp() * 0.5)); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.gitignore: -------------------------------------------------------------------------------- 1 | overs JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | # User-specific stuff 4 | .idea/**/workspace.xml 5 | .idea/**/tasks.xml 6 | .idea/**/usage.statistics.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | .idea/gradle.xml 10 | .idea/libraries 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | 16 | # IntelliJ 17 | out/ 18 | 19 | # Maven 20 | target/ 21 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/.name: -------------------------------------------------------------------------------- 1 | c2m3s1 -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/C2M3S1.asta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c2-Christopher-Alexander-設計模式/景點-責任鏈模式/C2M3S1.asta -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v1/Main.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Main { 9 | public static void main(String[] args) throws IOException { 10 | WaterballBot waterballBot = new WaterballBot(); 11 | waterballBot.connect(); 12 | } 13 | } -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v2/HelpHandler.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v2; 2 | 3 | import discord4j.core.object.entity.Message; 4 | import discord4j.core.object.entity.channel.MessageChannel; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class HelpHandler extends MessageHandler { 10 | 11 | public HelpHandler(MessageHandler next) { 12 | super(next); 13 | } 14 | 15 | @Override 16 | public void handle(Message message, MessageChannel channel) { 17 | if ("help".equalsIgnoreCase(message.getContent())) { 18 | channel.createMessage("▋ HELP ▋").block(); 19 | channel.createMessage("Commands: dcard, currency").block(); 20 | } else if (next != null) { 21 | next.handle(message, channel); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v2/Main.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v2; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Main { 9 | public static void main(String[] args) throws IOException { 10 | WaterballBot waterballBot = new WaterballBot(new HelpHandler((new CurrencyHandler(null)))); 11 | waterballBot.connect(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v2/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v2; 2 | 3 | import discord4j.core.object.entity.Message; 4 | import discord4j.core.object.entity.channel.MessageChannel; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public abstract class MessageHandler { 10 | protected MessageHandler next; 11 | 12 | public MessageHandler(MessageHandler next) { 13 | this.next = next; 14 | } 15 | 16 | public abstract void handle(Message message, MessageChannel channel); 17 | } 18 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v3/HelpMessageHandler.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v3; 2 | 3 | import discord4j.core.object.entity.Message; 4 | import discord4j.core.object.entity.channel.MessageChannel; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class HelpMessageHandler extends MessageHandler { 10 | public HelpMessageHandler(MessageHandler next) { 11 | super(next); 12 | } 13 | 14 | @Override 15 | protected boolean match(Message message) { 16 | return "help".equalsIgnoreCase(message.getContent()); 17 | } 18 | 19 | @Override 20 | protected void doHandling(Message message, MessageChannel channel) { 21 | channel.createMessage("▋ HELP ▋").block(); 22 | channel.createMessage("Commands: dcard, currency").block(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v3/Main.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v3; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Main { 9 | 10 | public static void main(String[] args) throws IOException { 11 | WaterballBot waterballBot = new WaterballBot( 12 | new HelpMessageHandler(new DcardHandler(new CurrencyHandler(null)))); 13 | waterballBot.connect(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/java/tw/waterballsa/degisnpattern/c2m3s1/v3/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package tw.waterballsa.degisnpattern.c2m3s1.v3; 2 | 3 | import discord4j.core.object.entity.Message; 4 | import discord4j.core.object.entity.channel.MessageChannel; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public abstract class MessageHandler { 10 | protected MessageHandler next; 11 | 12 | public MessageHandler(MessageHandler next) { 13 | this.next = next; 14 | } 15 | 16 | public void handle(Message message, MessageChannel channel) { 17 | if (match(message)) { 18 | doHandling(message, channel); 19 | } else if (next != null) { 20 | next.handle(message, channel); 21 | } 22 | } 23 | 24 | protected abstract boolean match(Message message); 25 | protected abstract void doHandling(Message message, MessageChannel channel); 26 | } 27 | -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/resources/.gitignore: -------------------------------------------------------------------------------- 1 | token.properties -------------------------------------------------------------------------------- /c2-Christopher-Alexander-設計模式/景點-責任鏈模式/src/main/resources/token.example.properties: -------------------------------------------------------------------------------- 1 | TOKEN= -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/commons/AirConditioner.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class AirConditioner { 7 | private boolean on; 8 | 9 | public boolean isOn() { 10 | return on; 11 | } 12 | 13 | public void turnOn() { 14 | this.on = true; 15 | System.out.println("【 AC 】Turned ON."); 16 | } 17 | 18 | public void turnOff() { 19 | this.on = false; 20 | System.out.println("【 AC 】Turned OFF."); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/commons/Fan.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Fan { 7 | private int level; // {0, 1, 2, 3} 8 | 9 | public int getLevel() { 10 | return level; 11 | } 12 | 13 | public void nextLevel() { 14 | level = (level + 1) % 4; 15 | System.out.println("【 Fan 】Level -> " + level); 16 | } 17 | 18 | public void previousLevel() { 19 | level = level - 1 == -1 ? 3 : level - 1; 20 | System.out.println("【 Fan 】Level -> " + level); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/commons/Television.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Television { 7 | private boolean on; 8 | 9 | public void turnOn() { 10 | this.on = true; 11 | System.out.println("【 TV 】Turned ON."); 12 | } 13 | 14 | public void turnOff() { 15 | this.on = false; 16 | System.out.println("【 TV 】Turned OFF."); 17 | } 18 | 19 | public boolean isOn() { 20 | return on; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v1a/Controller.java: -------------------------------------------------------------------------------- 1 | package v1a; 2 | 3 | import commons.AirConditioner; 4 | import commons.Fan; 5 | import commons.Television; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Controller { 11 | private final AirConditioner ac; 12 | private final Fan fan; 13 | private final Television tv; 14 | 15 | public Controller(AirConditioner ac, Fan fan, Television tv) { 16 | this.ac = ac; 17 | this.fan = fan; 18 | this.tv = tv; 19 | } 20 | 21 | public void press0() { 22 | fan.nextLevel(); 23 | } 24 | 25 | public void press1() { 26 | fan.previousLevel(); 27 | } 28 | 29 | public void press2() { 30 | ac.turnOn(); 31 | } 32 | 33 | public void press3() { 34 | ac.turnOff(); 35 | } 36 | 37 | public void press4() { 38 | tv.turnOn(); 39 | } 40 | 41 | public void press5() { 42 | tv.turnOff(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v1b/Controller.java: -------------------------------------------------------------------------------- 1 | package v1b; 2 | 3 | import commons.AirConditioner; 4 | import commons.Fan; 5 | import commons.Television; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Controller { 11 | private final AirConditioner ac; 12 | private final Fan fan; 13 | private final Television tv; 14 | 15 | public Controller(AirConditioner ac, Fan fan, Television tv) { 16 | this.ac = ac; 17 | this.fan = fan; 18 | this.tv = tv; 19 | } 20 | 21 | public void press(int button) { 22 | switch (button) { 23 | case 0: 24 | fan.nextLevel(); 25 | break; 26 | case 1: 27 | fan.previousLevel(); 28 | break; 29 | case 2: 30 | ac.turnOn(); 31 | break; 32 | case 3: 33 | ac.turnOff(); 34 | break; 35 | case 4: 36 | tv.turnOn(); 37 | break; 38 | case 5: 39 | tv.turnOff(); 40 | break; 41 | default: 42 | throw new IllegalArgumentException("Non-recognizable button."); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v1b/Main.java: -------------------------------------------------------------------------------- 1 | package v1b; 2 | 3 | import commons.AirConditioner; 4 | import commons.Fan; 5 | import commons.Television; 6 | 7 | import java.util.Scanner; 8 | 9 | /** 10 | * @author - johnny850807@gmail.com (Waterball) 11 | */ 12 | @SuppressWarnings("InfiniteLoopStatement") 13 | public class Main { 14 | public static void main(String[] args) { 15 | AirConditioner ac = new AirConditioner(); 16 | Fan fan = new Fan(); 17 | Television tv = new Television(); 18 | Controller controller = new Controller(ac, fan, tv); 19 | 20 | Scanner in = new Scanner(System.in); 21 | while (true) { 22 | System.out.println("Click a button (0~5): "); 23 | int button = in.nextInt(); 24 | controller.press(button); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/Command.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public interface Command { 7 | void execute(); 8 | } 9 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/Controller.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Controller { 7 | private final Command[] commands = new Command[6]; 8 | 9 | public void setCommand(int button, Command command) { 10 | commands[button] = command; 11 | } 12 | 13 | public void press(int button) { 14 | if (button >= 0 && button < commands.length) { 15 | commands[button].execute(); 16 | } else { 17 | throw new IllegalArgumentException("Button " + button + " unsupported."); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/FanNextLevelCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Fan; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class FanNextLevelCommand implements Command { 9 | private final Fan fan; 10 | 11 | public FanNextLevelCommand(Fan fan) { 12 | this.fan = fan; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | fan.nextLevel(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/FanPreviousLevelCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Fan; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class FanPreviousLevelCommand implements Command { 9 | private final Fan fan; 10 | 11 | public FanPreviousLevelCommand(Fan fan) { 12 | this.fan = fan; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | fan.previousLevel(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.AirConditioner; 4 | import commons.Fan; 5 | import commons.Television; 6 | 7 | import java.util.Scanner; 8 | 9 | /** 10 | * @author - johnny850807@gmail.com (Waterball) 11 | */ 12 | @SuppressWarnings("InfiniteLoopStatement") 13 | public class Main { 14 | public static void main(String[] args) { 15 | AirConditioner ac = new AirConditioner(); 16 | Fan fan = new Fan(); 17 | Television tv = new Television(); 18 | 19 | Controller controller = new Controller(); 20 | // dependency injection 21 | controller.setCommand(0, new FanNextLevelCommand(fan)); 22 | controller.setCommand(1, new FanPreviousLevelCommand(fan)); 23 | controller.setCommand(2, new TurnOnAirConditionerCommand(ac)); 24 | controller.setCommand(3, new TurnOffAirConditionerCommand(ac)); 25 | controller.setCommand(4, new TurnOnTvCommand(tv)); 26 | controller.setCommand(5, new TurnOffTvCommand(tv)); 27 | 28 | Scanner in = new Scanner(System.in); 29 | while (true) { 30 | System.out.println("Click a button (0~5): "); 31 | int button = in.nextInt(); 32 | controller.press(button); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/TurnOffAirConditionerCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.AirConditioner; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOffAirConditionerCommand implements Command { 9 | private final AirConditioner ac; 10 | 11 | public TurnOffAirConditionerCommand(AirConditioner ac) { 12 | this.ac = ac; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | ac.turnOff(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/TurnOffTvCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Television; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOffTvCommand implements Command { 9 | private final Television tv; 10 | 11 | public TurnOffTvCommand(Television tv) { 12 | this.tv = tv; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | tv.turnOff(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/TurnOnAirConditionerCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.AirConditioner; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOnAirConditionerCommand implements Command { 9 | private final AirConditioner ac; 10 | 11 | public TurnOnAirConditionerCommand(AirConditioner ac) { 12 | this.ac = ac; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | ac.turnOn(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v2/TurnOnTvCommand.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Television; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOnTvCommand implements Command { 9 | private final Television tv; 10 | 11 | public TurnOnTvCommand(Television tv) { 12 | this.tv = tv; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | tv.turnOn(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/Command.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public interface Command { 7 | void execute(); 8 | void undo(); 9 | } 10 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/FanNextLevelCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.Fan; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class FanNextLevelCommand implements Command { 9 | private final Fan fan; 10 | 11 | public FanNextLevelCommand(Fan fan) { 12 | this.fan = fan; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | fan.nextLevel(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | fan.previousLevel(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/FanPreviousLevelCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.Fan; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class FanPreviousLevelCommand implements Command { 9 | private final Fan fan; 10 | 11 | public FanPreviousLevelCommand(Fan fan) { 12 | this.fan = fan; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | fan.previousLevel(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | fan.nextLevel(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/TurnOffAirConditionerCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.AirConditioner; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOffAirConditionerCommand implements Command { 9 | private final AirConditioner ac; 10 | 11 | public TurnOffAirConditionerCommand(AirConditioner ac) { 12 | this.ac = ac; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | ac.turnOff(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | ac.turnOn(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/TurnOffTvCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.Television; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOffTvCommand implements Command { 9 | private final Television tv; 10 | 11 | public TurnOffTvCommand(Television tv) { 12 | this.tv = tv; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | tv.turnOff(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | tv.turnOn(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/TurnOnAirConditionerCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.AirConditioner; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOnAirConditionerCommand implements Command { 9 | private final AirConditioner ac; 10 | 11 | public TurnOnAirConditionerCommand(AirConditioner ac) { 12 | this.ac = ac; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | ac.turnOn(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | ac.turnOff(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-指令模式/v3/TurnOnTvCommand.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import commons.Television; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TurnOnTvCommand implements Command { 9 | private final Television tv; 10 | 11 | public TurnOnTvCommand(Television tv) { 12 | this.tv = tv; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | tv.turnOn(); 18 | } 19 | 20 | @Override 21 | public void undo() { 22 | tv.turnOff(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c3-掌握所有複雜行為變動/景點-狀態模式/img_1.png -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | 4 | import static v1.TicketSystem.State.*; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class Main { 10 | public static void main(String[] args) { 11 | TicketSystem ticketSystem = new TicketSystem(2); 12 | 13 | System.out.println("【Case 1】 Enough coins -> Error 不再接受新硬幣"); 14 | ticketSystem.setState(ENOUGH_COINS); 15 | ticketSystem.insertCoin(); 16 | 17 | System.out.println("\n【Case 2】 Enough Coins + Refund -> 吐 3 枚、熄燈"); 18 | ticketSystem.pressRefundButton(); 19 | 20 | System.out.println("\n【Case 3】 Enough coins + Buy -> 將硬幣總數歸零、出一張票、熄燈"); 21 | ticketSystem.setState(ENOUGH_COINS); 22 | ticketSystem.pressBuyButton(); 23 | 24 | System.out.println("\n【Case 4】 In-Stock(0 Coins) + Buy -> Error 金幣不足"); 25 | ticketSystem.setState(IN_STOCK); 26 | ticketSystem.pressBuyButton(); 27 | 28 | System.out.println("\n【Case 5】 In-Stock(0 Coins) + Refund -> 吐 0 枚"); 29 | ticketSystem.pressRefundButton(); 30 | 31 | System.out.println("\n【Case 6】 Sold-Out + Insert Coin -> 立即吐出 1 枚硬幣"); 32 | ticketSystem.setState(SOLD_OUT); 33 | ticketSystem.insertCoin(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/v2/ticketsystem/SoldOutState.java: -------------------------------------------------------------------------------- 1 | package v2.ticketsystem; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class SoldOutState extends State { 7 | public SoldOutState(TicketSystem ticketSystem) { 8 | super(ticketSystem); 9 | ticketSystem.turnLight(false); 10 | } 11 | 12 | @Override 13 | public void insertCoin() { 14 | ticketSystem.setTotal(ticketSystem.getTotal() + 1); 15 | ticketSystem.spitCoins(ticketSystem.getTotal()); 16 | } 17 | 18 | @Override 19 | public void fillInTickets(int tickets) { 20 | ticketSystem.setState(new InStockState(ticketSystem, 21 | ticketSystem.getTickets() + tickets)); 22 | } 23 | 24 | @Override 25 | public void pressBuyButton() { 26 | System.out.println("[ERROR] You haven't inserted enough coins."); 27 | } 28 | 29 | @Override 30 | public void pressRefundButton() { 31 | ticketSystem.spitCoins(ticketSystem.getTotal()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-狀態模式/v2/ticketsystem/State.java: -------------------------------------------------------------------------------- 1 | package v2.ticketsystem; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public abstract class State { 7 | protected TicketSystem ticketSystem; 8 | public abstract void insertCoin(); 9 | public abstract void fillInTickets(int tickets); 10 | public abstract void pressBuyButton(); 11 | public abstract void pressRefundButton(); 12 | 13 | public State(TicketSystem ticketSystem) { 14 | this.ticketSystem = ticketSystem; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.gitignore: -------------------------------------------------------------------------------- 1 | overs JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | # User-specific stuff 4 | .idea/**/workspace.xml 5 | .idea/**/tasks.xml 6 | .idea/**/usage.statistics.xml 7 | .idea/**/dictionaries 8 | .idea/**/shelf 9 | .idea/gradle.xml 10 | .idea/libraries 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | 16 | # IntelliJ 17 | out/ 18 | 19 | # Maven 20 | target/ 21 | 22 | *.backup.data 23 | students.bar.png 24 | students.pie.png -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/common/BarChart.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | import common.ReadStudents; 4 | import org.knowm.xchart.BitmapEncoder; 5 | import org.knowm.xchart.CategoryChart; 6 | import org.knowm.xchart.CategoryChartBuilder; 7 | import org.knowm.xchart.style.Styler; 8 | 9 | import java.io.IOException; 10 | import java.util.List; 11 | 12 | import static org.knowm.xchart.BitmapEncoder.saveBitmap; 13 | 14 | /** 15 | * @author - johnny850807@gmail.com (Waterball) 16 | */ 17 | public class BarChart { 18 | public void export(String fileName, List x, List y) throws IOException { 19 | CategoryChart chart = categoryChart(); 20 | chart.addSeries("histogram", x, y); 21 | saveBitmap(chart, fileName, BitmapEncoder.BitmapFormat.PNG); 22 | } 23 | 24 | private CategoryChart categoryChart() { 25 | CategoryChart chart = new CategoryChartBuilder().width(800).height(600).title("Bar Chart").xAxisTitle("Language").yAxisTitle("Count").build(); 26 | chart.getStyler().setLegendPosition(Styler.LegendPosition.InsideNW); 27 | chart.getStyler().setAvailableSpaceFill(.96); 28 | chart.getStyler().setOverlapped(true); 29 | return chart; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/common/Utils.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.function.Function; 6 | import java.util.function.Predicate; 7 | import java.util.stream.Collectors; 8 | 9 | import static java.util.stream.Collectors.toList; 10 | 11 | /** 12 | * @author - johnny850807@gmail.com (Waterball) 13 | */ 14 | public class Utils { 15 | public static void delay(long ms) { 16 | try { 17 | Thread.sleep(ms); 18 | } catch (InterruptedException ignored) { 19 | } 20 | } 21 | 22 | public static List selectDistinct(Collection t, Function mapping) { 23 | return t.stream().map(mapping).distinct().collect(toList()); 24 | } 25 | public static List count(Collection t, Collection v, Function mapping) { 26 | return t.stream().map(val -> (int) v.stream().filter(s -> val.equals(mapping.apply(s))).count()).collect(toList()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | StudentDataFile studentDataFile = new StudentDataFile("student.data"); 9 | studentDataFile.startMonitoring(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v1/StudentDataFileBackup.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.Student; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | import java.util.Locale; 11 | import java.util.stream.Collectors; 12 | 13 | import static java.util.stream.Collectors.joining; 14 | 15 | /** 16 | * @author - johnny850807@gmail.com (Waterball) 17 | */ 18 | public class StudentDataFileBackup { 19 | private final StudentDataFile dataFile; 20 | 21 | public StudentDataFileBackup(StudentDataFile dataFile) { 22 | this.dataFile = dataFile; 23 | } 24 | 25 | public void backup() throws IOException { 26 | String fileName = new SimpleDateFormat("yyyyMMdd-HH:mm:ss'.backup.data'", Locale.getDefault()).format(new Date()); 27 | Files.writeString(Paths.get(fileName), dataFile.getStudents().stream() 28 | .map(Student::toString).collect(joining("\n"))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v1/StudentJobTitlePieChart.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.PieChart; 4 | import common.Student; 5 | 6 | import java.io.IOException; 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | import static common.Utils.count; 11 | import static common.Utils.selectDistinct; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class StudentJobTitlePieChart { 17 | private final StudentDataFile dataFile; 18 | 19 | public StudentJobTitlePieChart(StudentDataFile dataFile) { 20 | this.dataFile = dataFile; 21 | } 22 | 23 | public void renderPieChart() throws IOException { 24 | Collection students = dataFile.getStudents(); 25 | List series = selectDistinct(students, Student::getJobTitle); 26 | List numbers = count(series, students, Student::getJobTitle); 27 | PieChart pieChart = new PieChart(); 28 | pieChart.export("students.pie.png", series, numbers); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v1/StudentLanguageBarChart.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import common.BarChart; 4 | import common.Student; 5 | 6 | import java.io.IOException; 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | import static common.Utils.count; 11 | import static common.Utils.selectDistinct; 12 | 13 | /** 14 | * @author - johnny850807@gmail.com (Waterball) 15 | */ 16 | public class StudentLanguageBarChart { 17 | private final StudentDataFile dataFile; 18 | 19 | public StudentLanguageBarChart(StudentDataFile dataFile) { 20 | this.dataFile = dataFile; 21 | } 22 | 23 | public void renderBarChart() throws IOException { 24 | BarChart barChart = new BarChart(); 25 | Collection students = dataFile.getStudents(); 26 | List x = selectDistinct(students, Student::getLanguage); 27 | List y = count(x, students, Student::getLanguage); 28 | barChart.export("students.bar.png", x, y); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v2pull/Main.java: -------------------------------------------------------------------------------- 1 | package v2pull; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | StudentDataFile studentDataFile = new StudentDataFile("student.data"); 9 | StudentLanguageBarChart barChart = new StudentLanguageBarChart(studentDataFile); 10 | StudentJobTitlePieChart pieChart = new StudentJobTitlePieChart(studentDataFile); 11 | StudentDataFileBackup dataFileBackup = new StudentDataFileBackup(studentDataFile); 12 | studentDataFile.register(barChart); 13 | studentDataFile.register(pieChart); 14 | studentDataFile.register(dataFileBackup); 15 | studentDataFile.startMonitoring(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v2pull/StudentDataFileBackup.java: -------------------------------------------------------------------------------- 1 | package v2pull; 2 | 3 | import common.Student; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | import java.util.Locale; 11 | 12 | import static java.util.stream.Collectors.joining; 13 | 14 | /** 15 | * @author - johnny850807@gmail.com (Waterball) 16 | */ 17 | public class StudentDataFileBackup implements StudentDataObserver { 18 | private final StudentDataFile dataFile; 19 | 20 | public StudentDataFileBackup(StudentDataFile dataFile) { 21 | this.dataFile = dataFile; 22 | } 23 | 24 | @Override 25 | public void update() throws IOException { 26 | String fileName = new SimpleDateFormat("yyyyMMdd-HH:mm:ss'.backup.data'", Locale.getDefault()).format(new Date()); 27 | Files.writeString(Paths.get(fileName), dataFile.getStudents().stream() 28 | .map(Student::toString) 29 | .collect(joining("\n"))); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v2pull/StudentDataObserver.java: -------------------------------------------------------------------------------- 1 | package v2pull; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public interface StudentDataObserver { 9 | void update() throws IOException; 10 | } 11 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v2pull/StudentJobTitlePieChart.java: -------------------------------------------------------------------------------- 1 | package v2pull; 2 | 3 | import common.BarChart; 4 | import common.PieChart; 5 | import common.Student; 6 | 7 | import java.io.IOException; 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | import static common.Utils.count; 12 | import static common.Utils.selectDistinct; 13 | import static java.util.stream.Collectors.toList; 14 | 15 | /** 16 | * @author - johnny850807@gmail.com (Waterball) 17 | */ 18 | public class StudentJobTitlePieChart implements StudentDataObserver { 19 | private final StudentDataFile dataFile; 20 | 21 | public StudentJobTitlePieChart(StudentDataFile dataFile) { 22 | this.dataFile = dataFile; 23 | } 24 | 25 | @Override 26 | public void update() throws IOException { 27 | PieChart pieChart = new PieChart(); 28 | Collection students = dataFile.getStudents(); 29 | List x = selectDistinct(students, Student::getLanguage); 30 | List y = count(x, students, Student::getLanguage); 31 | pieChart.export("students.bar.png", x, y); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v2pull/StudentLanguageBarChart.java: -------------------------------------------------------------------------------- 1 | package v2pull; 2 | 3 | import common.BarChart; 4 | import common.Student; 5 | import org.knowm.xchart.CategoryChart; 6 | import org.knowm.xchart.CategoryChartBuilder; 7 | import org.knowm.xchart.style.Styler; 8 | 9 | import java.io.IOException; 10 | import java.util.Collection; 11 | import java.util.List; 12 | 13 | import static common.Utils.count; 14 | import static common.Utils.selectDistinct; 15 | import static java.util.stream.Collectors.toList; 16 | 17 | /** 18 | * @author - johnny850807@gmail.com (Waterball) 19 | */ 20 | public class StudentLanguageBarChart implements StudentDataObserver { 21 | private final StudentDataFile dataFile; 22 | 23 | public StudentLanguageBarChart(StudentDataFile dataFile) { 24 | this.dataFile = dataFile; 25 | } 26 | 27 | @Override 28 | public void update() throws IOException { 29 | BarChart barChart = new BarChart(); 30 | Collection students = dataFile.getStudents(); 31 | List x = selectDistinct(students, Student::getLanguage); 32 | List y = count(x, students, Student::getLanguage); 33 | barChart.export("students.bar.png", x, y); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v3push/Main.java: -------------------------------------------------------------------------------- 1 | package v3push; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | StudentDataFile studentDataFile = new StudentDataFile("student.data"); 9 | StudentLanguageBarChart barChart = new StudentLanguageBarChart(); 10 | StudentJobTitlePieChart pieChart = new StudentJobTitlePieChart(); 11 | StudentDataFileBackup dataFileBackup = new StudentDataFileBackup(); 12 | studentDataFile.register(barChart); 13 | studentDataFile.register(pieChart); 14 | studentDataFile.register(dataFileBackup); 15 | studentDataFile.startMonitoring(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v3push/StudentDataFileBackup.java: -------------------------------------------------------------------------------- 1 | package v3push; 2 | 3 | import common.Student; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Collection; 10 | import java.util.Date; 11 | import java.util.Locale; 12 | 13 | import static java.util.stream.Collectors.joining; 14 | 15 | /** 16 | * @author - johnny850807@gmail.com (Waterball) 17 | */ 18 | @SuppressWarnings("ALL") 19 | public class StudentDataFileBackup implements StudentDataObserver { 20 | @Override 21 | public void update(Collection students) throws IOException { 22 | String fileName = new SimpleDateFormat("yyyyMMdd-HH:mm:ss'.backup.data'", Locale.getDefault()).format(new Date()); 23 | Files.writeString(Paths.get(fileName), students.stream() 24 | .map(Student::toString) 25 | .collect(joining("\n"))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v3push/StudentDataObserver.java: -------------------------------------------------------------------------------- 1 | package v3push; 2 | 3 | import common.Student; 4 | 5 | import java.io.IOException; 6 | import java.util.Collection; 7 | 8 | /** 9 | * @author - johnny850807@gmail.com (Waterball) 10 | */ 11 | public interface StudentDataObserver { 12 | void update(Collection students) throws IOException; 13 | } 14 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v3push/StudentJobTitlePieChart.java: -------------------------------------------------------------------------------- 1 | package v3push; 2 | 3 | import common.BarChart; 4 | import common.PieChart; 5 | import common.Student; 6 | 7 | import java.io.IOException; 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | import static common.Utils.count; 12 | import static common.Utils.selectDistinct; 13 | 14 | /** 15 | * @author - johnny850807@gmail.com (Waterball) 16 | */ 17 | public class StudentJobTitlePieChart implements StudentDataObserver { 18 | @Override 19 | public void update(Collection students) throws IOException { 20 | PieChart pieChart = new PieChart(); 21 | List x = selectDistinct(students, Student::getLanguage); 22 | List y = count(x, students, Student::getLanguage); 23 | pieChart.export("students.bar.png", x, y); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/v3push/StudentLanguageBarChart.java: -------------------------------------------------------------------------------- 1 | package v3push; 2 | 3 | import common.BarChart; 4 | import common.Student; 5 | import org.knowm.xchart.BitmapEncoder; 6 | import org.knowm.xchart.CategoryChart; 7 | import org.knowm.xchart.CategoryChartBuilder; 8 | import org.knowm.xchart.style.Styler; 9 | 10 | import java.io.IOException; 11 | import java.util.Collection; 12 | import java.util.List; 13 | 14 | import static common.Utils.count; 15 | import static common.Utils.selectDistinct; 16 | import static java.util.stream.Collectors.toList; 17 | import static org.knowm.xchart.BitmapEncoder.saveBitmap; 18 | 19 | /** 20 | * @author - johnny850807@gmail.com (Waterball) 21 | */ 22 | public class StudentLanguageBarChart implements StudentDataObserver { 23 | @Override 24 | public void update(Collection students) throws IOException { 25 | BarChart barChart = new BarChart(); 26 | List x = selectDistinct(students, Student::getLanguage); 27 | List y = count(x, students, Student::getLanguage); 28 | barChart.export("students.bar.png", x, y); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c3-掌握所有複雜行為變動/景點-觀察者模式/xchart-3.8.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c3-掌握所有複雜行為變動/景點-觀察者模式/xchart-3.8.1.jar -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_13_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_13_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/libraries/Maven__org_apache_commons_commons_csv_1_9_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c4-規模化架構思維/景點-代理人模式/img.png -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v1/Expense.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import java.math.BigDecimal; 4 | import java.time.LocalDateTime; 5 | import java.util.UUID; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Expense { 11 | private final String id; 12 | private final String description; 13 | private final BigDecimal cost; 14 | private final LocalDateTime createdTime; 15 | 16 | public Expense(String description, BigDecimal cost) { 17 | this(UUID.randomUUID().toString(), 18 | description, cost, LocalDateTime.now()); 19 | } 20 | 21 | public Expense(String id, String description, BigDecimal cost, LocalDateTime createdTime) { 22 | this.id = id; 23 | this.description = description; 24 | this.cost = cost; 25 | this.createdTime = createdTime; 26 | } 27 | 28 | public Expense edit(String description, BigDecimal cost) { 29 | return new Expense(id, description, cost, createdTime); 30 | } 31 | 32 | public String getId() { 33 | return id; 34 | } 35 | 36 | public String getDescription() { 37 | return description; 38 | } 39 | 40 | public BigDecimal getCost() { 41 | return cost; 42 | } 43 | 44 | public LocalDateTime getCreatedTime() { 45 | return createdTime; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v1/ExpenseTrackingSystem.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public interface ExpenseTrackingSystem { 9 | List getExpenses(); 10 | void addExpense(Expense expense); 11 | void editExpense(Expense expense); 12 | void exportCSV(String filename); 13 | } 14 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | ExpenseTrackingCLI cli = new ExpenseTrackingCLI(new SuperExpenseTrackingSystem()); 9 | cli.start(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import v1.ExpenseTrackingCLI; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Main { 9 | public static void main(String[] args) { 10 | ExpenseTrackingCLI cli = new ExpenseTrackingCLI(new VirtualSuperExpenseTrackingSystemProxy()); 11 | cli.start(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v2/VirtualSuperExpenseTrackingSystemProxy.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import v1.Expense; 4 | import v1.ExpenseTrackingSystem; 5 | import v1.SuperExpenseTrackingSystem; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author - johnny850807@gmail.com (Waterball) 11 | */ 12 | public class VirtualSuperExpenseTrackingSystemProxy implements ExpenseTrackingSystem { 13 | private SuperExpenseTrackingSystem superSystem; 14 | 15 | @Override 16 | public List getExpenses() { 17 | lazyInitialization(); 18 | return superSystem.getExpenses(); 19 | } 20 | 21 | @Override 22 | public void addExpense(Expense expense) { 23 | lazyInitialization(); 24 | superSystem.addExpense(expense); 25 | } 26 | 27 | @Override 28 | public void editExpense(Expense expense) { 29 | lazyInitialization(); 30 | superSystem.editExpense(expense); 31 | } 32 | 33 | @Override 34 | public void exportCSV(String filename) { 35 | lazyInitialization(); 36 | superSystem.exportCSV(filename); 37 | } 38 | 39 | private void lazyInitialization() { 40 | if (superSystem == null) { 41 | superSystem = new SuperExpenseTrackingSystem(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v3/Main.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import v1.ExpenseTrackingCLI; 4 | import v1.SuperExpenseTrackingSystem; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class Main { 10 | public static void main(String[] args) { 11 | ExpenseTrackingCLI cli = new ExpenseTrackingCLI(new TrialVersionSuperExpenseTrackingSystemProxy()); 12 | cli.start(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-代理人模式/v3/TrialVersionSuperExpenseTrackingSystemProxy.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import v2.VirtualSuperExpenseTrackingSystemProxy; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TrialVersionSuperExpenseTrackingSystemProxy extends VirtualSuperExpenseTrackingSystemProxy { 9 | @Override 10 | public void exportCSV(String filename) { 11 | throw new UnsupportedOperationException("CSV exporting is not supported in the trial version."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/commons/Email.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | import java.util.Objects; 4 | 5 | import static java.lang.String.format; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Email { 11 | private final String username; 12 | private final String domain; 13 | 14 | public Email(String username, String domain) { 15 | this.username = username; 16 | this.domain = domain; 17 | } 18 | 19 | public String getUsername() { 20 | return username; 21 | } 22 | 23 | public String getDomain() { 24 | return domain; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return format("%s@%s", username, domain); 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | if (this == o) return true; 35 | if (o == null || getClass() != o.getClass()) return false; 36 | Email email = (Email) o; 37 | return username.equals(email.username) && domain.equals(email.domain); 38 | } 39 | 40 | @Override 41 | public int hashCode() { 42 | return Objects.hash(username, domain); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/commons/User.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class User { 9 | private final Email email; 10 | private final String nickname; 11 | 12 | public User(Email email, String nickname) { 13 | this.email = email; 14 | this.nickname = nickname; 15 | } 16 | 17 | public String getNickname() { 18 | return nickname; 19 | } 20 | 21 | public Email getEmail() { 22 | return email; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return format("%s (%s)", nickname, email); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/commons/ValidationUtils.java: -------------------------------------------------------------------------------- 1 | package commons; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class ValidationUtils { 7 | public static String lengthShouldBeWithin(String content, int min, int max) { 8 | if (content.length() < min || content.length() > max) { 9 | throw new IllegalArgumentException(String.format("The length must be within %d~%d.", min, max)); 10 | } 11 | return content; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waterball-Software-Academy/Software-Design-Pattern/0d833dc792f953af40df43132dc555df20bd481b/c4-規模化架構思維/景點-裝飾者模式/img.png -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import commons.Email; 4 | import commons.Message; 5 | import commons.User; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | User waterball = new User(new Email("johnny", "waterballsa.tw"), "水球"); 10 | User tsen = new User(new Email("tsen", "waterballsa.tw"), "岑岑"); 11 | Message message = new Message(waterball, tsen, 12 | "Could you tell the following people (wally@waterballsa.tw, fixiabis@waterballsa.tw, fong-putao@waterballsa.tw)\n\n" + 13 | "that I'm gonna take a leave today? Thanks!" 14 | ); 15 | 16 | System.out.println("====== EmailFormattingAndParagraphingMessenger ====="); 17 | new EmailFormattingAndParagraphingMessenger().sendMessage(message); 18 | System.out.println("\n====== EmailHidingAndParagraphingMessenger ====="); 19 | new EmailHidingAndParagraphingMessenger().sendMessage(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v1/Messenger.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import commons.Message; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public abstract class Messenger { 9 | public abstract void sendMessage(Message message); 10 | } 11 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/ConsoleMessenger.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.time.format.DateTimeFormatter; 6 | import java.util.List; 7 | 8 | /** 9 | * @author - johnny850807@gmail.com (Waterball) 10 | */ 11 | public class ConsoleMessenger implements Messenger { 12 | @Override 13 | public void send(List messages) { 14 | System.out.println("以下訊息已經送到了 Console ..."); 15 | for (Message message : messages) { 16 | System.out.printf("[%s] %s: \n%s\n", 17 | message.getCreatedTime().format(DateTimeFormatter.ofPattern("MM/dd hh:mm")), 18 | message.getAuthor(), message.getContent()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/DiscordMessenger.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.time.format.DateTimeFormatter; 6 | import java.util.List; 7 | 8 | /** 9 | * @author - johnny850807@gmail.com (Waterball) 10 | */ 11 | public class DiscordMessenger implements Messenger { 12 | @Override 13 | public void send(List messages) { 14 | System.out.println("以下訊息已經送到了 Discord ..."); 15 | for (Message message : messages) { 16 | System.out.printf("[%s] %s: \n%s\n", 17 | message.getCreatedTime().format(DateTimeFormatter.ofPattern("MM/dd hh:mm")), 18 | message.getAuthor(), message.getContent()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/EmailFormatting.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.util.List; 6 | 7 | import static java.lang.String.format; 8 | import static java.util.stream.Collectors.toUnmodifiableList; 9 | 10 | /** 11 | * @author - johnny850807@gmail.com (Waterball) 12 | */ 13 | public class EmailFormatting extends MessageProcessor { 14 | public EmailFormatting(Messenger next) { 15 | super(next); 16 | } 17 | 18 | @Override 19 | public void send(List messages) { 20 | messages = messages 21 | .stream().map(this::mailFormatting) 22 | .collect(toUnmodifiableList()); 23 | 24 | next.send(messages); 25 | } 26 | 27 | 28 | private Message mailFormatting(Message message) { 29 | return message.edit(format("Dear %s,\n\n%s\n\nBest regards,\n%s", 30 | message.getTargetName(), message.getContent(), message.getAuthorName())); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Email; 4 | import commons.Message; 5 | import commons.User; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | User waterball = new User(new Email("johnny", "waterballsa.tw"), "水球"); 10 | User tsen = new User(new Email("tsen", "waterballsa.tw"), "岑岑"); 11 | Message message = new Message(waterball, tsen, 12 | "Could you tell the following people (wally@waterballsa.tw, fixiabis@waterballsa.tw, fong-putao@waterballsa.tw)\n\n" + 13 | "that I'm gonna take a leave today? Thanks!" 14 | ); 15 | 16 | System.out.println("====== EmailFormattingAndParagraphingMessenger ====="); 17 | new EmailFormatting(new Paragraphing(new DiscordMessenger())).send(message); 18 | System.out.println("\n====== EmailHidingAndParagraphingMessenger ====="); 19 | new HideEmails(new Paragraphing(new ConsoleMessenger())).send(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/MessageProcessor.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public abstract class MessageProcessor implements Messenger { 7 | protected Messenger next; 8 | public MessageProcessor(Messenger next) { 9 | this.next = next; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/Messenger.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.util.List; 6 | 7 | import static java.util.Collections.singletonList; 8 | 9 | /** 10 | * @author - johnny850807@gmail.com (Waterball) 11 | */ 12 | public interface Messenger { 13 | default void send(Message message) { 14 | send(singletonList(message)); 15 | } 16 | void send(List messages); 17 | } 18 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/Paragraphing.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.util.List; 6 | 7 | import static java.util.Arrays.stream; 8 | import static java.util.stream.Collectors.toList; 9 | import static java.util.stream.Collectors.toUnmodifiableList; 10 | 11 | /** 12 | * @author - johnny850807@gmail.com (Waterball) 13 | */ 14 | public class Paragraphing extends MessageProcessor { 15 | public Paragraphing(Messenger next) { 16 | super(next); 17 | } 18 | 19 | @Override 20 | public void send(List messages) { 21 | messages = messages 22 | .stream().flatMap(msg -> paragraph(msg).stream()) 23 | .collect(toUnmodifiableList()); 24 | 25 | next.send(messages); 26 | } 27 | 28 | private List paragraph(Message message) { 29 | return stream(message.getContent().split("\n\n")) 30 | .map(message::edit) 31 | .collect(toList()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-裝飾者模式/v2/SendMessagesRequest.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import commons.Message; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class SendMessagesRequest { 11 | private final List messages; 12 | 13 | public SendMessagesRequest(List messages) { 14 | this.messages = messages; 15 | } 16 | 17 | public List getMessages() { 18 | return messages; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/utils/ValidationUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class ValidationUtils { 9 | public static String shouldMatch(String regex, String content) { 10 | if (!Pattern.matches(regex, content)) { 11 | throw new IllegalArgumentException( 12 | String.format("Content '%s' doesn't match '%s'", 13 | content, regex)); 14 | } 15 | return content; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/v1/File.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import static utils.ValidationUtils.shouldMatch; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class File { 9 | private Directory parent; 10 | private final String name; 11 | private final byte[] content; 12 | 13 | public File(String name, String content) { 14 | this.name = shouldMatch("[A-Za-z0-9.\\-_]+", name); 15 | this.content = content.getBytes(); 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public long bytes() { 23 | return content.length; 24 | } 25 | 26 | public Directory getParent() { 27 | return parent; 28 | } 29 | 30 | public void setParent(Directory parent) { 31 | this.parent = parent; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | Directory root = Directory.root(); 9 | Directory document = new Directory("document"); 10 | Directory notes = new Directory("notes"); 11 | root.addDirectory(document); 12 | document.addDirectory(notes); 13 | root.addFile(new File("me.txt", "Hello, I'm Waterball.")); 14 | notes.addFile(new File("meeting-0825.txt", "Lauren: To be or not to be.")); 15 | notes.addFile(new File("meeting-0824.txt", "Waterball: Composition over Inheritance.")); 16 | 17 | CLI cli = new CLI(root); 18 | cli.start(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/v2/File.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import static java.util.Collections.emptyList; 7 | import static utils.ValidationUtils.shouldMatch; 8 | 9 | /** 10 | * @author - johnny850807@gmail.com (Waterball) 11 | */ 12 | public class File extends Item { 13 | private final byte[] content; 14 | 15 | public File(String name, String content) { 16 | super(name); 17 | this.content = content.getBytes(); 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | @Override 25 | public long totalBytes() { 26 | return content.length; 27 | } 28 | 29 | @Override 30 | public List search(String keyword) { 31 | return emptyList(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/v2/Item.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.List; 4 | 5 | import static utils.ValidationUtils.shouldMatch; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public abstract class Item { 11 | protected final String name; 12 | protected Directory parent; 13 | 14 | public Item(String name) { 15 | this.name = shouldMatch("[A-Za-z0-9.\\-_]+", name); 16 | } 17 | 18 | public abstract long totalBytes(); 19 | 20 | public abstract List search(String keyword); 21 | 22 | public void setParent(Directory parent) { 23 | this.parent = parent; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public Directory getParent() { 31 | return parent; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-複合模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | Directory root = Directory.root(); 9 | Directory document = new Directory("document"); 10 | Directory notes = new Directory("notes"); 11 | root.addDirectory(document); 12 | document.addDirectory(notes); 13 | root.addFile(new File("me.txt", "Hello, I'm Waterball.")); 14 | notes.addFile(new File("meeting-0825.txt", "Lauren: To be or not to be.")); 15 | notes.addFile(new File("meeting-0824.txt", "Waterball: Composition over Inheritance.")); 16 | 17 | CLI cli = new CLI(root); 18 | cli.start(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/libraries/Maven__org_jsoup_jsoup_1_15_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | tw.wateballsa.design-pattern 8 | c4m2s1 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 11 13 | 11 14 | 15 | 16 | 17 | 18 | org.jsoup 19 | jsoup 20 | 1.15.2 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/Main.java: -------------------------------------------------------------------------------- 1 | package v1and2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class Main { 7 | public static void main(String[] args) { 8 | VocabLookupCLI cli = new VocabLookupCLI(new VocabCrawlerAdapter()); 9 | cli.start(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/VocabDictionary.java: -------------------------------------------------------------------------------- 1 | package v1and2; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public interface VocabDictionary { 9 | 10 | /** 11 | * @param wordSpelling the exact whole spelling of the word 12 | * @return the word that exactly matches that spelling 13 | */ 14 | Word lookup(String wordSpelling) throws WordNotExistsException; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/VocabLookupCLI.java: -------------------------------------------------------------------------------- 1 | package v1and2; 2 | 3 | import java.util.Scanner; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class VocabLookupCLI { 9 | private static final Scanner in = new Scanner(System.in); 10 | private final VocabDictionary dictionary; 11 | 12 | public VocabLookupCLI(VocabDictionary dictionary) { 13 | this.dictionary = dictionary; 14 | } 15 | 16 | public void start() { 17 | while (true) { 18 | System.out.println("Lookup a word: "); 19 | String spelling = in.nextLine(); 20 | if (!spelling.isBlank()) { 21 | try { 22 | Word word = dictionary.lookup(spelling); 23 | System.out.println(word); 24 | } catch (WordNotExistsException e) { 25 | System.out.printf("Can't find the word '%s'.\n", spelling); 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/WordNotExistsException.java: -------------------------------------------------------------------------------- 1 | package v1and2; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class WordNotExistsException extends RuntimeException { 7 | private final String wordSpelling; 8 | public WordNotExistsException(String wordSpelling, Exception e) { 9 | super(e); 10 | this.wordSpelling = wordSpelling; 11 | } 12 | 13 | public String getWordSpelling() { 14 | return wordSpelling; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/crawler/SuperWORD.java: -------------------------------------------------------------------------------- 1 | package v1and2.crawler; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class SuperWORD { 9 | public String raw; 10 | public List definitions; // format: 11 | 12 | public SuperWORD(String raw, List definitions) { 13 | this.raw = raw; 14 | this.definitions = definitions; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-轉接器模式/v1and2/crawler/YouSpellItWrongException.java: -------------------------------------------------------------------------------- 1 | package v1and2.crawler; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class YouSpellItWrongException extends Exception { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/data.table: -------------------------------------------------------------------------------- 1 | | Id | Name | Cost | Revenue | 2 | |---------|-------------|---------|-----------| 3 | | 1 | Waterball | 20 | 0 | 4 | | 2 | Lauren | 200000 | 2000 | 5 | | 3 | Eric | 150 | 5000 | 6 | | 4 | Steven | 150 | 3000 | 7 | | 5 | Timm | 300 | 300 | 8 | | 6 | Saker | 150 | 2000 | 9 | | 7 | Steven | 300 | 2000 | 10 | | 8 | Snowman | 150 | 2000 | 11 | | 9 | Jack | 150 | 2000 | 12 | | 10 | Victor | 150 | 2000 | 13 | | 11 | Rumiu | 150 | 2000 | 14 | | 12 | Mily | 150 | 2000 | 15 | | 13 | Winnie | 150 | 2000 | 16 | | 14 | Shengpo | 200 | 2000 | 17 | | 15 | Adam | 150 | 2000 | 18 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import v1.lib.CountRows; 4 | import v1.lib.MarkdownParser; 5 | import v1.lib.Table; 6 | import v1.lib.TableStatsPerformer; 7 | import v1.lib.TotalColumn; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * @author - johnny850807@gmail.com (Waterball) 13 | */ 14 | public class Main { 15 | public static void main(String[] args) throws IOException { 16 | MarkdownParser parser = new MarkdownParser(); 17 | Table table = parser.parseTableFromFile("data.table"); 18 | TableStatsPerformer statsPerformer = new TableStatsPerformer(); 19 | statsPerformer.addStatsOperation(new TotalColumn("Cost")); 20 | statsPerformer.addStatsOperation(new CountRows("Members")); 21 | statsPerformer.print(table); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/CountRows.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class CountRows implements StatsOperation { 9 | public CountRows(String statsName) { 10 | this.rowName = statsName; 11 | } 12 | 13 | private final String rowName; 14 | @Override 15 | public String getName() { 16 | return format("Count %s", rowName); 17 | } 18 | 19 | @Override 20 | public Object perform(Table table) { 21 | return table.getData().size(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/MarkdownParser.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | 4 | import java.io.IOException; 5 | import java.nio.file.Paths; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static java.nio.file.Files.readString; 10 | import static java.util.Arrays.asList; 11 | 12 | /** 13 | * @author - johnny850807@gmail.com (Waterball) 14 | */ 15 | public class MarkdownParser { 16 | public Table parseTableFromFile(String fileName) throws IOException { 17 | String markdown = readString(Paths.get(fileName)); 18 | String[] lines = markdown.split("\n"); 19 | List> fields = new ArrayList<>(); 20 | fields.add(parseRow(0, lines)); 21 | for (int i = 2; i < lines.length; i++) { 22 | fields.add(parseRow(i, lines)); 23 | } 24 | return new Table(fields); 25 | } 26 | 27 | private List parseRow(int i, String[] lines) { 28 | return asList(lines[i].replaceFirst("[|\\s]+", "") 29 | .split("[|\\s]+")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/StatsOperation.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public interface StatsOperation { 7 | String getName(); 8 | Object perform(Table table); 9 | } 10 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/Table.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | import java.util.List; 4 | 5 | import static java.util.stream.Collectors.toList; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Table { 11 | private final List header; 12 | private final List> data; 13 | 14 | public Table(List> data) { 15 | this.header = data.get(0); 16 | this.data = data; 17 | } 18 | 19 | public List getColumn(String fieldName) { 20 | int column = header.indexOf(fieldName); 21 | return data.stream() 22 | .skip(1) // skip the header 23 | .map(row -> row.get(column)).collect(toList()); 24 | } 25 | 26 | public List getRow(int row) { 27 | return data.get(row); 28 | } 29 | 30 | public List> getRows() { 31 | return data.subList(1 /*skip the header*/, data.size()); 32 | } 33 | 34 | public List> getData() { 35 | return data; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/TableStatsPerformer.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class TableStatsPerformer { 10 | private final List statsOperations = new ArrayList<>(); 11 | 12 | public void addStatsOperation(StatsOperation statsOperation) { 13 | statsOperations.add(statsOperation); 14 | } 15 | 16 | public void print(Table table) { 17 | StringBuilder stats = new StringBuilder(); 18 | for (StatsOperation operation : statsOperations) { 19 | stats.append(operation.getName()).append(": ") 20 | .append(operation.perform(table)).append("\n"); 21 | } 22 | System.out.println(stats); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v1/lib/TotalColumn.java: -------------------------------------------------------------------------------- 1 | package v1.lib; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TotalColumn implements StatsOperation { 9 | private final String fieldName; 10 | 11 | public TotalColumn(String fieldName) { 12 | this.fieldName = fieldName; 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return format("Total %s", fieldName); 18 | } 19 | 20 | @Override 21 | public Object perform(Table table) { 22 | return table.getColumn(fieldName) 23 | .stream().mapToDouble(Double::parseDouble) 24 | .sum(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.io.IOException; 4 | 5 | import static v2.StatsFacade.COUNT_MEMBERS; 6 | import static v2.StatsFacade.TOTAL_COST; 7 | 8 | /** 9 | * @author - johnny850807@gmail.com (Waterball) 10 | */ 11 | public class Main { 12 | public static void main(String[] args) throws IOException { 13 | StatsFacade statsFacade = new StatsFacade(); 14 | statsFacade.printMarkdownTableStats("data.table", 15 | TOTAL_COST | COUNT_MEMBERS); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/StatsFacade.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import v2.lib.*; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class StatsFacade { 11 | public static final int TOTAL_COST = 0x01; 12 | public static final int COUNT_MEMBERS = 0x01 << 1; 13 | private final MarkdownParser parser = new MarkdownParser(); 14 | 15 | public void printMarkdownTableStats(String fileName, int statOpsFlag) throws IOException { 16 | Table table = parser.parseTableFromFile(fileName); 17 | 18 | TableStatsPerformer statsPerformer = new TableStatsPerformer(); 19 | 20 | if ((statOpsFlag & TOTAL_COST) != 0) { 21 | statsPerformer.addStatsOperation(new TotalColumn("Cost")); 22 | } 23 | if ((statOpsFlag & COUNT_MEMBERS) != 0) { 24 | statsPerformer.addStatsOperation(new CountRows("Members")); 25 | } 26 | 27 | statsPerformer.print(table); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/CountRows.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class CountRows implements StatsOperation { 9 | public CountRows(String rowName) { 10 | this.rowName = rowName; 11 | } 12 | 13 | private final String rowName; 14 | @Override 15 | public String getName() { 16 | return format("Count %s", rowName); 17 | } 18 | 19 | @Override 20 | public Object perform(Table table) { 21 | return table.getData().size(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/MarkdownParser.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | 4 | import java.io.IOException; 5 | import java.nio.file.Paths; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static java.nio.file.Files.readString; 10 | import static java.util.Arrays.asList; 11 | 12 | /** 13 | * @author - johnny850807@gmail.com (Waterball) 14 | */ 15 | public class MarkdownParser { 16 | 17 | public Table parseTableFromFile(String fileName) throws IOException { 18 | String markdown = readString(Paths.get(fileName)); 19 | String[] lines = markdown.split("\n"); 20 | List> fields = new ArrayList<>(); 21 | fields.add(parseRow(0, lines)); 22 | for (int i = 2; i < lines.length; i++) { 23 | fields.add(parseRow(i, lines)); 24 | } 25 | return new Table(fields); 26 | } 27 | 28 | private List parseRow(int i, String[] lines) { 29 | return asList(lines[i].replaceFirst("[|\\s]+", "") 30 | .split("[|\\s]+")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/StatsOperation.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public interface StatsOperation { 7 | String getName(); 8 | Object perform(Table table); 9 | } 10 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/Table.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | import java.util.List; 4 | 5 | import static java.util.stream.Collectors.toList; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class Table { 11 | private final List header; 12 | private final List> data; 13 | 14 | public Table(List> data) { 15 | this.header = data.get(0); 16 | this.data = data; 17 | } 18 | 19 | public List getColumn(String fieldName) { 20 | int column = header.indexOf(fieldName); 21 | return data.stream() 22 | .skip(1) // skip the header 23 | .map(row -> row.get(column)).collect(toList()); 24 | } 25 | 26 | public List getRow(int row) { 27 | return data.get(row); 28 | } 29 | 30 | public List> getRows() { 31 | return data.subList(1 /*skip the header*/, data.size()); 32 | } 33 | 34 | public List> getData() { 35 | return data; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/TableStatsPerformer.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author - johnny850807@gmail.com (Waterball) 8 | */ 9 | public class TableStatsPerformer { 10 | private final List statsOperations = new ArrayList<>(); 11 | 12 | public void addStatsOperation(StatsOperation statsOperation) { 13 | statsOperations.add(statsOperation); 14 | } 15 | 16 | public void print(Table table) { 17 | StringBuilder stats = new StringBuilder(); 18 | for (StatsOperation operation : statsOperations) { 19 | stats.append(operation.getName()).append(": ") 20 | .append(operation.perform(table)).append("\n"); 21 | } 22 | System.out.println(stats); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c4-規模化架構思維/景點-門面模式/v2/lib/TotalColumn.java: -------------------------------------------------------------------------------- 1 | package v2.lib; 2 | 3 | import static java.lang.String.format; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class TotalColumn implements StatsOperation { 9 | private final String fieldName; 10 | 11 | public TotalColumn(String fieldName) { 12 | this.fieldName = fieldName; 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return format("Total %s", fieldName); 18 | } 19 | 20 | @Override 21 | public Object perform(Table table) { 22 | return table.getColumn(fieldName) 23 | .stream().mapToDouble(Double::parseDouble) 24 | .sum(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/remaining-budget: -------------------------------------------------------------------------------- 1 | 50 -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/script.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "and", 4 | "children": [ 5 | { 6 | "name": "echo", 7 | "args": ["Hello World"] 8 | }, 9 | { 10 | "name": "repeat", 11 | "args": [3], 12 | "children": [ 13 | { 14 | "name": "echo", 15 | "args": ["Yo"] 16 | } 17 | ] 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import app.sdk.v1.ChatBot; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class Main { 9 | public static void main(String[] args) throws IOException { 10 | ChatBot chatBot = new ChatBot(); 11 | String chat = chatBot.chat("水球軟體學院想要名正言順地串接你這個猛 AI 到學院" + 12 | "Discord 中應用,說說你第一個最想被應用的地方吧!(我們有2200人和各種論壇喔)!)"); 13 | System.out.println(chat); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/discord/Channel.java: -------------------------------------------------------------------------------- 1 | package app.discord; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Channel { 7 | public void sendResponse(ChatMessageResponse chatMessageResponse) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/discord/ChatMessageResponse.java: -------------------------------------------------------------------------------- 1 | package app.discord; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class ChatMessageResponse { 7 | public ChatMessageResponse(String response) { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/discord/Events.java: -------------------------------------------------------------------------------- 1 | package app.discord; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Events { 7 | public static class MessageEvent { 8 | public String getContent() { 9 | return null; 10 | } 11 | 12 | public String getUsername() { 13 | return null; 14 | } 15 | } 16 | public static class InquiryEvent {} 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/fb/Bot.java: -------------------------------------------------------------------------------- 1 | package app.fb; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Bot { 7 | public void addMessage(String message) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/fb/Cart.java: -------------------------------------------------------------------------------- 1 | package app.fb; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Cart { 7 | public int getSize() { 8 | return 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/fb/Client.java: -------------------------------------------------------------------------------- 1 | package app.fb; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Client { 7 | public Bot getBot() { 8 | return null; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/fb/ECommercePlatformBot.java: -------------------------------------------------------------------------------- 1 | package app.fb; 2 | 3 | import app.fb.Events.AddToCartEvent; 4 | import app.sdk.v1.ChatBot; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | 10 | import static java.lang.String.format; 11 | 12 | /** 13 | * @author johnny@waterballsa.tw 14 | */ 15 | public class ECommercePlatformBot { 16 | private final static String thingsBotNeedToKnow = readContext(); 17 | private final static ChatBot chatBot = new ChatBot(); 18 | private static String readContext() { 19 | try { 20 | return Files.readString(Path.of("EC-Things-Bot-Need-To-Know")); 21 | } catch (IOException e) { 22 | throw new RuntimeException(e); 23 | } 24 | } 25 | 26 | public void reactToEvent(AddToCartEvent event) { 27 | Cart cart = event.getCart(); 28 | if (cart.getSize() % 3 == 0) { 29 | String suggestion =chatBot.chat(format("%s 剛剛將 %s 加入購物車,現在已經買了 %d 項商品,你覺得他可能還想買哪一項商品?推一項吧。", 30 | event.getUsername(), event.getProductName(), cart.getSize())); 31 | 32 | Client client = event.getUserClient(); 33 | client.getBot().addMessage(suggestion); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/fb/Events.java: -------------------------------------------------------------------------------- 1 | package app.fb; 2 | 3 | import java.awt.*; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class Events { 9 | public static class AddToCartEvent { 10 | public String getContent() { 11 | return null; 12 | } 13 | 14 | public String getUsername() { 15 | return null; 16 | } 17 | 18 | public Cart getCart() { 19 | return null; 20 | } 21 | 22 | public String getProductName() { 23 | return null; 24 | } 25 | 26 | public Client getUserClient() { 27 | return null; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/app/sdk/v2/Main.java: -------------------------------------------------------------------------------- 1 | package app.sdk.v2; 2 | 3 | 4 | /** 5 | * @author johnny@waterballsa.tw 6 | */ 7 | public class Main { 8 | public static void main(String[] args) { 9 | ChatBot chatBot = ChatBot.getInstance(); 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/commands/AndCommand.java: -------------------------------------------------------------------------------- 1 | package lib.commands; 2 | 3 | import lib.ioc.Command; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class AndCommand implements Command { 11 | private List children; 12 | 13 | @Override 14 | public int execute() { 15 | for (Command child : children) { 16 | int status = child.execute(); 17 | if (status != 0) { 18 | return status; 19 | } 20 | } 21 | return 0; 22 | } 23 | 24 | @Override 25 | public void setChildren(List children) { 26 | this.children = children; 27 | } 28 | 29 | @Override 30 | public void setArguments(List arguments) { 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/ioc/Command.java: -------------------------------------------------------------------------------- 1 | package lib.ioc; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public interface Command { 9 | int execute(); 10 | void setChildren(List children); 11 | void setArguments(List arguments); 12 | 13 | 14 | Command NO_OP = new Command() { 15 | @Override 16 | public int execute() { 17 | return 0; 18 | } 19 | 20 | @Override 21 | public void setChildren(List children) { 22 | throw new UnsupportedOperationException(); 23 | } 24 | 25 | @Override 26 | public void setArguments(List arguments) { 27 | throw new UnsupportedOperationException(); 28 | } 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/ioc/CommandLine.java: -------------------------------------------------------------------------------- 1 | package lib.ioc; 2 | 3 | import static java.util.Arrays.copyOfRange; 4 | 5 | /** 6 | * @author - johnny850807@gmail.com (Waterball) 7 | */ 8 | public class CommandLine { 9 | private final String[] tokens; 10 | 11 | public CommandLine(String rawCommandLine) { 12 | this.tokens = rawCommandLine.split(" "); 13 | } 14 | 15 | public String[] getTokens() { 16 | return tokens; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/ioc/DuplicateInstanceTypeException.java: -------------------------------------------------------------------------------- 1 | package lib.ioc; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public class DuplicateInstanceTypeException extends IllegalStateException { 7 | private final Object instance; 8 | 9 | public DuplicateInstanceTypeException(Object instance) { 10 | 11 | this.instance = instance; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/ioc/Instantiator.java: -------------------------------------------------------------------------------- 1 | package lib.ioc; 2 | 3 | /** 4 | * @author - johnny850807@gmail.com (Waterball) 5 | */ 6 | public interface Instantiator { 7 | T instantiate(Object ...args); 8 | } 9 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/java/lib/utils/IteratorUtils.java: -------------------------------------------------------------------------------- 1 | package lib.utils; 2 | 3 | import java.util.Iterator; 4 | import java.util.stream.Stream; 5 | import java.util.stream.StreamSupport; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class IteratorUtils { 11 | public static Stream stream(Iterator iterator) { 12 | return StreamSupport.stream(((Iterable) () -> iterator).spliterator(), false); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/main/resources/.gitignore: -------------------------------------------------------------------------------- 1 | secret -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/test/java/lib/commands/EchoCommandTask.java: -------------------------------------------------------------------------------- 1 | package lib.commands; 2 | 3 | import lib.ioc.Command; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class EchoCommandTask implements Command { 11 | private String content; 12 | 13 | @Override 14 | public int execute() { 15 | System.out.println(content); 16 | return 0; 17 | } 18 | 19 | @Override 20 | public void setChildren(List children) { 21 | } 22 | 23 | @Override 24 | public void setArguments(List arguments) { 25 | content = (String) arguments.get(0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-單體模式/src/test/java/lib/commands/RepeatCommandTask.java: -------------------------------------------------------------------------------- 1 | package lib.commands; 2 | 3 | import lib.ioc.Command; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author - johnny850807@gmail.com (Waterball) 9 | */ 10 | public class RepeatCommandTask implements Command { 11 | private int times; 12 | private Command child; 13 | 14 | @Override 15 | public int execute() { 16 | for (int i = 0; i < times; i++) { 17 | int status = child.execute(); 18 | if (status != 0) { 19 | return status; 20 | } 21 | } 22 | return 0; 23 | } 24 | 25 | @Override 26 | public void setChildren(List children) { 27 | child = children.get(0); 28 | } 29 | 30 | @Override 31 | public void setArguments(List arguments) { 32 | times = (int) arguments.get(0); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/tunnel/Tunnel.java: -------------------------------------------------------------------------------- 1 | package tunnel; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public interface Tunnel { 9 | String message() throws IOException; 10 | 11 | void disconnect() throws IOException; 12 | } 13 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v1/ChatRoomServer.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | 3 | import tunnel.Tunnel; 4 | 5 | import java.io.IOException; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | 9 | import static java.lang.String.format; 10 | 11 | /** 12 | * @author johnny@waterballsa.tw 13 | */ 14 | public abstract class ChatRoomServer { 15 | private final int port; 16 | 17 | public ChatRoomServer(int port) { 18 | this.port = port; 19 | } 20 | 21 | public void startServer() throws IOException { 22 | try(var server = new ServerSocket(port)) { 23 | // 等下一位客人光臨 24 | Socket client = server.accept(); 25 | Tunnel tunnel = createTunnel(client); 26 | String message = tunnel.message(); 27 | System.out.println(message); 28 | } 29 | } 30 | 31 | // 工廠方法 factory method 32 | protected abstract Tunnel createTunnel(Socket client); 33 | } 34 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v2/ChatRoomServer.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import tunnel.Tunnel; 4 | 5 | import java.io.IOException; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | 9 | /** 10 | * @author johnny@waterballsa.tw 11 | */ 12 | public abstract class ChatRoomServer { 13 | private final int port; 14 | 15 | public ChatRoomServer(int port) { 16 | this.port = port; 17 | } 18 | 19 | public void startServer() throws IOException { 20 | try (var server = new ServerSocket(port)) { 21 | Socket client = server.accept(); 22 | 23 | Tunnel tunnel = createTunnel(client); 24 | String message = tunnel.message(); 25 | 26 | System.out.println(message); 27 | } 28 | } 29 | 30 | protected abstract Tunnel createTunnel(Socket client); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v2/Main.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class Main { 9 | public static void main(String[] args) throws IOException { 10 | ChatRoomServer server = new WaterballChatRoomServer(8787); 11 | server.startServer(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v2/WaterballChatRoomServer.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import tunnel.Tunnel; 4 | import tunnel.WaterballTunnel; 5 | 6 | import java.net.Socket; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class WaterballChatRoomServer extends ChatRoomServer { 12 | public WaterballChatRoomServer(int port) { 13 | super(port); 14 | } 15 | 16 | @Override 17 | protected Tunnel createTunnel(Socket client) { 18 | return new WaterballTunnel(client); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/ChatRoomServer.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import tunnel.Tunnel; 4 | 5 | import java.io.IOException; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | 9 | /** 10 | * V3: 組合取代繼承 11 | * @author johnny@waterballsa.tw 12 | */ 13 | public class ChatRoomServer { 14 | private final int port; 15 | private final TunnelFactory tunnelFactory; 16 | private final DatabaseFactory databaseFactory; 17 | 18 | public ChatRoomServer(int port, 19 | TunnelFactory tunnelFactory, 20 | DatabaseFactory databaseFactory) { 21 | this.port = port; 22 | this.tunnelFactory = tunnelFactory; 23 | this.databaseFactory = databaseFactory; 24 | } 25 | 26 | public void startServer() throws IOException { 27 | try (var server = new ServerSocket(port)) { 28 | Socket client = server.accept(); 29 | 30 | Tunnel tunnel = tunnelFactory.createTunnel(client); 31 | // Database database = databaseFactory.createDatabase(); 32 | createDatabase 33 | String message = tunnel.message(); 34 | 35 | System.out.println(message); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/Database.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface Database { 7 | } 8 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/DatabaseFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface DatabaseFactory { 7 | Database createDatabase(); 8 | } 9 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/Main.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import tunnel.Tunnel; 4 | 5 | import java.io.IOException; 6 | import java.net.Socket; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class Main { 12 | public static void main(String[] args) { 13 | ChatRoomServer server = new ChatRoomServer(8787, 14 | new SuperTunnelFactory(), 15 | new SuperDatabaseFactory()); 16 | } 17 | } 18 | 19 | class SuperTunnel implements Tunnel { 20 | 21 | @Override 22 | public String message() throws IOException { 23 | return null; 24 | } 25 | 26 | @Override 27 | public void disconnect() throws IOException { 28 | 29 | } 30 | } 31 | 32 | class SuperTunnelFactory implements TunnelFactory { 33 | @Override 34 | public Tunnel createTunnel(Socket client) { 35 | return new SuperTunnel(); 36 | } 37 | } 38 | 39 | class SuperDatabase implements Database { } 40 | 41 | class SuperDatabaseFactory implements DatabaseFactory { 42 | @Override 43 | public Database createDatabase() { 44 | return new SuperDatabase(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/TunnelFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import tunnel.Tunnel; 4 | 5 | import java.net.Socket; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public interface TunnelFactory { 11 | Tunnel createTunnel(Socket client); 12 | } 13 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-工廠方法/src/v3/WaterballTunnelFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import tunnel.Tunnel; 4 | import tunnel.WaterballTunnel; 5 | 6 | import java.net.Socket; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class WaterballTunnelFactory implements TunnelFactory { 12 | @Override 13 | public Tunnel createTunnel(Socket client) { 14 | return new WaterballTunnel(client); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/c5m3s1.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/requirement.md: -------------------------------------------------------------------------------- 1 | 你正在玩一個「知識王闖關爬塔遊戲」。 2 | 3 | 這一款藉由答對「知識問答」,就能夠往其他地區移動,或是找到傳送門往下一層樓爬,直到爬到頂樓就能通關的遊戲! 4 | 5 | 1. 遊戲開始之後,玩家會從「一樓」開始闖關,也就是 Floor-1。 6 | 2. 玩家每進入一個新的樓層,就會先踏入該樓層的初始地區 (access the initial region)。 7 | 3. 玩家進入每一個地區之後,都要受到「知識問答」的關卡挑戰 (play the stage),每一樓層都有專屬的題庫,依靠讀檔讀取: 8 | 1. 每個關卡都配有 3 題題目 (Question),每一題都有特定的答案 (Answer)。 9 | 2. 只要在三題中答對兩題,就能過關;反之若玩家答錯兩題,就會立刻被淘汰且遊戲結束 (Game Over)。 10 | 3. 每一次玩家通關,就會視機率在玩家所屬樓層中發生以下三件事其中一項: 11 | - 有 30% 機率:會先生成一個新地區,再生成一盞傳送門 (spawn a portal) 連接玩家目前所在地區與此生成地區之間。 12 | - 有 30% 機率:會生成一盞傳送門 (spawn a portal),連結隨機兩個地區之間。 13 | - 有 40% 機率會在一隨機地區中,生成通往下一樓層的傳送門。 14 | - 以上這些機率條件,都要遵守該樓層的限制: 15 | - 每一樓層可限制最多生成幾個地區。 16 | - 而每個地區最多只能連接四盞傳送門,如果傳送門的數量已滿導致不能生成新的傳送門,則會隨機破壞現有的傳送門。 17 | 4. 玩家通關後,接著可以選擇與所處地區相連的一道傳送門,玩家透過傳送門在地區間移動。 18 | 4. 每個傳送門最多都只能被使用「三次」,使用三次之後,傳送門就會從地區中被刪除。 19 | 5. 若玩家抵達頂樓(最高層),則會恭喜過關。 20 | 21 | - Variants: 22 | - 層: 23 | - 關卡: 24 | - 題庫 25 | - 題目種類 26 | - 通關條件 27 | - 傳送門的「傳送行為」 28 | 29 | - 生命週期限制/需要多個的實體: 30 | - 傳送門(因為有傳送次數上限,所以需要分別統計):傳送行為會疊加 31 | - 關卡(遇到才生):關卡中題目的讀取方式、題目答題時對答案的行為不同,有些題目是從網路上抓取,對答案也是通過網路,有些是本地 32 | - 地區(需要多個,承載傳送門):玩家進入地圖時行為疊加 (e.g., 下廣告之類的) 33 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v1/Game.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class Game { 6 | private Floor floor1; 7 | private boolean over = false; 8 | 9 | public void start() { 10 | Player player = new Player(); 11 | floor1.access(player); 12 | } 13 | 14 | public void over() { 15 | over = true; 16 | System.out.println("The game is over."); 17 | } 18 | 19 | public boolean isGameOver() { 20 | return over; 21 | } 22 | 23 | public void setFloor1(Floor floor1) { 24 | this.floor1 = floor1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v1/Main.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class Main { 6 | public static void main(String[] args) { 7 | Game game = new Game(); 8 | 9 | TopFloor topFloor = new TopFloor(game); // TopFloor extends Floor 10 | Floor f3 = new Floor(game, "Floor 3", topFloor); 11 | Floor f2 = new Floor(game, "Floor 2", f3); 12 | Floor f1 = new Floor(game, "Floor 1", f2); // the next floor 13 | 14 | game.setFloor1(f1); 15 | game.start(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v1/Portable.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public interface Portable { 6 | String getName(); 7 | void access(Player player); 8 | 9 | default void addPortal(Portal portal) { 10 | // default: do nothing 11 | } 12 | 13 | default void removePortal(Portal portal) { 14 | // default: do nothing 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v1/Question.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class Question { 6 | private final String description; 7 | private final String answer; 8 | 9 | public Question(String description, String answer) { 10 | this.description = description; 11 | this.answer = answer; 12 | } 13 | 14 | public boolean isCorrectAnswer(String answer) { 15 | return this.answer.equalsIgnoreCase(answer); 16 | } 17 | 18 | public String getDescription() { 19 | return description; 20 | } 21 | 22 | public String getAnswer() { 23 | return answer; 24 | } 25 | 26 | public void ask(int questionNumber) { 27 | System.out.printf("(%d) %s%nPlease answer: ", questionNumber, description); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v1/TopFloor.java: -------------------------------------------------------------------------------- 1 | package v1; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class TopFloor extends Floor { 6 | public TopFloor(Game game) { 7 | super(game, "Top Floor", null, 1); 8 | } 9 | 10 | @Override 11 | public void access(Player player) { 12 | System.out.println("You win this game! Congratulations!"); 13 | game.over(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Game.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Game { 7 | private Floor floor1; 8 | private boolean over = false; 9 | 10 | public void start() { 11 | Player player = new Player(); 12 | floor1.access(player); 13 | } 14 | 15 | public void over() { 16 | over = true; 17 | System.out.println("The game is over."); 18 | } 19 | 20 | public boolean isGameOver() { 21 | return over; 22 | } 23 | 24 | public void setFloor1(Floor floor1) { 25 | this.floor1 = floor1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Portable.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface Portable { 7 | String getName(); 8 | void access(Player player); 9 | 10 | default void addPortal(Portal portal) { 11 | // default: do nothing 12 | } 13 | 14 | default void removePortal(Portal portal) { 15 | // default: do nothing 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Portal.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface Portal { 7 | 8 | int id(); 9 | void access(Player player); 10 | 11 | Portable getTarget(Player player); 12 | 13 | void destroy(); 14 | } 15 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/PortalDecorator.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public abstract class PortalDecorator implements Portal { 9 | protected Portal next; 10 | 11 | public PortalDecorator(Portal next) { 12 | this.next = next; 13 | } 14 | 15 | @Override 16 | public Portable getTarget(Player player) { 17 | return next.getTarget(player); 18 | } 19 | 20 | @Override 21 | public void destroy() { 22 | next.destroy(); 23 | } 24 | 25 | @Override 26 | public int id() { 27 | return next.id(); 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | return next.equals(obj); 33 | } 34 | 35 | @Override 36 | public int hashCode() { 37 | return next.hashCode(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Question.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class Question { 6 | private final String description; 7 | private final String answer; 8 | 9 | public Question(String description, String answer) { 10 | this.description = description; 11 | this.answer = answer; 12 | } 13 | 14 | public boolean isCorrectAnswer(String answer) { 15 | return this.answer.equalsIgnoreCase(answer); 16 | } 17 | 18 | public String getDescription() { 19 | return description; 20 | } 21 | 22 | public String getAnswer() { 23 | return answer; 24 | } 25 | 26 | public void ask(int questionNumber) { 27 | System.out.printf("(%d) %s%nPlease answer: ", questionNumber, description); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Region.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public interface Region extends Portable { 9 | String getName(); 10 | 11 | void addPortal(Portal portal); 12 | 13 | void removePortal(Portal portal); 14 | 15 | boolean hasSpaceForMorePortals(); 16 | 17 | Collection getPortals(); 18 | 19 | int getNumber(); 20 | 21 | Floor getFloor(); 22 | } 23 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/RegionDecorator.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public abstract class RegionDecorator implements Region { 9 | protected Region next; 10 | 11 | public RegionDecorator(Region next) { 12 | this.next = next; 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return next.getName(); 18 | } 19 | 20 | @Override 21 | public void addPortal(Portal portal) { 22 | next.addPortal(portal); 23 | } 24 | 25 | @Override 26 | public void removePortal(Portal portal) { 27 | next.removePortal(portal); 28 | } 29 | 30 | @Override 31 | public boolean hasSpaceForMorePortals() { 32 | return next.hasSpaceForMorePortals(); 33 | } 34 | 35 | @Override 36 | public Collection getPortals() { 37 | return next.getPortals(); 38 | } 39 | 40 | @Override 41 | public int getNumber() { 42 | return next.getNumber(); 43 | } 44 | 45 | @Override 46 | public Floor getFloor() { 47 | return next.getFloor(); 48 | } 49 | 50 | @Override 51 | public boolean equals(Object obj) { 52 | return next.equals(obj); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return next.hashCode(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/Stage.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public abstract class Stage { 9 | protected int fails; 10 | 11 | public void play(Player player) { 12 | List questions = loadQuestions(); 13 | for (int i = 0; i < questions.size(); i++) { 14 | Question question = questions.get(i); 15 | question.ask(i + 1); 16 | String answer = player.answer(); 17 | if (question.isCorrectAnswer(answer)) { 18 | System.out.println("You are correct!"); 19 | } else { 20 | System.out.println("You are wrong!"); 21 | ++fails; 22 | if (failed()) { 23 | System.out.println("You lose the game!"); 24 | player.loseGame(); 25 | return; 26 | } 27 | } 28 | } 29 | System.out.println("You pass this stage!"); 30 | } 31 | 32 | protected abstract List loadQuestions(); 33 | 34 | 35 | public boolean failed() { 36 | return fails >= 2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/TopFloor.java: -------------------------------------------------------------------------------- 1 | package v2; 2 | 3 | import v2.factories.PortalFactory; 4 | import v2.factories.RegionFactory; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public class TopFloor extends Floor { 10 | 11 | public TopFloor(Game game, RegionFactory regionFactory, PortalFactory portalFactory) { 12 | super(game, "Top Floor", null, 1, regionFactory, portalFactory); 13 | } 14 | 15 | @Override 16 | public void access(Player player) { 17 | System.out.println("You win this game! Congratulations!"); 18 | game.over(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/defaults/BasePortalFactory.java: -------------------------------------------------------------------------------- 1 | package v2.defaults; 2 | 3 | import v2.BasePortal; 4 | import v2.Portable; 5 | import v2.Portal; 6 | import v2.factories.PortalFactory; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class BasePortalFactory implements PortalFactory { 12 | @Override 13 | public Portal createPortal(Portable p1, Portable p2) { 14 | return BasePortal.makePortal(p1, p2); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/defaults/BaseRegionFactory.java: -------------------------------------------------------------------------------- 1 | package v2.defaults; 2 | 3 | import v2.BaseRegion; 4 | import v2.Floor; 5 | import v2.Region; 6 | import v2.factories.StageFactory; 7 | import v2.factories.RegionFactory; 8 | 9 | /** 10 | * @author johnny@waterballsa.tw 11 | */ 12 | public class BaseRegionFactory implements RegionFactory { 13 | private final StageFactory stageFactory; 14 | 15 | public BaseRegionFactory(StageFactory stageFactory) { 16 | this.stageFactory = stageFactory; 17 | } 18 | 19 | @Override 20 | public Region createRegion(int number, Floor floor) { 21 | return new BaseRegion(number, floor, stageFactory); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/defaults/BaseStageFactory.java: -------------------------------------------------------------------------------- 1 | package v2.defaults; 2 | 3 | import v2.BaseStage; 4 | import v2.Question; 5 | import v2.Region; 6 | import v2.Stage; 7 | import v2.factories.StageFactory; 8 | 9 | /** 10 | * @author johnny@waterballsa.tw 11 | */ 12 | public class BaseStageFactory implements StageFactory { 13 | @Override 14 | public Stage createStage(Region region) { 15 | return new BaseStage(region); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/factories/PortalFactory.java: -------------------------------------------------------------------------------- 1 | package v2.factories; 2 | 3 | import v2.Portable; 4 | import v2.Portal; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public interface PortalFactory { 10 | Portal createPortal(Portable p1, Portable p2); 11 | } 12 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/factories/RegionFactory.java: -------------------------------------------------------------------------------- 1 | package v2.factories; 2 | 3 | import v2.Floor; 4 | import v2.Region; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public interface RegionFactory { 10 | Region createRegion(int number, Floor floor); 11 | } 12 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/factories/StageFactory.java: -------------------------------------------------------------------------------- 1 | package v2.factories; 2 | 3 | import v2.Region; 4 | import v2.Stage; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public interface StageFactory { 10 | Stage createStage(Region region); 11 | } 12 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperPortal.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.Player; 4 | import v2.Portal; 5 | import v2.PortalDecorator; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public class SuperPortal extends PortalDecorator { 11 | 12 | public SuperPortal(Portal next) { 13 | super(next); 14 | } 15 | 16 | @Override 17 | public void access(Player player) { 18 | System.out.println("<有機率打廣告>"); 19 | next.access(player); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperPortalFactory.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.BasePortal; 4 | import v2.Portable; 5 | import v2.Portal; 6 | import v2.factories.PortalFactory; 7 | 8 | /** 9 | * @author johnny@waterballsa.tw 10 | */ 11 | public class SuperPortalFactory implements PortalFactory { 12 | // 裝飾者模式 13 | @Override 14 | public Portal createPortal(Portable p1, Portable p2) { 15 | return new SuperPortal(BasePortal.makePortal(p1, p2)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperRegion.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.Player; 4 | import v2.Region; 5 | import v2.RegionDecorator; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public class SuperRegion extends RegionDecorator { 11 | 12 | public SuperRegion(Region next) { 13 | super(next); 14 | } 15 | 16 | @Override 17 | public void access(Player player) { 18 | System.out.println(""); 19 | next.access(player); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperRegionFactory.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.BaseRegion; 4 | import v2.Floor; 5 | import v2.Region; 6 | import v2.factories.StageFactory; 7 | import v2.factories.RegionFactory; 8 | 9 | /** 10 | * @author johnny@waterballsa.tw 11 | */ 12 | public class SuperRegionFactory implements RegionFactory { 13 | private final StageFactory stageFactory; 14 | 15 | public SuperRegionFactory(StageFactory stageFactory) { 16 | this.stageFactory = stageFactory; 17 | } 18 | 19 | @Override 20 | public Region createRegion(int number, Floor floor) { 21 | return new SuperRegion(new BaseRegion(number, floor, stageFactory)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperStage.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.Question; 4 | import v2.Stage; 5 | 6 | import java.util.List; 7 | 8 | import static java.util.Collections.emptyList; 9 | 10 | /** 11 | * @author johnny@waterballsa.tw 12 | */ 13 | public class SuperStage extends Stage { 14 | @Override 15 | protected List loadQuestions() { 16 | return loadQuestionViaAPI("https://super.intel.tw/api"); 17 | } 18 | 19 | protected List loadQuestionViaAPI(String api) { 20 | // 假裝是從小華服務的 API 中讀取 21 | if (api.equals("https://super.intel.tw/api")) { 22 | return List.of(new Question("水球潘院長幾歲?", "26"), 23 | new Question("小華智慧的理想是什麼?", "征服世界"), 24 | new Question("小華智慧最得意的作法是什麼?", "Super Crawler"), 25 | new Question("小華最喜歡的設計模式是什麼?", "Adapter Pattern") 26 | ); 27 | } 28 | return emptyList(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v2/thirdparty/SuperStageFactory.java: -------------------------------------------------------------------------------- 1 | package v2.thirdparty; 2 | 3 | import v2.Region; 4 | import v2.Stage; 5 | import v2.factories.StageFactory; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public class SuperStageFactory implements StageFactory { 11 | @Override 12 | public Stage createStage(Region region) { 13 | return new SuperStage(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Game.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class Game { 7 | private Floor floor1; 8 | private boolean over = false; 9 | 10 | public void start() { 11 | Player player = new Player(); 12 | floor1.access(player); 13 | } 14 | 15 | public void over() { 16 | over = true; 17 | System.out.println("The game is over."); 18 | } 19 | 20 | public boolean isGameOver() { 21 | return over; 22 | } 23 | 24 | public void setFloor1(Floor floor1) { 25 | this.floor1 = floor1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Main.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import v2.defaults.BasePortalFactory; 4 | import v2.defaults.BaseRegionFactory; 5 | import v2.defaults.BaseStageFactory; 6 | import v2.thirdparty.SuperPortalFactory; 7 | import v2.thirdparty.SuperRegionFactory; 8 | import v2.thirdparty.SuperStageFactory; 9 | import v3.defaults.BaseFloorAbstractFactory; 10 | import v3.factories.FloorAbstractFactory; 11 | import v3.thirdparty.SuperFloorAbstractFactory; 12 | 13 | /** 14 | * @author johnny@waterballsa.tw 15 | */ 16 | public class Main { 17 | public static void main(String[] args) { 18 | Game game = new Game(); 19 | FloorAbstractFactory baseFactory = new BaseFloorAbstractFactory(); 20 | FloorAbstractFactory superFactory = new SuperFloorAbstractFactory(); 21 | 22 | TopFloor topFloor = new TopFloor(game, baseFactory); 23 | Floor f3 = new Floor(game, "Super Floor 3", topFloor, superFactory); 24 | Floor f2 = new Floor(game, "Super Floor 2", f3, superFactory); 25 | Floor f1 = new Floor(game, "Floor 1", f2, baseFactory); 26 | 27 | game.setFloor1(f1); 28 | game.start(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Portable.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface Portable { 7 | String getName(); 8 | void access(Player player); 9 | 10 | default void addPortal(Portal portal) { 11 | // default: do nothing 12 | } 13 | 14 | default void removePortal(Portal portal) { 15 | // default: do nothing 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Portal.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface Portal { 7 | 8 | int id(); 9 | void access(Player player); 10 | 11 | Portable getTarget(Player player); 12 | 13 | void destroy(); 14 | } 15 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/PortalDecorator.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public abstract class PortalDecorator implements Portal { 7 | protected Portal next; 8 | 9 | public PortalDecorator(Portal next) { 10 | this.next = next; 11 | } 12 | 13 | @Override 14 | public Portable getTarget(Player player) { 15 | return next.getTarget(player); 16 | } 17 | 18 | @Override 19 | public void destroy() { 20 | next.destroy(); 21 | } 22 | 23 | @Override 24 | public int id() { 25 | return next.id(); 26 | } 27 | 28 | @Override 29 | public boolean equals(Object obj) { 30 | return next.equals(obj); 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return next.hashCode(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/PortalFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface PortalFactory { 7 | Portal createPortal(Portable p1, Portable p2); 8 | } 9 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Question.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | /** 3 | * @author johnny@waterballsa.tw 4 | */ 5 | public class Question { 6 | private final String description; 7 | private final String answer; 8 | 9 | public Question(String description, String answer) { 10 | this.description = description; 11 | this.answer = answer; 12 | } 13 | 14 | public boolean isCorrectAnswer(String answer) { 15 | return this.answer.equalsIgnoreCase(answer); 16 | } 17 | 18 | public String getDescription() { 19 | return description; 20 | } 21 | 22 | public String getAnswer() { 23 | return answer; 24 | } 25 | 26 | public void ask(int questionNumber) { 27 | System.out.printf("(%d) %s%nPlease answer: ", questionNumber, description); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Region.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public interface Region extends Portable { 9 | String getName(); 10 | 11 | void addPortal(Portal portal); 12 | 13 | void removePortal(Portal portal); 14 | 15 | boolean hasSpaceForMorePortals(); 16 | 17 | Collection getPortals(); 18 | 19 | int getNumber(); 20 | 21 | Floor getFloor(); 22 | } 23 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/RegionFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface RegionFactory { 7 | Region createRegion(int number, Floor floor); 8 | } 9 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/Stage.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public abstract class Stage { 9 | protected int fails; 10 | 11 | public void play(Player player) { 12 | List questions = loadQuestions(); 13 | for (int i = 0; i < questions.size(); i++) { 14 | Question question = questions.get(i); 15 | question.ask(i + 1); 16 | String answer = player.answer(); 17 | if (question.isCorrectAnswer(answer)) { 18 | System.out.println("You are correct!"); 19 | } else { 20 | System.out.println("You are wrong!"); 21 | ++fails; 22 | if (failed()) { 23 | System.out.println("You lose the game!"); 24 | player.loseGame(); 25 | return; 26 | } 27 | } 28 | } 29 | System.out.println("You pass this stage!"); 30 | } 31 | 32 | protected abstract List loadQuestions(); 33 | 34 | 35 | public boolean failed() { 36 | return fails >= 2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/StageFactory.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public interface StageFactory { 7 | Stage createStage(Region region); 8 | } 9 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/SuperPortal.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class SuperPortal extends PortalDecorator { 7 | 8 | public SuperPortal(Portal next) { 9 | super(next); 10 | } 11 | 12 | @Override 13 | public void access(Player player) { 14 | System.out.println("<有機率打廣告>"); 15 | next.access(player); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/SuperRegion.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | /** 4 | * @author johnny@waterballsa.tw 5 | */ 6 | public class SuperRegion extends RegionDecorator { 7 | 8 | public SuperRegion(Region next) { 9 | super(next); 10 | } 11 | 12 | @Override 13 | public void access(Player player) { 14 | System.out.println(""); 15 | next.access(player); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/SuperStage.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import java.util.List; 4 | 5 | import static java.util.Collections.emptyList; 6 | 7 | /** 8 | * @author johnny@waterballsa.tw 9 | */ 10 | public class SuperStage extends Stage { 11 | @Override 12 | protected List loadQuestions() { 13 | return loadQuestionViaAPI("https://super.intel.tw/api"); 14 | } 15 | 16 | protected List loadQuestionViaAPI(String api) { 17 | // 假裝是從小華服務的 API 中讀取 18 | if (api.equals("https://super.intel.tw/api")) { 19 | return List.of(new Question("水球潘院長幾歲?", "26"), 20 | new Question("小華智慧的理想是什麼?", "征服世界"), 21 | new Question("小華智慧最得意的作法是什麼?", "Super Crawler"), 22 | new Question("小華最喜歡的設計模式是什麼?", "Adapter Pattern") 23 | ); 24 | } 25 | return emptyList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/TopFloor.java: -------------------------------------------------------------------------------- 1 | package v3; 2 | 3 | import v3.factories.FloorAbstractFactory; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class TopFloor extends Floor { 9 | 10 | public TopFloor(Game game, FloorAbstractFactory factory) { 11 | super(game, "Top Floor", null, 1, factory); 12 | } 13 | 14 | @Override 15 | public void access(Player player) { 16 | System.out.println("You win this game! Congratulations!"); 17 | game.over(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/defaults/BaseFloorAbstractFactory.java: -------------------------------------------------------------------------------- 1 | package v3.defaults; 2 | 3 | import v3.*; 4 | import v3.factories.FloorAbstractFactory; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public class BaseFloorAbstractFactory implements FloorAbstractFactory { 10 | 11 | @Override 12 | public Portal createPortal(Portable p1, Portable p2) { 13 | return BasePortal.makePortal(p1, p2); 14 | } 15 | 16 | @Override 17 | public Region createRegion(int number, Floor floor) { 18 | return new BaseRegion(number, floor); 19 | } 20 | 21 | @Override 22 | public Stage createStage(Region region) { 23 | return new BaseStage(region); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/factories/FloorAbstractFactory.java: -------------------------------------------------------------------------------- 1 | package v3.factories; 2 | 3 | import v3.*; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public interface FloorAbstractFactory { 9 | Portal createPortal(Portable p1, Portable p2); 10 | Region createRegion(int number, Floor floor); 11 | Stage createStage(Region region); 12 | } 13 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/thirdparty/SuperFloorAbstractFactory.java: -------------------------------------------------------------------------------- 1 | package v3.thirdparty; 2 | 3 | import v3.*; 4 | import v3.factories.FloorAbstractFactory; 5 | 6 | /** 7 | * @author johnny@waterballsa.tw 8 | */ 9 | public class SuperFloorAbstractFactory implements FloorAbstractFactory { 10 | @Override 11 | public Portal createPortal(Portable p1, Portable p2) { 12 | return new SuperPortal(BasePortal.makePortal(p1, p2)); 13 | } 14 | 15 | @Override 16 | public Region createRegion(int number, Floor floor) { 17 | return new SuperRegion(new BaseRegion(number, floor)); 18 | } 19 | 20 | @Override 21 | public Stage createStage(Region region) { 22 | return new SuperStage(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/thirdparty/SuperPortal.java: -------------------------------------------------------------------------------- 1 | package v3.thirdparty; 2 | 3 | import v3.*; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class SuperPortal extends PortalDecorator { 9 | 10 | public SuperPortal(Portal next) { 11 | super(next); 12 | } 13 | 14 | @Override 15 | public void access(Player player) { 16 | System.out.println("<有機率打廣告>"); 17 | next.access(player); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/thirdparty/SuperRegion.java: -------------------------------------------------------------------------------- 1 | package v3.thirdparty; 2 | 3 | import v3.*; 4 | 5 | /** 6 | * @author johnny@waterballsa.tw 7 | */ 8 | public class SuperRegion extends RegionDecorator { 9 | 10 | public SuperRegion(Region next) { 11 | super(next); 12 | } 13 | 14 | @Override 15 | public void access(Player player) { 16 | System.out.println(""); 17 | next.access(player); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c5-生命週期及控制反轉/景點-抽象工廠/v3/thirdparty/SuperStage.java: -------------------------------------------------------------------------------- 1 | package v3.thirdparty; 2 | 3 | import v3.*; 4 | 5 | import java.util.List; 6 | 7 | import static java.util.Collections.emptyList; 8 | 9 | /** 10 | * @author johnny@waterballsa.tw 11 | */ 12 | public class SuperStage extends Stage { 13 | @Override 14 | protected List loadQuestions() { 15 | return loadQuestionViaAPI("https://super.intel.tw/api"); 16 | } 17 | 18 | protected List loadQuestionViaAPI(String api) { 19 | // 假裝是從小華服務的 API 中讀取 20 | if (api.equals("https://super.intel.tw/api")) { 21 | return List.of(new Question("水球潘院長幾歲?", "26"), 22 | new Question("小華智慧的理想是什麼?", "征服世界"), 23 | new Question("小華智慧最得意的作法是什麼?", "Super Crawler"), 24 | new Question("小華最喜歡的設計模式是什麼?", "Adapter Pattern") 25 | ); 26 | } 27 | return emptyList(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /wsa-design-pattern.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | --------------------------------------------------------------------------------