Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strategy pattern lesson fixes + other minor fixes #61

Merged
merged 7 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
id: 1583020778
id: 205367361
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ class Store {
}
}
}

fun main() {
val store = Store()
println(store.calculateTotalPrice(listOf(1, 2, 3))) // Output: Sum of prices
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
type: edu
custom_name: Inline Method and variables
custom_name: Inline methods and variables
files:
- name: src/main/kotlin/jetbrains/refactoring/course/inlining/Task.kt
visible: true
placeholders:
- offset: 113
length: 265
placeholder_text: |-
fun calculateTotalPrice(productPrice: List<Int>): Int? {
return try {
val totalPrice = productPrice.sum()
totalPrice
} catch (error: Exception) {
logError(error, "Exception.txt")
null
}
}

private fun logError(error: Exception, filePath: String) {
val file = File(filePath)
val text = error
PrintWriter(file, Charsets.UTF_8).use { it.print(text) }
}
- name: test/Tests.kt
visible: false
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Task 2/2: Inline methods and variables

### Task

In this task, you need to identify unnecessary variables and method and inline them using the automatic Inline
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package jetbrains.refactoring.course.inlining

fun main() {
// Write your solution here
}

This file was deleted.

2 changes: 1 addition & 1 deletion InliningCode/InlineMethodRefactoring/Theory/task-info.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
type: theory
custom_name: Inline Method refactoring
files:
- name: src/main/kotlin/jetbrains/refactoring/course/inlining/Task.kt
- name: src/main/kotlin/jetbrains/refactoring/course/inlining/Main.kt
visible: true
2 changes: 2 additions & 0 deletions InliningCode/InlineMethodRefactoring/Theory/task.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Task 1/2: Inline Method refactoring

Apply the Inline Method refactoring when a method's behavior is simple and its purpose is clear, but it is called from only one place.
If the method has become redundant or does not add significant value, it can be safely inlined.

Expand Down
4 changes: 1 addition & 3 deletions InliningCode/InlineMethodRefactoring/lesson-info.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
type: framework
custom_name: Inline Method refactoring
custom_name: What is Inline Method refactoring?
content:
- Theory
- InlineMethodAndVariables
is_template_based: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package jetbrains.refactoring.course.inlining

import java.io.File
import java.io.FileNotFoundException

class FileReader {
fun readFileContent(path: String): String {
if (!File(path).exists()) {
throw FileNotFoundException("File not found at path: $path")
}
return File(path).readText()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type: edu
custom_name: Practice
files:
- name: test/Tests.kt
visible: false
- name: src/main/kotlin/jetbrains/refactoring/course/inlining/Task.kt
visible: true
placeholders:
- offset: 128
length: 205
placeholder_text: |-
fun readFileContent(path: String): String {
val fileExists = File(path).exists()
if (!fileExists) {
throw FileNotFoundException("File not found at path: $path")
}
val content = File(path).readText()
return content
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Task 2/2: What is Inline Variable refactoring?

In this task, you need to identify unnecessary variables and inline them using the automatic Inline
refactoring.

### Hints

<div class="hint" title="Shortcut for Inline refactoring">
To apply the Inline refactoring, select the code you want to inline and press the &shortcut:Inline; (macOS) or
Ctrl+Alt+N (Windows/Linux) shortcut.
</div>

<div class="hint" title="Refactoring hint">

The variables `fileExists` and `content` in the method `readFileContent()` are redundant and could be inlined.

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import org.jetbrains.academy.test.system.test.BaseIjTestClass
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeAll
import java.io.File

class InliningVariableTest : BaseIjTestClass() {

companion object {

private lateinit var sourceText: String

@JvmStatic
@BeforeAll
fun initialize() {
val taskDirectoryPath = System.getProperty("user.dir")
val sourceCodeFile =
File("$taskDirectoryPath/src/main/kotlin/jetbrains/refactoring/course/inlining/Task.kt")
sourceText = sourceCodeFile.readText()
}
}

@Test
fun testVariablesInlined() {
setUp()
myFixture.configureByText("Task.kt", sourceText)
Assertions.assertFalse(hasProperty("fileExists")) {
"Please, identify unnecessary variables"
}
Assertions.assertFalse(hasProperty("content")) {
"Please, identify unnecessary variables"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Task 1/1: What is Inline Variable refactoring?
# Task 1/2: What is Inline Variable refactoring?

We apply the **Inline refactoring** to simplify code by removing an unnecessary method or variable declarations and directly
replacing them with their respective expressions or values.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
custom_name: What is Inline Variable refactoring?
content:
- Theory
- Theory
- InlineVariables
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package jetbrains.refactoring.course.patterns

import java.time.LocalDate

fun main() {
val order1 = Order(100.0, "CreditCard")
val order2 = Order(50.0, "PayPal")
val order3 = Order(200.0, "Bitcoin")
val order1 = Order(100.0, LocalDate.of(2023, 3, 1), "CreditCard")
val order2 = Order(50.0, LocalDate.of(2023, 6, 1), "PayPal")
val order3 = Order(200.0, LocalDate.of(2023, 9, 1), "Bitcoin")

order1.processPayment()
order2.processPayment()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package jetbrains.refactoring.course.patterns

class Order(val totalAmount: Double, val paymentMethod: String) {
import java.time.LocalDate

class Order(val totalAmount: Double, val date: LocalDate, val paymentMethod: String) {
fun processPayment() {
when (paymentMethod) {
"CreditCard" -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import jetbrains.refactoring.course.patterns.processor.PaymentProcessor
import jetbrains.refactoring.course.patterns.strategy.BitcoinPayment
import jetbrains.refactoring.course.patterns.strategy.CreditCardPayment
import jetbrains.refactoring.course.patterns.strategy.PayPalPayment
import java.time.LocalDate

fun main() {
val order1 = Order(100.0, LocalDate.of(2023, 3, 1))
val order2 = Order(50.0, LocalDate.of(2023, 6, 1))
val order3 = Order(200.0, LocalDate.of(2023, 9, 1))

val creditCardPayment = PaymentProcessor(CreditCardPayment())
val paypalPayment = PaymentProcessor(PayPalPayment())
val bitcoinPayment = PaymentProcessor(BitcoinPayment())

creditCardPayment.processOrderPayment(100.0)
paypalPayment.processOrderPayment(50.0)
bitcoinPayment.processOrderPayment(200.0)
creditCardPayment.processOrderPayment(order1.totalAmount)
paypalPayment.processOrderPayment(order2.totalAmount)
bitcoinPayment.processOrderPayment(order3.totalAmount)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package jetbrains.refactoring.course.patterns

// The Order class is no longer necessary
class Order(val totalAmount: Double)
import java.time.LocalDate

data class Order(val totalAmount: Double, val date: LocalDate)
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ files:
visible: false
- name: test/PaymentProcessorClass.kt
visible: false
- name: test/OrderClass.kt
visible: false
15 changes: 9 additions & 6 deletions RefactoringToDesignPatterns/StrategyPatternPractice/Task/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
- Create a `PaymentProcessor` class that encapsulates the payment behavior.
This class should take as a constructor parameter `paymentStrategy: PaymentStrategy`
and should contain the `processOrderPayment` method, which invokes the `processPayment` method from `paymentStrategy`.
- Within the `Main::main` method, for every payment type, instantiate a `PaymentProcessor`. Ensure you pass the
corresponding payment strategy during the object's creation.
- Transform the `Order` class into a `data class` that encapsulates details regarding the order's price and date.
- Within the `Main::main` method, instantiate an `Order` object for each order and a `PaymentProcessor` for each payment type.
Make sure to pass the corresponding payment strategy when creating the `PaymentProcessor` object.

By using the **Strategy** design pattern, the payment processing logic is separated from the `Order` class,
making it more flexible and maintainable.
Expand Down Expand Up @@ -51,13 +52,15 @@ class CreditCardPayment : PaymentStrategy {

<div class="hint" title="How to fix main method?">

In the main method, you should instantiate a `PaymentProcessor` object and provide the appropriate payment strategy as
an
argument. For instance, for a credit card payment type, the code would be:
In the main method, **for each order**, you should instantiate an `Order` object, providing it with the corresponding total amount and date.
Then, you need to instantiate a `PaymentProcessor` object, supplying it with the appropriate payment strategy as an argument.
Finally, you should invoke the `processOrderPayment()` method.
For example, the code for processing a payment with a credit card would be:

```kotlin
val order1 = Order(100.0, LocalDate.of(2023, 3, 1))
val creditCardPayment = PaymentProcessor(CreditCardPayment())
creditCardPayment.processOrderPayment(100.0)
creditCardPayment.processOrderPayment(order1.totalAmount)
```

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import org.jetbrains.academy.test.system.core.models.Visibility
import org.jetbrains.academy.test.system.core.models.classes.ClassType
import org.jetbrains.academy.test.system.core.models.classes.TestClass
import org.jetbrains.academy.test.system.core.models.variable.TestVariable
import org.jetbrains.academy.test.system.core.models.variable.VariableMutability

internal val orderClass = TestClass(
"Order",
classPackage = "jetbrains.refactoring.course.patterns",
classType = ClassType.CLASS,
declaredFields = listOf(
TestVariable(
name = "totalAmount",
javaType = "Double",
mutability = VariableMutability.VAL,
visibility = Visibility.PUBLIC,
),
TestVariable(
name = "date",
javaType = "LocalDate",
mutability = VariableMutability.VAL,
visibility = Visibility.PUBLIC,
)
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ class StrategyPatternTest : BaseIjTestClass() {
)
}

@Test
fun orderClassTest() {
Assertions.assertDoesNotThrow(
{
val clazz = orderClass.checkBaseDefinition()
orderClass.checkFieldsDefinition(clazz)
},
"Please, create a data class Order with two fields: totalAmount: Double," +
"and date: LocalDate"
)
}

@Test
fun testCreatedInstancesInMainMethod() {
setUp()
Expand All @@ -91,26 +103,26 @@ class StrategyPatternTest : BaseIjTestClass() {
fun testInvokedMethodsOfPaymentClassesInMainMethod() {
setUp()
myFixture.configureByText("Main.kt", sourceText)
var method = "processOrderPayment(100.0)"
var method = "processOrderPayment(order1.totalAmount)"
Assertions.assertEquals(
findMethodUsages(method),
listOf("main")
) {
"Please, invoke the $method method of Credit Card Payment in the main method"
"Please, invoke the $method method of Credit Card Payment and pass in the totalAmount from the first order within the main method"
}
method = "processOrderPayment(50.0)"
method = "processOrderPayment(order2.totalAmount)"
Assertions.assertEquals(
findMethodUsages(method),
listOf("main")
) {
"Please, invoke the $method method of PayPal Payment in the main method"
"Please, invoke the $method method of PayPal Payment and pass in the totalAmount from the second order within the main method"
}
method = "processOrderPayment(200.0)"
method = "processOrderPayment(order3.totalAmount)"
Assertions.assertEquals(
findMethodUsages(method),
listOf("main")
) {
"Please, invoke the $method method of Bitcoin Payment in the main method"
"Please, invoke the $method method of Bitcoin Payment and pass in the totalAmount from the third order within the main method"
}
}
}
Loading