-
Notifications
You must be signed in to change notification settings - Fork 0
Homework Submission for OOP & POP Programming #1
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,313 @@ | ||
import UIKit | ||
|
||
// MARK: - Exercise 1: Social Media Post | ||
|
||
class Post { | ||
var author: String | ||
var content: String | ||
var likes: Int | ||
|
||
init(author: String, content: String, likes: Int = 0) { | ||
self.author = author | ||
self.content = content | ||
self.likes = likes | ||
} | ||
|
||
func display() { | ||
print("Post by \(author):") | ||
print("\"\(content)\"") | ||
print("Likes: \(likes)") | ||
print(String(repeating: "-", count: 30)) // Separator line for better readability | ||
} | ||
} | ||
|
||
// MARK: - Main program functionality | ||
|
||
func main() { | ||
// Create first post | ||
let post1 = Post(author: "Alice", content: "Just finished my first iOS assignment!", likes: 15) | ||
|
||
// Create second post | ||
let post2 = Post(author: "Bob", content: "Learning Swift classes is fun!", likes: 7) | ||
|
||
// Display both posts | ||
post1.display() | ||
post2.display() | ||
} | ||
|
||
// Calling the main function | ||
main() | ||
|
||
|
||
// MARK: - Exercise 2: Using the Singleton Pattern to create a more flexible shopping cart system | ||
|
||
// Product Class | ||
class Product { | ||
let name: String | ||
let price: Double | ||
var quantity: Int | ||
|
||
init(name: String, price: Double, quantity: Int = 1) { | ||
self.name = name | ||
self.price = price | ||
self.quantity = quantity | ||
} | ||
} | ||
|
||
//MARK: - DiscountStrategy Protocol and Implementations | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like seeing that you are experimenting with the concepts you are learning. |
||
|
||
protocol DiscountStrategy { | ||
func calculateDiscount(total: Double) -> Double | ||
} | ||
|
||
class NoDiscountStrategy: DiscountStrategy { | ||
func calculateDiscount(total: Double) -> Double { | ||
return 0.0 // No discount | ||
} | ||
} | ||
|
||
class PercentageDiscountStrategy: DiscountStrategy { | ||
let percentage: Double | ||
|
||
init(percentage: Double) { | ||
self.percentage = min(percentage, 100.0) // Ensure discount doesn't exceed 100% | ||
} | ||
|
||
func calculateDiscount(total: Double) -> Double { | ||
return total * (percentage / 100.0) | ||
} | ||
} | ||
|
||
//MARK: - ShoppingCartSingleton Class | ||
|
||
class ShoppingCartSingleton { | ||
// Static property for the singleton instance | ||
private static var instance: ShoppingCartSingleton? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are using Xcode 16, you may have received the error: Static property 'instance' is not concurrency-safe because it is nonisolated global shared mutable state. Swift 6 introduced strict concurrency checking so this error will not be present on an older version of Xcode. With this error, the compiler is trying to communicate that Static mutable properties are generally unsafe because they can be concurrently modified from any thread/actor. Will go over concurrency later in the course, for now since instance is only accessed by the ShoppingCartSingleton class we can add nonisolated(unsafe) to the definition.
|
||
|
||
// Private array to store products (composition) | ||
private var products: [Product] = [] | ||
|
||
// Discount strategy | ||
var discountStrategy: DiscountStrategy = NoDiscountStrategy() | ||
|
||
// Private initializer to enforce singleton pattern | ||
private init() {} | ||
|
||
// Method to access the singleton instance | ||
static func sharedInstance() -> ShoppingCartSingleton { | ||
if instance == nil { | ||
instance = ShoppingCartSingleton() | ||
} | ||
return instance! | ||
} | ||
|
||
// Method to add a product to the cart | ||
func addProduct(product: Product, quantity: Int = 1) { | ||
// Check if the product is already in the cart | ||
if let index = products.firstIndex(where: { $0.name == product.name }) { | ||
// If it is, update the quantity | ||
products[index].quantity += quantity | ||
} else { | ||
// If not, add the product with the specified quantity | ||
let newProduct = Product(name: product.name, price: product.price, quantity: quantity) | ||
products.append(newProduct) | ||
} | ||
} | ||
|
||
// Method to remove a product from the cart | ||
func removeProduct(product: Product) { | ||
products.removeAll { $0.name == product.name } | ||
} | ||
|
||
// Method to clear the cart | ||
func clearCart() { | ||
products.removeAll() | ||
} | ||
|
||
// Method to calculate the total price | ||
func getTotalPrice() -> Double { | ||
let subtotal = products.reduce(0.0) { $0 + ($1.price * Double($1.quantity)) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excellent use of higher order methods! |
||
let discount = discountStrategy.calculateDiscount(total: subtotal) | ||
return subtotal - discount | ||
} | ||
|
||
// Helper method to display cart contents | ||
func displayCart() { | ||
if products.isEmpty { | ||
print("Shopping cart is empty.") | ||
return | ||
} | ||
|
||
print("Shopping Cart Contents:") | ||
print("------------------------") | ||
for product in products { | ||
print("\(product.name) - $\(product.price) x \(product.quantity) = $\(product.price * Double(product.quantity))") | ||
} | ||
|
||
let subtotal = products.reduce(0.0) { $0 + ($1.price * Double($1.quantity)) } | ||
let discount = discountStrategy.calculateDiscount(total: subtotal) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you use the getTotalPrice() method instead? |
||
|
||
print("------------------------") | ||
print("Subtotal: $\(subtotal)") | ||
print("Discount: $\(discount)") | ||
print("Total: $\(getTotalPrice())") | ||
print("------------------------") | ||
} | ||
} | ||
|
||
//MARK: - Example Usage | ||
|
||
func mainexample() { | ||
// Singleton pattern to shopping cart instance | ||
let cart = ShoppingCartSingleton.sharedInstance() | ||
|
||
// Example product creation | ||
let laptop = Product(name: "Laptop", price: 1299.99) | ||
let phone = Product(name: "Smartphone", price: 599.99) | ||
let charger = Product(name: "USB-C Charger", price: 19.99) | ||
|
||
// Adding products to the cart | ||
cart.addProduct(product: laptop) | ||
cart.addProduct(product: phone, quantity: 2) | ||
cart.addProduct(product: charger, quantity: 3) | ||
|
||
// Displaying the cart with no discount | ||
print("Cart with no discount:") | ||
cart.displayCart() | ||
|
||
// Applying a 10% discount | ||
cart.discountStrategy = PercentageDiscountStrategy(percentage: 10.0) | ||
print("\nCart with 10% discount:") | ||
cart.displayCart() | ||
|
||
// Removing a product | ||
cart.removeProduct(product: phone) | ||
print("\nCart after removing smartphones:") | ||
cart.displayCart() | ||
|
||
// Clearing the cart | ||
cart.clearCart() | ||
print("\nCart after clearing:") | ||
cart.displayCart() | ||
} | ||
|
||
// Running the example usage | ||
main() | ||
|
||
// MARK: - Exercise 3: Payment System Model & Custom Error Type for Payment Processing | ||
|
||
enum PaymentError: Error { | ||
case insufficientFunds | ||
case invalidCard | ||
case cardExpired | ||
case networkError | ||
case paymentLimitExceeded | ||
case cashRegisterEmpty | ||
|
||
var message: String { | ||
switch self { | ||
case .insufficientFunds: | ||
return "Insufficient funds to complete the transaction." | ||
case .invalidCard: | ||
return "The card information is invalid." | ||
case .cardExpired: | ||
return "The card has expired." | ||
case .networkError: | ||
return "Network error occurred during payment processing." | ||
case .paymentLimitExceeded: | ||
return "The payment amount exceeds the allowed limit." | ||
case .cashRegisterEmpty: | ||
return "Cash register is empty and cannot provide change." | ||
} | ||
} | ||
} | ||
|
||
// MARK: - Payment Processor Protocol | ||
|
||
protocol PaymentProcessor { | ||
func processPayment(amount: Double) throws | ||
var name: String { get } | ||
} | ||
|
||
// MARK: - Credit Card Processor | ||
|
||
class CreditCardProcessor: PaymentProcessor { | ||
let name = "Credit Card" | ||
private let cardNumber: String | ||
private let expiryDate: String | ||
private let cvv: String | ||
private let balance: Double | ||
|
||
init(cardNumber: String, expiryDate: String, cvv: String, balance: Double) { | ||
self.cardNumber = cardNumber | ||
self.expiryDate = expiryDate | ||
self.cvv = cvv | ||
self.balance = balance | ||
} | ||
|
||
func processPayment(amount: Double) throws { | ||
// Validate the amount | ||
if amount <= 0 { | ||
throw PaymentError.invalidCard | ||
} | ||
|
||
// Check for payment limits | ||
if amount > 10000 { | ||
throw PaymentError.paymentLimitExceeded | ||
} | ||
|
||
// Simulate card validation | ||
if cardNumber.count != 16 { | ||
throw PaymentError.invalidCard | ||
} | ||
|
||
// Simulate expiry date check (very basic simulation) | ||
if expiryDate == "01/20" { | ||
throw PaymentError.cardExpired | ||
} | ||
|
||
// Check for sufficient funds | ||
if amount > balance { | ||
throw PaymentError.insufficientFunds | ||
} | ||
|
||
// Simulate random network error (10% chance) | ||
if Double.random(in: 0...1) < 0.1 { | ||
throw PaymentError.networkError | ||
} | ||
|
||
// If we reach here, payment is successful | ||
print("Credit card payment of $\(amount) processed successfully.") | ||
} | ||
} | ||
|
||
// MARK: - Cash Processor | ||
|
||
class CashProcessor: PaymentProcessor { | ||
let name = "Cash" | ||
private var cashInRegister: Double | ||
|
||
init(cashInRegister: Double) { | ||
self.cashInRegister = cashInRegister | ||
} | ||
|
||
func processPayment(amount: Double) throws { | ||
// Validating the amount | ||
if amount <= 0 { | ||
throw PaymentError.invalidCard // Reusing error for simplicity | ||
} | ||
|
||
// Check if providing change is possible | ||
if cashInRegister < amount { | ||
throw PaymentError.cashRegisterEmpty | ||
} | ||
|
||
// Processing payment | ||
cashInRegister -= amount | ||
|
||
// If below messages display, payment is successful | ||
print("Cash payment of $\(amount) processed successfully.") | ||
print("Remaining cash in register: $\(cashInRegister)") | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You missed adding the code to try processing payments with different processors and handle potential errors using try-catch blocks. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<playground version='7.0' target-platform='ios' swift-version='6' buildActiveScheme='true' importAppTypes='true'/> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many languages require some form of entry point to be defined that instructs the compiler where execution should start. That is not the case with Swift, especially in Playgrounds. In Playground execution, always start at the top of the file and continue line by line until the end of the file. Lines 27 through 35 do not need to be wrapped in a function. This applies to the "main functions" below as well.