Skip to content

Kapitel 8: Entwurfsmuster

Kevin Wiesner edited this page Jun 7, 2024 · 5 revisions

Zwei Entwurfsmuster

Zwei unterschiedliche Entwurfsmuster aus der Vorlesung (oder nach Absprache auch andere) jeweils sinnvoll einsetzen, begründen und UML-Diagramm

Entwurfsmuster: Factory Method

Im Rahmen von QuizClash werden vier verschiedene UI-Elemente eingesetzt, welche für eine Darstellung in der CLI (oder auch irgendwo anders) verwendet werden können. Dazu gehören die Folgenden:

  • Eingabe von Text (TextInputScreen)
  • Eingabe von Nummern (NumberInputScreen)
  • Auswahl aus einer Liste von Optionen (OptionScreen)
  • Darstellung von reinen Text-Informationen (InformationScreen)

Sie erben dabei alle von dem Screen Basistyp (abstrakte Klasse), sodass alle Subtypen einheitliche Grundfunktionen besitzen.

Um die Application-Schicht von der Darstellung zu entkoppeln, wird das Factory Method Design Pattern eingesetzt, um in der Application-Schicht eine Factory verwenden zu können, um den benötigten Screen zu erstellen. Dabei ist es für die Application-Schicht nicht von Relevanz, welche konkrete Implementierung des ScreenFactory Interfaces bei Start der Anwendung in die Application-Schicht gegeben wird. Im Falle der derzeitigen CLI Anwendung besteht eine CLIScreenFactory Implementierung in der Plugin-Cli-Schicht, welche zusätzlich Implementierungen für die abstrakten Screen-Typen liefert (CLITextInputScreen, etc.). Bei einer möglichen zukünftigen Änderung der Anforderung an die UI könnten neue Implementierungen für die ScreenFactory und die abstrakten Screen-Typen geliefert werden, eine Änderung in der Application-Schicht wäre nicht notwendig.

classDiagram
direction BT
class CLIInformationScreen {
  + CLIInformationScreen(String, List~String~, boolean, CLIWindowManager) 
  + CLIInformationScreen(String, List~String~, CLIWindowManager) 
  ~ CLIWindowManager cliWindow
  + render() void
}
class CLINumberInputScreen {
  + CLINumberInputScreen(String, String, CLIWindowManager) 
  - CLIWindowManager cliWindow
  - int userInput
  + render() void
  + getNumberInput() Action~Integer~
}
class CLIOptionScreen {
  + CLIOptionScreen(String, List~Displayable~, CLIWindowManager) 
  - CLIWindowManager cliWindow
  - int userOption
  - selectFromOptions(List~Displayable~) int
  + render() void
  + getOptionInput() Action~Integer~
}
class CLIScreenFactory {
  + CLIScreenFactory(CLIWindowManager) 
  ~ CLIWindowManager cliWindow
  + createNumberInputScreen(String, String) NumberInputScreen
  + createOptionScreen(String, List~Displayable~) OptionScreen
  + createInformationScreen(String, List~String~, boolean) InformationScreen
  + createTextInputScreen(String, String) TextInputScreen
  + createInformationScreen(String, List~String~) InformationScreen
}
class CLITextInputScreen {
  + CLITextInputScreen(String, String, CLIWindowManager) 
  - CLIWindowManager cliWindow
  - String userInput
  + render() void
  + getTextInput() Action~String~
}
class InformationScreen {
  + InformationScreen(String, List~String~) 
  + InformationScreen(String, List~String~, boolean) 
  - List~String~ lines
  - boolean isBlocking
  + getLines() List~String~
  + isBlocking() boolean
}
class NumberInputScreen {
  + NumberInputScreen(String, String) 
  - String inputRequest
  + getNumberInput() Action~Integer~
  + getInputRequest() String
}
class OptionScreen {
  + OptionScreen(String, List~Displayable~) 
  - List~Displayable~ displayableList
  + getScreenOptions() List~Displayable~
  + getOptionInput() Action~Integer~
}
class Screen {
  + Screen(String) 
  - String screenName
  + getScreenName() String
  + render() void
}
class ScreenFactory {
<<Interface>>
  + createTextInputScreen(String, String) TextInputScreen
  + createInformationScreen(String, List~String~) InformationScreen
  + createInformationScreen(String, List~String~, boolean) InformationScreen
  + createNumberInputScreen(String, String) NumberInputScreen
  + createOptionScreen(String, List~Displayable~) OptionScreen
}
class TextInputScreen {
  + TextInputScreen(String, String) 
  - String inputRequest
  + getTextInput() Action~String~
  + getInputRequest() String
}

CLIInformationScreen  -->  InformationScreen 
CLINumberInputScreen  -->  NumberInputScreen 
CLIOptionScreen  -->  OptionScreen 
CLIScreenFactory  ..>  CLIInformationScreen : «create»
CLIScreenFactory  ..>  CLINumberInputScreen : «create»
CLIScreenFactory  ..>  CLIOptionScreen : «create»
CLIScreenFactory  ..>  CLITextInputScreen : «create»
CLIScreenFactory  ..>  ScreenFactory 
CLITextInputScreen  -->  TextInputScreen 
InformationScreen  -->  Screen 
NumberInputScreen  -->  Screen 
OptionScreen  -->  Screen 
TextInputScreen  -->  Screen 
Loading

Entwurfsmuster: Builder

Im Rahmen des JSON-Parsings der Spiel-Kategorien (inklusive Fragen und Antwortmöglichkeiten) wird das Builder Pattern verwendet, um Elemente vom Typ Category, Question und QuestionOption zu erstellen. Dazu sind die Klassen CategoryBuilder, QuestionBuilder und QuestionOptionBuilder vorhanden. Da in dem JSON die einzelnen Elemente ineinander verschachtelt sind (Fragen haben feste Antwortmöglichkeiten und sind einer Kategorie fest zugeordnet), können diese nicht in einem Schritt erstellt werden. Um die Entwicklung daher besser zu strukturieren, wurde das Builder Pattern eingesetzt.

classDiagram
direction BT
class Category {
  + Category(int, String, Question[]) 
  - int id
  - String categoryName
  - Question[] questions
  + getDisplayName() String
  + getQuestions() Question[]
  + getCategoryName() String
  + getRandomQuestion() Question
  + getId() int
}
class CategoryBuilder {
  + CategoryBuilder() 
  - int id
  - String categoryName
  - List~Question~ questions
  + setId(int) CategoryBuilder
  + addQuestion(Question) CategoryBuilder
  + build() Category
  + setCategoryName(String) CategoryBuilder
}
class JSONCategoryParser {
  + JSONCategoryParser() 
  - parseCategory(JSONObject, boolean) Category
  - parseQuestionOption(JSONObject) QuestionOption
  + parseFromJSONArray(JSONArray, boolean) Category[]
  - parseQuestion(JSONObject, boolean) Question
}
class Question {
  + Question(int, String, QuestionOption[], boolean) 
  + Question(int, String, QuestionOption[]) 
  - int id
  - String question
  - QuestionOption[] questionOptions
  + checkAnswer(int) boolean
  + getQuestion() String
  + getId() int
  + getQuestionOptions() QuestionOption[]
}
class QuestionBuilder {
  + QuestionBuilder() 
  - String question
  - List~QuestionOption~ questionOptions
  - int id
  - boolean shuffle
  + setQuestion(String) QuestionBuilder
  + build() Question
  + setQuestionShuffling(boolean) QuestionBuilder
  + setId(int) QuestionBuilder
  + addQuestionOption(QuestionOption) QuestionBuilder
}
class QuestionOption {
  + QuestionOption(String, boolean) 
  - boolean isRight
  - String questionOption
  + getDisplayName() String
  + isRight() boolean
  + getQuestionOption() String
}
class QuestionOptionBuilder {
  + QuestionOptionBuilder() 
  - String questionOption
  - boolean isRight
  + build() QuestionOption
  + setQuestionOption(String) QuestionOptionBuilder
  + setIsRight(boolean) QuestionOptionBuilder
}

Category "1" *--> "questions *" Question 
CategoryBuilder  ..>  Category : «create»
CategoryBuilder  ..>  Question : «create»
CategoryBuilder "1" *--> "questions *" Question 
JSONCategoryParser  ..>  Category : «create»
JSONCategoryParser  ..>  CategoryBuilder : «create»
JSONCategoryParser  ..>  QuestionBuilder : «create»
JSONCategoryParser  ..>  QuestionOptionBuilder : «create»
Question "1" *--> "questionOptions *" QuestionOption 
Question  ..>  QuestionOption : «create»
QuestionBuilder  ..>  Question : «create»
QuestionBuilder "1" *--> "questionOptions *" QuestionOption 
QuestionBuilder  ..>  QuestionOption : «create»
QuestionOptionBuilder  ..>  QuestionOption : «create»
Loading