Repository: ashishps1/awesome-low-level-design Branch: main Commit: fc26e4033cad Files: 2758 Total size: 2.8 MB Directory structure: gitextract_z31mpvc2/ ├── .gitignore ├── LICENSE ├── README.md ├── design-patterns/ │ ├── Javascript/ │ │ ├── Behavioral Pattern/ │ │ │ ├── Chain of Responsibilites/ │ │ │ │ ├── main.js │ │ │ │ └── supportRequest.js │ │ │ ├── Command Design Pattern/ │ │ │ │ ├── command.js │ │ │ │ ├── invoker.js │ │ │ │ ├── main.js │ │ │ │ └── receiver.js │ │ │ ├── Iterator Design Pattern/ │ │ │ │ ├── aggregate.js │ │ │ │ ├── book.js │ │ │ │ ├── iterator.js │ │ │ │ └── main.js │ │ │ ├── Mediator Design Pattern/ │ │ │ │ ├── main.js │ │ │ │ ├── mediator.js │ │ │ │ └── user.js │ │ │ ├── Memento Design Pattern/ │ │ │ │ ├── Example2/ │ │ │ │ │ ├── canvas.js │ │ │ │ │ ├── careTaker.js │ │ │ │ │ ├── main.js │ │ │ │ │ └── memento.js │ │ │ │ ├── careTaker.js │ │ │ │ ├── main.js │ │ │ │ ├── memento.js │ │ │ │ └── orginator.js │ │ │ ├── Observer Design Pattern/ │ │ │ │ ├── main.js │ │ │ │ ├── observer.js │ │ │ │ └── publisher.js │ │ │ ├── State Design Pattern/ │ │ │ │ ├── context.js │ │ │ │ ├── main.js │ │ │ │ └── state.js │ │ │ ├── Strategy Design Pattern/ │ │ │ │ ├── main.js │ │ │ │ ├── paymentStrategy.js │ │ │ │ └── shoppingCart_Context.js │ │ │ ├── Template Design Pattern/ │ │ │ │ ├── beverages.js │ │ │ │ ├── beveragesTypes.js │ │ │ │ └── main.js │ │ │ └── Visitor Design Pattern/ │ │ │ ├── element.js │ │ │ ├── main.js │ │ │ └── visitor.js │ │ ├── Creational Pattern/ │ │ │ ├── AbstractFactory Design Pattern/ │ │ │ │ ├── abstract.js │ │ │ │ └── main.js │ │ │ ├── Builder Design Pattern/ │ │ │ │ ├── app.js │ │ │ │ └── computerBuilder.js │ │ │ ├── Factory Design Pattern/ │ │ │ │ ├── factory.js │ │ │ │ ├── main.js │ │ │ │ └── pizza.js │ │ │ ├── Prototype Design Pattern/ │ │ │ │ └── app.js │ │ │ └── Singleton Design Pattern/ │ │ │ ├── app.js │ │ │ └── singleton.js │ │ └── Structural Pattern/ │ │ ├── Adapter Design Pattern/ │ │ │ ├── adapter.js │ │ │ ├── main.js │ │ │ ├── usbA_connector.js │ │ │ └── usbC_device.js │ │ ├── Bridge Design Pattern/ │ │ │ ├── device.js │ │ │ ├── main.js │ │ │ └── remoteControl.js │ │ ├── Composite Design Pattern/ │ │ │ ├── app.js │ │ │ ├── component.js │ │ │ ├── file.js │ │ │ └── folder.js │ │ ├── Decorator Design Pattern/ │ │ │ ├── additional.js │ │ │ ├── coffee.js │ │ │ └── main.js │ │ ├── Facade Design Pattern/ │ │ │ ├── dvdPlayer.js │ │ │ ├── lights.js │ │ │ ├── main.js │ │ │ ├── movieFacade.js │ │ │ ├── projector.js │ │ │ ├── snacks.js │ │ │ └── soundSystem.js │ │ ├── Flyweight Design Pattern/ │ │ │ ├── circle.js │ │ │ ├── circleFactory.js │ │ │ └── main.js │ │ └── Proxy Design Pattern/ │ │ ├── main.js │ │ ├── proxyImage.js │ │ └── real_Image.js │ ├── cpp/ │ │ ├── adapter/ │ │ │ ├── in_house_payment_processor.cpp │ │ │ ├── in_house_payment_processor.h │ │ │ ├── legacy_gateway.cpp │ │ │ ├── legacy_gateway.h │ │ │ ├── legacy_gateway_adapter.cpp │ │ │ ├── legacy_gateway_adapter.h │ │ │ ├── main.cpp │ │ │ └── payment_processor.h │ │ ├── bridge/ │ │ │ ├── circle.cpp │ │ │ ├── circle.h │ │ │ ├── main.cpp │ │ │ ├── raster_renderer.cpp │ │ │ ├── raster_renderer.h │ │ │ ├── rectangle.cpp │ │ │ ├── rectangle.h │ │ │ ├── renderer.h │ │ │ ├── shape.cpp │ │ │ ├── shape.h │ │ │ ├── vector_renderer.cpp │ │ │ └── vector_renderer.h │ │ ├── builder/ │ │ │ ├── http_request.cpp │ │ │ ├── http_request.h │ │ │ ├── http_request_builder.cpp │ │ │ ├── http_request_builder.h │ │ │ └── main.cpp │ │ ├── chainofresponsibility/ │ │ │ ├── auth_handler.h │ │ │ ├── authorization_handler.h │ │ │ ├── base_handler.cpp │ │ │ ├── base_handler.h │ │ │ ├── business_logic_handler.h │ │ │ ├── main.cpp │ │ │ ├── rate_limit_handler.h │ │ │ ├── request.cpp │ │ │ ├── request.h │ │ │ ├── request_handler.h │ │ │ └── validation_handler.h │ │ ├── composite/ │ │ │ ├── file.cpp │ │ │ ├── file.h │ │ │ ├── file_system_item.h │ │ │ ├── folder.cpp │ │ │ ├── folder.h │ │ │ └── main.cpp │ │ ├── decorator/ │ │ │ ├── bold_decorator.cpp │ │ │ ├── bold_decorator.h │ │ │ ├── italic_decorator.cpp │ │ │ ├── italic_decorator.h │ │ │ ├── main.cpp │ │ │ ├── plain_text_view.cpp │ │ │ ├── plain_text_view.h │ │ │ ├── text_decorator.cpp │ │ │ ├── text_decorator.h │ │ │ ├── text_view.h │ │ │ ├── underline_decorator.cpp │ │ │ └── underline_decorator.h │ │ ├── facade/ │ │ │ ├── build_system.cpp │ │ │ ├── build_system.h │ │ │ ├── deployment_facade.cpp │ │ │ ├── deployment_facade.h │ │ │ ├── deployment_target.cpp │ │ │ ├── deployment_target.h │ │ │ ├── main.cpp │ │ │ ├── testing_framework.cpp │ │ │ ├── testing_framework.h │ │ │ ├── version_control_system.cpp │ │ │ └── version_control_system.h │ │ ├── factory/ │ │ │ ├── CMakeLists.txt │ │ │ ├── email_notification.cpp │ │ │ ├── email_notification.h │ │ │ ├── main.cpp │ │ │ ├── notification.h │ │ │ ├── notification_factory.cpp │ │ │ ├── notification_factory.h │ │ │ ├── push_notification.cpp │ │ │ ├── push_notification.h │ │ │ ├── sms_notification.cpp │ │ │ └── sms_notification.h │ │ ├── flyweight/ │ │ │ ├── circle.cpp │ │ │ ├── circle.h │ │ │ ├── main.cpp │ │ │ ├── shape.h │ │ │ ├── shape_factory.cpp │ │ │ └── shape_factory.h │ │ ├── iterator/ │ │ │ ├── container.h │ │ │ ├── iterator.h │ │ │ ├── main.cpp │ │ │ ├── name_iterator.cpp │ │ │ ├── name_iterator.h │ │ │ ├── name_repository.cpp │ │ │ └── name_repository.h │ │ ├── mediator/ │ │ │ ├── button.cpp │ │ │ ├── button.h │ │ │ ├── form_mediator.cpp │ │ │ ├── form_mediator.h │ │ │ ├── label.cpp │ │ │ ├── label.h │ │ │ ├── main.cpp │ │ │ ├── text_field.cpp │ │ │ ├── text_field.h │ │ │ ├── ui_component.cpp │ │ │ ├── ui_component.h │ │ │ └── ui_mediator.h │ │ ├── memento/ │ │ │ ├── main.cpp │ │ │ ├── text_editor.cpp │ │ │ ├── text_editor.h │ │ │ ├── text_editor_memento.cpp │ │ │ ├── text_editor_memento.h │ │ │ ├── text_editor_undo_manager.cpp │ │ │ └── text_editor_undo_manager.h │ │ ├── observer/ │ │ │ ├── fitness_data.cpp │ │ │ ├── fitness_data.h │ │ │ ├── fitness_data_observer.h │ │ │ ├── fitness_data_subject.h │ │ │ ├── goal_notifier.cpp │ │ │ ├── goal_notifier.h │ │ │ ├── live_activity_display.cpp │ │ │ ├── live_activity_display.h │ │ │ ├── main.cpp │ │ │ ├── progress_logger.cpp │ │ │ └── progress_logger.h │ │ ├── prototype/ │ │ │ ├── enemy.cpp │ │ │ ├── enemy.h │ │ │ ├── enemy_prototype.h │ │ │ ├── enemy_registry.cpp │ │ │ ├── enemy_registry.h │ │ │ └── main.cpp │ │ ├── proxy/ │ │ │ ├── CMakeLists.txt │ │ │ ├── high_resolution_image.cpp │ │ │ ├── high_resolution_image.h │ │ │ ├── image.h │ │ │ ├── image_gallery_app_v1.cpp │ │ │ ├── image_gallery_app_v2.cpp │ │ │ ├── image_proxy.cpp │ │ │ └── image_proxy.h │ │ ├── singleton/ │ │ │ ├── double_checked_singleton.cpp │ │ │ ├── double_checked_singleton.h │ │ │ ├── eager_singleton.cpp │ │ │ ├── eager_singleton.h │ │ │ ├── lazy_singleton.cpp │ │ │ ├── lazy_singleton.h │ │ │ ├── main.cpp │ │ │ ├── thread_safe_singleton.cpp │ │ │ └── thread_safe_singleton.h │ │ ├── state/ │ │ │ ├── dispensing_state.cpp │ │ │ ├── dispensing_state.h │ │ │ ├── has_money_state.cpp │ │ │ ├── has_money_state.h │ │ │ ├── idle_state.cpp │ │ │ ├── idle_state.h │ │ │ ├── item_selected_state.cpp │ │ │ ├── item_selected_state.h │ │ │ ├── machine_state.h │ │ │ ├── main.cpp │ │ │ ├── vending_machine.cpp │ │ │ └── vending_machine.h │ │ ├── strategy/ │ │ │ ├── distance_based_shipping.cpp │ │ │ ├── distance_based_shipping.h │ │ │ ├── ecommerce_app.cpp │ │ │ ├── flat_rate_shipping.cpp │ │ │ ├── flat_rate_shipping.h │ │ │ ├── order.h │ │ │ ├── shipping_cost_service.cpp │ │ │ ├── shipping_cost_service.h │ │ │ ├── shipping_strategy.h │ │ │ ├── third_party_api_shipping.cpp │ │ │ ├── third_party_api_shipping.h │ │ │ ├── weight_based_shipping.cpp │ │ │ └── weight_based_shipping.h │ │ └── templatemethod/ │ │ ├── CMakeLists.txt │ │ ├── abstract_report_exporter.cpp │ │ ├── abstract_report_exporter.h │ │ ├── csv_report_exporter.cpp │ │ ├── csv_report_exporter.h │ │ ├── excel_report_exporter.cpp │ │ ├── excel_report_exporter.h │ │ ├── pdf_report_exporter.cpp │ │ ├── pdf_report_exporter.h │ │ ├── report_app.cpp │ │ ├── report_data.cpp │ │ └── report_data.h │ ├── csharp/ │ │ ├── adapter/ │ │ │ ├── CheckoutService.cs │ │ │ ├── IPaymentProcessor.cs │ │ │ ├── InHousePaymentProcessor.cs │ │ │ ├── LegacyGateway.cs │ │ │ ├── LegacyGatewayAdapter.cs │ │ │ └── Program.cs │ │ ├── bridge/ │ │ │ ├── Circle.cs │ │ │ ├── IRenderer.cs │ │ │ ├── Program.cs │ │ │ ├── RasterRenderer.cs │ │ │ ├── Rectangle.cs │ │ │ ├── Shape.cs │ │ │ └── VectorRenderer.cs │ │ ├── builder/ │ │ │ ├── HttpRequest.cs │ │ │ └── Program.cs │ │ ├── chainofresponsibility/ │ │ │ ├── AuthHandler.cs │ │ │ ├── AuthorizationHandler.cs │ │ │ ├── BaseHandler.cs │ │ │ ├── BusinessLogicHandler.cs │ │ │ ├── IRequestHandler.cs │ │ │ ├── Program.cs │ │ │ ├── RateLimitHandler.cs │ │ │ ├── Request.cs │ │ │ └── ValidationHandler.cs │ │ ├── composite/ │ │ │ ├── File.cs │ │ │ ├── Folder.cs │ │ │ ├── IFileSystemItem.cs │ │ │ └── Program.cs │ │ ├── decorator/ │ │ │ ├── BoldDecorator.cs │ │ │ ├── ITextView.cs │ │ │ ├── ItalicDecorator.cs │ │ │ ├── PlainTextView.cs │ │ │ ├── Program.cs │ │ │ ├── TextDecorator.cs │ │ │ └── UnderlineDecorator.cs │ │ ├── facade/ │ │ │ ├── BuildSystem.cs │ │ │ ├── DeploymentFacade.cs │ │ │ ├── DeploymentTarget.cs │ │ │ ├── Program.cs │ │ │ ├── TestingFramework.cs │ │ │ └── VersionControlSystem.cs │ │ ├── factory/ │ │ │ ├── EmailNotification.cs │ │ │ ├── INotification.cs │ │ │ ├── NotificationServiceNaive.cs │ │ │ ├── Program.cs │ │ │ ├── PushNotification.cs │ │ │ ├── SMSNotification.cs │ │ │ └── SimpleNotificationFactory.cs │ │ ├── flyweight/ │ │ │ ├── CharacterFlyweightFactory.cs │ │ │ ├── CharacterGlyph.cs │ │ │ ├── ICharacterFlyweight.cs │ │ │ ├── Program.cs │ │ │ └── TextEditorClient.cs │ │ ├── iterator/ │ │ │ ├── IIterableCollection.cs │ │ │ ├── IIterator.cs │ │ │ ├── Playlist.cs │ │ │ ├── PlaylistIterator.cs │ │ │ └── Program.cs │ │ ├── mediator/ │ │ │ ├── Button.cs │ │ │ ├── FormMediator.cs │ │ │ ├── IUIMediator.cs │ │ │ ├── Label.cs │ │ │ ├── Program.cs │ │ │ ├── TextField.cs │ │ │ └── UIComponent.cs │ │ ├── memento/ │ │ │ ├── Program.cs │ │ │ ├── TextEditor.cs │ │ │ ├── TextEditorMemento.cs │ │ │ └── TextEditorUndoManager.cs │ │ ├── observer/ │ │ │ ├── FitnessData.cs │ │ │ ├── GoalNotifier.cs │ │ │ ├── IFitnessDataObserver.cs │ │ │ ├── IFitnessDataSubject.cs │ │ │ ├── LiveActivityDisplay.cs │ │ │ ├── Program.cs │ │ │ └── ProgressLogger.cs │ │ ├── prototype/ │ │ │ ├── Enemy.cs │ │ │ ├── EnemyRegistry.cs │ │ │ ├── Game.cs │ │ │ └── IEnemyPrototype.cs │ │ ├── proxy/ │ │ │ ├── HighResolutionImage.cs │ │ │ ├── IImage.cs │ │ │ ├── ImageGalleryApp.cs │ │ │ └── ImageProxy.cs │ │ ├── singleton/ │ │ │ ├── BillPughSingleton.cs │ │ │ ├── DoubleCheckedLockingSingleton.cs │ │ │ ├── EagerSingleton.cs │ │ │ ├── LazySingleton.cs │ │ │ ├── SingletonDemo.cs │ │ │ ├── StaticBlockSingleton.cs │ │ │ └── ThreadSafeSingleton.cs │ │ ├── state/ │ │ │ ├── DispensingState.cs │ │ │ ├── HasMoneyState.cs │ │ │ ├── IMachineState.cs │ │ │ ├── IdleState.cs │ │ │ ├── ItemSelectedState.cs │ │ │ ├── Program.cs │ │ │ └── VendingMachine.cs │ │ ├── strategy/ │ │ │ ├── DistanceBasedShipping.cs │ │ │ ├── FlatRateShipping.cs │ │ │ ├── IShippingStrategy.cs │ │ │ ├── Order.cs │ │ │ ├── Program.cs │ │ │ ├── ShippingCostService.cs │ │ │ ├── ThirdPartyApiShipping.cs │ │ │ └── WeightBasedShipping.cs │ │ └── templatemethod/ │ │ ├── AbstractReportExporter.cs │ │ ├── CsvReportExporter.cs │ │ ├── ExcelReportExporter.cs │ │ ├── PdfReportExporter.cs │ │ ├── Program.cs │ │ └── ReportData.cs │ ├── golang/ │ │ ├── adapter/ │ │ │ ├── checkout_service.go │ │ │ ├── go.mod │ │ │ ├── in_house_payment_processor.go │ │ │ ├── legacy_gateway.go │ │ │ ├── legacy_gateway_adapter.go │ │ │ ├── main.go │ │ │ └── payment_processor.go │ │ ├── bridge/ │ │ │ ├── circle.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── raster_renderer.go │ │ │ ├── rectangle.go │ │ │ ├── renderer.go │ │ │ ├── shape.go │ │ │ └── vector_renderer.go │ │ ├── builder/ │ │ │ ├── go.mod │ │ │ ├── http_request.go │ │ │ ├── http_request_builder.go │ │ │ └── main.go │ │ ├── chainofresponsibility/ │ │ │ ├── authentication_handler.go │ │ │ ├── authorization_handler.go │ │ │ ├── base_handler.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── request.go │ │ │ ├── request_handler.go │ │ │ └── validation_handler.go │ │ ├── composite/ │ │ │ ├── file.go │ │ │ ├── file_system_item.go │ │ │ ├── folder.go │ │ │ ├── go.mod │ │ │ └── main.go │ │ ├── decorator/ │ │ │ ├── beverage.go │ │ │ ├── beverage_decorator.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── milk_decorator.go │ │ │ ├── simple_coffee.go │ │ │ └── sugar_decorator.go │ │ ├── facade/ │ │ │ ├── build_system.go │ │ │ ├── deployment_facade.go │ │ │ ├── deployment_target.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── testing_framework.go │ │ │ └── version_control_system.go │ │ ├── factory/ │ │ │ ├── email_notification.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── notification.go │ │ │ ├── push_notification.go │ │ │ ├── simple_notification_factory.go │ │ │ └── sms_notification.go │ │ ├── flyweight/ │ │ │ ├── character_flyweight.go │ │ │ ├── character_flyweight_factory.go │ │ │ ├── character_glyph.go │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ └── text_editor_client.go │ │ ├── iterator/ │ │ │ ├── book.go │ │ │ ├── book_collection.go │ │ │ ├── collection.go │ │ │ ├── go.mod │ │ │ ├── iterator.go │ │ │ └── main.go │ │ ├── mediator/ │ │ │ ├── chat_mediator.go │ │ │ ├── colleague.go │ │ │ ├── main.go │ │ │ ├── mediator.go │ │ │ └── user.go │ │ ├── memento/ │ │ │ ├── go.mod │ │ │ ├── main.go │ │ │ ├── text_editor.go │ │ │ ├── text_editor_memento.go │ │ │ └── text_editor_undo_manager.go │ │ ├── observer/ │ │ │ ├── fitness_data.go │ │ │ ├── fitness_data_observer.go │ │ │ ├── fitness_data_subject.go │ │ │ ├── go.mod │ │ │ ├── goal_notifier.go │ │ │ ├── live_activity_display.go │ │ │ ├── main.go │ │ │ └── progress_logger.go │ │ ├── prototype/ │ │ │ ├── enemy.go │ │ │ ├── enemy_prototype.go │ │ │ ├── enemy_registry.go │ │ │ ├── go.mod │ │ │ └── main.go │ │ ├── proxy/ │ │ │ ├── go.mod │ │ │ ├── high_resolution_image.go │ │ │ ├── image.go │ │ │ ├── image_proxy.go │ │ │ └── main.go │ │ ├── singleton/ │ │ │ ├── double_checked_singleton.go │ │ │ ├── eager_singleton.go │ │ │ ├── go.mod │ │ │ ├── lazy_singleton.go │ │ │ ├── main.go │ │ │ └── thread_safe_singleton.go │ │ ├── state/ │ │ │ ├── go.mod │ │ │ ├── has_money_state.go │ │ │ ├── idle_state.go │ │ │ ├── item_selected_state.go │ │ │ ├── machine_state.go │ │ │ ├── main.go │ │ │ └── vending_machine.go │ │ ├── strategy/ │ │ │ ├── credit_card_payment.go │ │ │ ├── main.go │ │ │ ├── payment_strategy.go │ │ │ ├── paypal_payment.go │ │ │ └── shopping_cart.go │ │ └── templatemethod/ │ │ ├── csv_data_processor.go │ │ ├── data_processor.go │ │ ├── main.go │ │ └── xml_data_processor.go │ ├── java/ │ │ ├── abstractfactory/ │ │ │ ├── AppLauncher.java │ │ │ ├── Application.java │ │ │ ├── Button.java │ │ │ ├── Checkbox.java │ │ │ ├── GUIFactory.java │ │ │ ├── MacOSButton.java │ │ │ ├── MacOSCheckbox.java │ │ │ ├── MacOSFactory.java │ │ │ ├── WindowsButton.java │ │ │ ├── WindowsCheckbox.java │ │ │ ├── WindowsFactory.java │ │ │ └── shoefactory/ │ │ │ ├── BumpySole.java │ │ │ ├── CasualShoeFactory.java │ │ │ ├── FlatSole.java │ │ │ ├── FormalShoeFactory.java │ │ │ ├── RoundShoeLace.java │ │ │ ├── Shoe.java │ │ │ ├── ShoeFactory.java │ │ │ ├── ShoeLace.java │ │ │ ├── ShoeManufacture.java │ │ │ ├── Sole.java │ │ │ ├── SportsShoeFactory.java │ │ │ ├── TapeShoeLace.java │ │ │ └── ThinSole.java │ │ ├── adapter/ │ │ │ ├── CheckoutService.java │ │ │ ├── ECommerceAppV1.java │ │ │ ├── ECommerceAppV2.java │ │ │ ├── InHousePaymentProcessor.java │ │ │ ├── LegacyGateway.java │ │ │ ├── LegacyGatewayAdapter.java │ │ │ └── PaymentProcessor.java │ │ ├── bridge/ │ │ │ ├── BridgeDemo.java │ │ │ ├── Circle.java │ │ │ ├── RasterRenderer.java │ │ │ ├── Rectangle.java │ │ │ ├── Renderer.java │ │ │ ├── Shape.java │ │ │ └── VectorRenderer.java │ │ ├── builder/ │ │ │ ├── HttpAppBuilder.java │ │ │ ├── HttpAppTelescoping.java │ │ │ ├── HttpRequest.java │ │ │ └── HttpRequestTelescoping.java │ │ ├── chainofresponsibility/ │ │ │ ├── AuthHandler.java │ │ │ ├── AuthorizationHandler.java │ │ │ ├── BaseHandler.java │ │ │ ├── BusinessLogicHandler.java │ │ │ ├── RateLimitHandler.java │ │ │ ├── Request.java │ │ │ ├── RequestHandler.java │ │ │ ├── RequestHandlerV1.java │ │ │ ├── RequestHandlerV2.java │ │ │ └── ValidationHandler.java │ │ ├── command/ │ │ │ ├── Command.java │ │ │ ├── CommandPatternDemo.java │ │ │ ├── Light.java │ │ │ ├── LightOffCommand.java │ │ │ ├── LightOnCommand.java │ │ │ ├── SetTemperatureCommand.java │ │ │ ├── SmartButton.java │ │ │ └── Thermostat.java │ │ ├── composite/ │ │ │ ├── filesystem/ │ │ │ │ ├── File.java │ │ │ │ ├── FileExplorerApp.java │ │ │ │ ├── FileSystemItem.java │ │ │ │ └── Folder.java │ │ │ └── organization/ │ │ │ ├── CompositeDemo.java │ │ │ ├── Designer.java │ │ │ ├── Developer.java │ │ │ ├── Employee.java │ │ │ └── Manager.java │ │ ├── decorator/ │ │ │ ├── BoldDecorator.java │ │ │ ├── DecoratorDemo.java │ │ │ ├── ItalicDecorator.java │ │ │ ├── PlainTextView.java │ │ │ ├── TextDecorator.java │ │ │ ├── TextView.java │ │ │ ├── UnderlineDecorator.java │ │ │ └── coffee/ │ │ │ ├── Coffee.java │ │ │ ├── CoffeeDecorator.java │ │ │ ├── DecoratorDemo.java │ │ │ ├── Milk.java │ │ │ ├── SimpleCoffee.java │ │ │ └── Sugar.java │ │ ├── facade/ │ │ │ ├── BuildSystem.java │ │ │ ├── DeploymentAppDirect.java │ │ │ ├── DeploymentAppFacade.java │ │ │ ├── DeploymentFacade.java │ │ │ ├── DeploymentOrchestrator.java │ │ │ ├── DeploymentTarget.java │ │ │ ├── TestingFramework.java │ │ │ └── VersionControlSystem.java │ │ ├── factory/ │ │ │ ├── notification/ │ │ │ │ ├── EmailNotification.java │ │ │ │ ├── EmailNotificationCreator.java │ │ │ │ ├── FactoryMethodDemo.java │ │ │ │ ├── Notification.java │ │ │ │ ├── NotificationCreator.java │ │ │ │ ├── NotificationServiceNaive.java │ │ │ │ ├── PushNotification.java │ │ │ │ ├── PushNotificationCreator.java │ │ │ │ ├── SMSNotification.java │ │ │ │ ├── SMSNotificationCreator.java │ │ │ │ └── SimpleNotificationFactory.java │ │ │ └── subscription/ │ │ │ ├── Customer.java │ │ │ ├── DataBase.java │ │ │ ├── FactoryApplication.java │ │ │ ├── Gold.java │ │ │ ├── Platinum.java │ │ │ ├── RoyalGold.java │ │ │ ├── Silver.java │ │ │ ├── Subscription.java │ │ │ └── SubscriptionFactory.java │ │ ├── flyweight/ │ │ │ ├── CharacterFlyweight.java │ │ │ ├── CharacterFlyweightFactory.java │ │ │ ├── CharacterGlyph.java │ │ │ ├── FlyweightDemo.java │ │ │ └── TextEditorClient.java │ │ ├── iterator/ │ │ │ ├── IterableCollection.java │ │ │ ├── Iterator.java │ │ │ ├── MusicPlayer.java │ │ │ ├── Playlist.java │ │ │ ├── PlaylistIterator.java │ │ │ └── books/ │ │ │ ├── Book.java │ │ │ ├── BookShelf.java │ │ │ ├── Container.java │ │ │ ├── Iterator.java │ │ │ └── IteratorDemo.java │ │ ├── mediator/ │ │ │ ├── Button.java │ │ │ ├── FormMediator.java │ │ │ ├── Label.java │ │ │ ├── MediatorApp.java │ │ │ ├── TextField.java │ │ │ ├── UIComponent.java │ │ │ └── UIMediator.java │ │ ├── memento/ │ │ │ ├── TextEditor.java │ │ │ ├── TextEditorMemento.java │ │ │ ├── TextEditorNaive.java │ │ │ ├── TextEditorUndoManager.java │ │ │ ├── TextEditorUndoV1.java │ │ │ └── TextEditorUndoV2.java │ │ ├── observer/ │ │ │ ├── FitnessAppNaiveClient.java │ │ │ ├── FitnessAppObserverDemo.java │ │ │ ├── FitnessData.java │ │ │ ├── FitnessDataNaive.java │ │ │ ├── FitnessDataObserver.java │ │ │ ├── FitnessDataSubject.java │ │ │ ├── GoalNotifier.java │ │ │ ├── LiveActivityDisplay.java │ │ │ ├── LiveActivityDisplayNaive.java │ │ │ ├── NotificationServiceNaive.java │ │ │ ├── ProgressLogger.java │ │ │ └── ProgressLoggerNaive.java │ │ ├── prototype/ │ │ │ ├── Enemy.java │ │ │ ├── EnemyPrototype.java │ │ │ ├── EnemyRegistry.java │ │ │ └── Game.java │ │ ├── proxy/ │ │ │ ├── HighResolutionImage.java │ │ │ ├── Image.java │ │ │ ├── ImageGalleryAppV1.java │ │ │ ├── ImageGalleryAppV2.java │ │ │ └── ImageProxy.java │ │ ├── singleton/ │ │ │ ├── BillPughSingleton.java │ │ │ ├── DoubleCheckedLockingSingleton.java │ │ │ ├── EagerSingleton.java │ │ │ ├── EnumSingleton.java │ │ │ ├── LazySingleton.java │ │ │ ├── StaticBlockSingleton.java │ │ │ └── ThreadSafeSingleton.java │ │ ├── state/ │ │ │ ├── DispensingState.java │ │ │ ├── HasMoneyState.java │ │ │ ├── IdleState.java │ │ │ ├── ItemSelectedState.java │ │ │ ├── MachineState.java │ │ │ ├── VendingMachine.java │ │ │ ├── VendingMachineApp.java │ │ │ └── VendingMachineNaive.java │ │ ├── strategy/ │ │ │ ├── DistanceBasedShipping.java │ │ │ ├── ECommerceAppV1.java │ │ │ ├── ECommerceAppV2.java │ │ │ ├── FlatRateShipping.java │ │ │ ├── Order.java │ │ │ ├── ShippingCostCalculatorNaive.java │ │ │ ├── ShippingCostService.java │ │ │ ├── ShippingStrategy.java │ │ │ ├── ThirdPartyApiShipping.java │ │ │ └── WeightBasedShipping.java │ │ ├── templatemethod/ │ │ │ ├── AbstractReportExporter.java │ │ │ ├── CsvReportExporter.java │ │ │ ├── CsvReportExporterNaive.java │ │ │ ├── ExcelReportExporter.java │ │ │ ├── ExcelReportExporterNaive.java │ │ │ ├── PdfReportExporter.java │ │ │ ├── PdfReportExporterNaive.java │ │ │ ├── ReportAppNaive.java │ │ │ ├── ReportAppTemplateMethod.java │ │ │ └── ReportData.java │ │ └── visitor/ │ │ ├── AreaCalculatorVisitor.java │ │ ├── Circle.java │ │ ├── Rectangle.java │ │ ├── Shape.java │ │ ├── ShapeVisitor.java │ │ ├── SvgExporterVisitor.java │ │ └── VisitorPatternDemo.java │ └── python/ │ ├── README.md │ └── adapter/ │ └── README.md ├── oop/ │ ├── cpp/ │ │ ├── abstraction/ │ │ │ └── README.md │ │ ├── aggregation/ │ │ │ └── README.md │ │ ├── association/ │ │ │ └── README.md │ │ ├── classesandobjects/ │ │ │ └── README.md │ │ ├── composition/ │ │ │ └── README.md │ │ ├── encapsulation/ │ │ │ └── README.md │ │ ├── inheritance/ │ │ │ └── README.md │ │ ├── interfaces/ │ │ │ └── README.md │ │ └── polymorphism/ │ │ └── README.md │ ├── csharp/ │ │ ├── abstraction/ │ │ │ └── README.md │ │ ├── aggregation/ │ │ │ └── README.md │ │ ├── association/ │ │ │ └── README.md │ │ ├── classesandobjects/ │ │ │ └── README.md │ │ ├── composition/ │ │ │ └── README.md │ │ ├── encapsulation/ │ │ │ └── README.md │ │ ├── inheritance/ │ │ │ └── README.md │ │ ├── interfaces/ │ │ │ └── README.md │ │ └── polymorphism/ │ │ └── README.md │ ├── golang/ │ │ ├── abstraction/ │ │ │ └── README.md │ │ ├── aggregation/ │ │ │ └── README.md │ │ ├── association/ │ │ │ └── README.md │ │ ├── classesandobjects/ │ │ │ └── README.md │ │ ├── composition/ │ │ │ └── README.md │ │ ├── encapsulation/ │ │ │ └── README.md │ │ ├── inheritance/ │ │ │ └── README.md │ │ ├── interfaces/ │ │ │ └── README.md │ │ └── polymorphism/ │ │ └── README.md │ ├── java/ │ │ ├── AggregationVsComposition/ │ │ │ └── README.MD │ │ ├── abstraction/ │ │ │ └── README.md │ │ ├── aggregation/ │ │ │ └── README.md │ │ ├── association/ │ │ │ └── README.md │ │ ├── classesandobjects/ │ │ │ └── README.md │ │ ├── composition/ │ │ │ └── README.md │ │ ├── encapsulation/ │ │ │ └── README.md │ │ ├── inheritance/ │ │ │ └── README.md │ │ ├── interfaces/ │ │ │ └── README.md │ │ └── polymorphism/ │ │ └── README.md │ ├── python/ │ │ ├── abstraction/ │ │ │ └── README.md │ │ ├── aggregation/ │ │ │ └── README.md │ │ ├── association/ │ │ │ └── README.md │ │ ├── classesandobjects/ │ │ │ └── README.md │ │ ├── composition/ │ │ │ └── README.md │ │ ├── encapsulation/ │ │ │ └── README.md │ │ ├── inheritance/ │ │ │ └── README.md │ │ ├── interfaces/ │ │ │ └── README.md │ │ └── polymorphism/ │ │ └── README.md │ └── rust/ │ ├── .gitignore │ ├── Cargo.toml │ ├── abstraction/ │ │ ├── README.md │ │ └── main.rs │ ├── aggregation/ │ │ ├── README.md │ │ └── main.rs │ ├── association/ │ │ ├── README.md │ │ └── main.rs │ ├── classes_and_objects/ │ │ ├── README.md │ │ └── main.rs │ ├── composition/ │ │ ├── README.md │ │ └── main.rs │ ├── encapsulation/ │ │ ├── README.md │ │ └── main.rs │ ├── inheritance/ │ │ ├── README.md │ │ └── main.rs │ ├── interfaces/ │ │ ├── README.md │ │ └── main.rs │ └── polymorphism/ │ ├── README.md │ └── main.rs ├── problems/ │ ├── airline-management-system.md │ ├── atm.md │ ├── car-rental-system.md │ ├── chess-game.md │ ├── coffee-vending-machine.md │ ├── concert-ticket-booking-system.md │ ├── course-registration-system.md │ ├── cricinfo.md │ ├── digital-wallet-service.md │ ├── elevator-system.md │ ├── food-delivery-service.md │ ├── hotel-management-system.md │ ├── library-management-system.md │ ├── linkedin.md │ ├── logging-framework.md │ ├── lru-cache.md │ ├── movie-ticket-booking-system.md │ ├── music-streaming-service.md │ ├── online-auction-system.md │ ├── online-shopping-service.md │ ├── online-stock-brokerage-system.md │ ├── parking-lot.md │ ├── pub-sub-system.md │ ├── restaurant-management-system.md │ ├── ride-sharing-service.md │ ├── snake-and-ladder.md │ ├── social-networking-service.md │ ├── splitwise.md │ ├── stack-overflow.md │ ├── task-management-system.md │ ├── tic-tac-toe.md │ ├── traffic-signal.md │ └── vending-machine.md └── solutions/ ├── cpp/ │ ├── airlinemanagementsystem/ │ │ ├── AirlineManagementSystem.cpp │ │ ├── AirlineManagementSystem.hpp │ │ ├── AirlineManagementSystemDemo.cpp │ │ ├── Booking.cpp │ │ ├── Booking.hpp │ │ ├── Flight.cpp │ │ ├── Flight.hpp │ │ ├── Passenger.cpp │ │ ├── Passenger.hpp │ │ ├── README.md │ │ ├── Seat.cpp │ │ ├── Seat.hpp │ │ └── airline_system │ ├── atm/ │ │ ├── ATM.cpp │ │ ├── ATM.hpp │ │ ├── ATMDemo.cpp │ │ ├── Account.cpp │ │ ├── Account.hpp │ │ ├── README.md │ │ └── atm │ ├── carrentalsystem/ │ │ ├── Car.cpp │ │ ├── Car.hpp │ │ ├── CarRentalSystem.cpp │ │ ├── CarRentalSystem.hpp │ │ ├── CarRentalSystemDemo.cpp │ │ ├── Customer.cpp │ │ ├── Customer.hpp │ │ ├── README.md │ │ ├── Rental.cpp │ │ ├── Rental.hpp │ │ └── car_rental │ ├── chessgame/ │ │ ├── Board.hpp │ │ ├── ChessDemo.cpp │ │ ├── Game.cpp │ │ ├── Game.hpp │ │ ├── Piece.cpp │ │ ├── Piece.hpp │ │ ├── Position.hpp │ │ ├── README.md │ │ └── pieces/ │ │ ├── Bishop.cpp │ │ ├── Bishop.hpp │ │ ├── King.cpp │ │ ├── King.hpp │ │ ├── Knight.cpp │ │ ├── Knight.hpp │ │ ├── Pawn.cpp │ │ ├── Pawn.hpp │ │ ├── Queen.cpp │ │ ├── Queen.hpp │ │ ├── Rook.cpp │ │ └── Rook.hpp │ ├── coffeevendingmachine/ │ │ ├── Coffee.cpp │ │ ├── Coffee.hpp │ │ ├── CoffeeType.hpp │ │ ├── CoffeeVendingMachine.cpp │ │ ├── CoffeeVendingMachine.hpp │ │ ├── CoffeeVendingMachineDemo.cpp │ │ ├── Inventory.cpp │ │ ├── Inventory.hpp │ │ ├── README.md │ │ └── coffee_machine │ ├── concertticketbookingsystem/ │ │ ├── Booking.cpp │ │ ├── Booking.hpp │ │ ├── BookingSystem.cpp │ │ ├── BookingSystem.hpp │ │ ├── Concert.cpp │ │ ├── Concert.hpp │ │ ├── ConcertBookingDemo.cpp │ │ ├── README.md │ │ ├── Seat.cpp │ │ ├── Seat.hpp │ │ └── concert_booking │ ├── courseregistrationsystem/ │ │ ├── Course.cpp │ │ ├── Course.hpp │ │ ├── README.md │ │ ├── RegistrationSystem.cpp │ │ ├── RegistrationSystem.hpp │ │ ├── RegistrationSystemDemo.cpp │ │ ├── Student.cpp │ │ └── Student.hpp │ ├── cricinfo/ │ │ ├── CricInfoDemo.cpp │ │ ├── CricInfoSystem.cpp │ │ ├── CricInfoSystem.hpp │ │ ├── Match.cpp │ │ ├── Match.hpp │ │ ├── Player.cpp │ │ ├── Player.hpp │ │ ├── PlayerStats.hpp │ │ ├── README.md │ │ ├── Team.cpp │ │ └── Team.hpp │ ├── digitalwalletservice/ │ │ ├── README.md │ │ ├── Transaction.cpp │ │ ├── Transaction.hpp │ │ ├── User.cpp │ │ ├── User.hpp │ │ ├── Wallet.cpp │ │ ├── Wallet.hpp │ │ ├── WalletDemo.cpp │ │ ├── WalletSystem.cpp │ │ └── WalletSystem.hpp │ ├── elevatorsystem/ │ │ ├── Elevator.cpp │ │ ├── Elevator.hpp │ │ ├── ElevatorDemo.cpp │ │ ├── ElevatorSystem.cpp │ │ ├── ElevatorSystem.hpp │ │ ├── README.md │ │ ├── Request.cpp │ │ └── Request.hpp │ ├── fooddeliveryservice/ │ │ ├── DeliveryDemo.cpp │ │ ├── DeliveryService.cpp │ │ ├── DeliveryService.hpp │ │ ├── MenuItem.cpp │ │ ├── MenuItem.hpp │ │ ├── Order.cpp │ │ ├── Order.hpp │ │ ├── README.md │ │ ├── Restaurant.cpp │ │ ├── Restaurant.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── hotelmanagementsystem/ │ │ ├── Booking.cpp │ │ ├── Booking.hpp │ │ ├── Guest.cpp │ │ ├── Guest.hpp │ │ ├── HotelDemo.cpp │ │ ├── HotelManager.cpp │ │ ├── HotelManager.hpp │ │ ├── README.md │ │ ├── Room.cpp │ │ └── Room.hpp │ ├── librarymanagementsystem/ │ │ ├── Book.cpp │ │ ├── Book.hpp │ │ ├── LibraryDemo.cpp │ │ ├── LibraryManager.cpp │ │ ├── LibraryManager.hpp │ │ ├── Member.cpp │ │ ├── Member.hpp │ │ ├── README.md │ │ ├── Transaction.cpp │ │ └── Transaction.hpp │ ├── linkedin/ │ │ ├── LinkedInDemo.cpp │ │ ├── LinkedInManager.cpp │ │ ├── LinkedInManager.hpp │ │ ├── Post.cpp │ │ ├── Post.hpp │ │ ├── Profile.cpp │ │ ├── Profile.hpp │ │ ├── README.md │ │ ├── User.cpp │ │ └── User.hpp │ ├── loggingframework/ │ │ ├── ConsoleAppender.cpp │ │ ├── ConsoleAppender.hpp │ │ ├── FileAppender.cpp │ │ ├── FileAppender.hpp │ │ ├── LogAppender.hpp │ │ ├── LogLevel.hpp │ │ ├── LogMessage.cpp │ │ ├── LogMessage.hpp │ │ ├── Logger.cpp │ │ ├── Logger.hpp │ │ ├── LoggingDemo.cpp │ │ └── README.md │ ├── lrucache/ │ │ ├── DoublyLinkedList.hpp │ │ ├── LRUCache.hpp │ │ ├── LRUCacheDemo.cpp │ │ └── README.md │ ├── movieticketbookingsystem/ │ │ ├── Booking.cpp │ │ ├── Booking.hpp │ │ ├── BookingDemo.cpp │ │ ├── BookingSystem.cpp │ │ ├── BookingSystem.hpp │ │ ├── Movie.cpp │ │ ├── Movie.hpp │ │ ├── README.md │ │ ├── Show.cpp │ │ ├── Show.hpp │ │ ├── Theater.cpp │ │ └── Theater.hpp │ ├── musicstreamingservice/ │ │ ├── Artist.cpp │ │ ├── Artist.hpp │ │ ├── MusicStreamingDemo.cpp │ │ ├── MusicStreamingService.cpp │ │ ├── MusicStreamingService.hpp │ │ ├── Playlist.cpp │ │ ├── Playlist.hpp │ │ ├── README.md │ │ ├── Song.cpp │ │ ├── Song.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── onlineauctionsystem/ │ │ ├── Auction.cpp │ │ ├── Auction.hpp │ │ ├── AuctionSystem.cpp │ │ ├── AuctionSystem.hpp │ │ ├── AuctionSystemDemo.cpp │ │ ├── Item.cpp │ │ ├── Item.hpp │ │ ├── README.md │ │ ├── User.cpp │ │ └── User.hpp │ ├── onlineshoppingservice/ │ │ ├── Cart.cpp │ │ ├── Cart.hpp │ │ ├── CartItem.cpp │ │ ├── CartItem.hpp │ │ ├── Order.cpp │ │ ├── Order.hpp │ │ ├── Product.cpp │ │ ├── Product.hpp │ │ ├── README.md │ │ ├── ShoppingDemo.cpp │ │ ├── ShoppingSystem.cpp │ │ ├── ShoppingSystem.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── onlinestockbrokeragesystem/ │ │ ├── BrokerageDemo.cpp │ │ ├── BrokerageSystem.cpp │ │ ├── BrokerageSystem.hpp │ │ ├── Portfolio.cpp │ │ ├── Portfolio.hpp │ │ ├── README.md │ │ ├── Stock.cpp │ │ ├── Stock.hpp │ │ ├── Transaction.cpp │ │ ├── Transaction.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── parkinglot/ │ │ ├── ParkingLot.cpp │ │ ├── ParkingLot.hpp │ │ ├── ParkingLotDemo.cpp │ │ ├── ParkingSpot.cpp │ │ ├── ParkingSpot.hpp │ │ ├── README.md │ │ ├── Vehicle.cpp │ │ └── Vehicle.hpp │ ├── pubsubsystem/ │ │ ├── Message.cpp │ │ ├── Message.hpp │ │ ├── PubSubDemo.cpp │ │ ├── PubSubSystem.cpp │ │ ├── PubSubSystem.hpp │ │ ├── README.md │ │ ├── Subscriber.cpp │ │ ├── Subscriber.hpp │ │ ├── Topic.cpp │ │ └── Topic.hpp │ ├── restaurantmanagementsystem/ │ │ ├── MenuItem.cpp │ │ ├── MenuItem.hpp │ │ ├── Order.cpp │ │ ├── Order.hpp │ │ ├── OrderItem.cpp │ │ ├── OrderItem.hpp │ │ ├── README.md │ │ ├── RestaurantDemo.cpp │ │ ├── RestaurantSystem.cpp │ │ ├── RestaurantSystem.hpp │ │ ├── Table.cpp │ │ └── Table.hpp │ ├── ridesharingservice/ │ │ ├── Location.cpp │ │ ├── Location.hpp │ │ ├── README.md │ │ ├── Ride.cpp │ │ ├── Ride.hpp │ │ ├── RideDemo.cpp │ │ ├── RideService.cpp │ │ ├── RideService.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── snakeandladdergame/ │ │ ├── Board.cpp │ │ ├── Board.hpp │ │ ├── Dice.cpp │ │ ├── Dice.hpp │ │ ├── Game.cpp │ │ ├── Game.hpp │ │ ├── GameDemo.cpp │ │ ├── Player.cpp │ │ ├── Player.hpp │ │ └── README.md │ ├── socialnetworkingservice/ │ │ ├── Post.cpp │ │ ├── Post.hpp │ │ ├── README.md │ │ ├── SocialNetwork.cpp │ │ ├── SocialNetwork.hpp │ │ ├── SocialNetworkDemo.cpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── splitwise/ │ │ ├── Expense.cpp │ │ ├── Expense.hpp │ │ ├── README.md │ │ ├── SplitwiseDemo.cpp │ │ ├── SplitwiseSystem.cpp │ │ ├── SplitwiseSystem.hpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── stackoverflow/ │ │ ├── Comment.cpp │ │ ├── Comment.hpp │ │ ├── Post.cpp │ │ ├── Post.hpp │ │ ├── README.md │ │ ├── StackOverflow.cpp │ │ ├── StackOverflow.hpp │ │ ├── StackOverflowDemo.cpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── taskmanagementsystem/ │ │ ├── README.md │ │ ├── Task.cpp │ │ ├── Task.hpp │ │ ├── TaskManager.cpp │ │ ├── TaskManager.hpp │ │ ├── TaskManagerDemo.cpp │ │ ├── User.cpp │ │ └── User.hpp │ ├── tictactoe/ │ │ ├── Board.cpp │ │ ├── Board.hpp │ │ ├── Game.cpp │ │ ├── Game.hpp │ │ ├── Player.cpp │ │ ├── Player.hpp │ │ ├── README.md │ │ └── TicTacToeDemo.cpp │ ├── trafficsignalsystem/ │ │ ├── Intersection.cpp │ │ ├── Intersection.hpp │ │ ├── README.md │ │ ├── Signal.cpp │ │ ├── Signal.hpp │ │ ├── TrafficSystem.cpp │ │ ├── TrafficSystem.hpp │ │ └── TrafficSystemDemo.cpp │ ├── vendingmachine/ │ │ ├── Product.cpp │ │ ├── Product.hpp │ │ ├── README.md │ │ ├── Transaction.cpp │ │ ├── Transaction.hpp │ │ ├── VendingMachine.cpp │ │ ├── VendingMachine.hpp │ │ └── VendingMachineDemo.cpp │ └── votingsystem/ │ └── README.md ├── csharp/ │ ├── LLDRunner.cs │ ├── airlinemanagementsystem/ │ │ ├── Aircraft.cs │ │ ├── AirlineManagementSystem.cs │ │ ├── AirlineManagementSystemDemo.cs │ │ ├── Booking.cs │ │ ├── BookingManager.cs │ │ ├── BookingStatus.cs │ │ ├── Flight.cs │ │ ├── FlightSearch.cs │ │ ├── Passenger.cs │ │ ├── Payment.cs │ │ ├── PaymentProcessor.cs │ │ ├── PaymentStatus.cs │ │ ├── README.md │ │ ├── Seat.cs │ │ ├── SeatStatus.cs │ │ └── SeatType.cs │ ├── atm/ │ │ ├── ATM.cs │ │ ├── ATMDemo.cs │ │ ├── DispenserChain/ │ │ │ ├── CashDispenser.cs │ │ │ ├── IDispenseChain.cs │ │ │ ├── NoteDispenser.cs │ │ │ ├── NoteDispenser100.cs │ │ │ ├── NoteDispenser20.cs │ │ │ └── NoteDispenser50.cs │ │ ├── Enums/ │ │ │ └── OperationType.cs │ │ ├── Models/ │ │ │ ├── Account.cs │ │ │ └── Card.cs │ │ ├── README.md │ │ ├── Service/ │ │ │ └── BankService.cs │ │ ├── State/ │ │ │ ├── AuthenticatedState.cs │ │ │ ├── HasCardState.cs │ │ │ ├── IATMState.cs │ │ │ └── IdleState.cs │ │ └── atm.csproj │ ├── bin/ │ │ └── Debug/ │ │ └── net8.0/ │ │ ├── c# │ │ ├── c#.deps.json │ │ ├── c#.pdb │ │ └── c#.runtimeconfig.json │ ├── c#.csproj │ ├── c#.sln │ ├── carrentalsystem/ │ │ ├── Car.cs │ │ ├── CarRentalSystemDemo.cs │ │ ├── CreditCardPaymentProcessor.cs │ │ ├── Customer.cs │ │ ├── IPaymentProcessor.cs │ │ ├── PayPalPaymentProcessor.cs │ │ ├── README.md │ │ ├── RentalSystem.cs │ │ └── Reservation.cs │ ├── chessgame/ │ │ ├── Bishop.cs │ │ ├── Board.cs │ │ ├── ChessGame.cs │ │ ├── ChessGameDemo.cs │ │ ├── Color.cs │ │ ├── InvalidMoveException.cs │ │ ├── King.cs │ │ ├── Knight.cs │ │ ├── Move.cs │ │ ├── Pawn.cs │ │ ├── Piece.cs │ │ ├── Player.cs │ │ ├── Queen.cs │ │ ├── README.md │ │ └── Rook.cs │ ├── coffeevendingmachine/ │ │ ├── CoffeeVendingMachine.cs │ │ ├── CoffeeVendingMachineDemo.cs │ │ ├── Decorator/ │ │ │ ├── CaramelSyrupDecorator.cs │ │ │ ├── CoffeeDecorator.cs │ │ │ └── ExtraSugarDecorator.cs │ │ ├── Enums/ │ │ │ ├── CoffeeType.cs │ │ │ ├── Ingredient.cs │ │ │ └── ToppingType.cs │ │ ├── Factory/ │ │ │ └── CoffeeFactory.cs │ │ ├── Inventory.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── IVendingMachineState.cs │ │ │ ├── OutOfIngredientState.cs │ │ │ ├── PaidState.cs │ │ │ ├── ReadyState.cs │ │ │ └── SelectingState.cs │ │ ├── TemplateMethod/ │ │ │ ├── Cappuccino.cs │ │ │ ├── Coffee.cs │ │ │ ├── Espresso.cs │ │ │ └── Latte.cs │ │ └── coffeevendingmachine.csproj │ ├── concertticketbookingsystem/ │ │ ├── Booking.cs │ │ ├── BookingStatus.cs │ │ ├── Concert.cs │ │ ├── ConcertTicketBookingSystem.cs │ │ ├── ConcertTicketBookingSystemDemo.cs │ │ ├── README.md │ │ ├── Seat.cs │ │ ├── SeatNotAvailableException.cs │ │ ├── SeatStatus.cs │ │ ├── SeatType.cs │ │ └── User.cs │ ├── courseregistrationsystem/ │ │ ├── Course.cs │ │ ├── CourseRegistrationDemo.cs │ │ ├── CourseRegistrationSystem.cs │ │ ├── README.md │ │ ├── Registration.cs │ │ └── Student.cs │ ├── cricinfo/ │ │ ├── CommentaryManager.cs │ │ ├── CricinfoDemo.cs │ │ ├── CricinfoService.cs │ │ ├── Enums/ │ │ │ ├── ExtraType.cs │ │ │ ├── MatchStatus.cs │ │ │ ├── MatchType.cs │ │ │ ├── PlayerRole.cs │ │ │ └── WicketType.cs │ │ ├── Models/ │ │ │ ├── Ball.cs │ │ │ ├── Innings.cs │ │ │ ├── Match.cs │ │ │ ├── Player.cs │ │ │ ├── PlayerStats.cs │ │ │ ├── Team.cs │ │ │ └── Wicket.cs │ │ ├── Observers/ │ │ │ ├── CommentaryDisplay.cs │ │ │ ├── IMatchObserver.cs │ │ │ ├── ScorecardDisplay.cs │ │ │ └── UserNotifier.cs │ │ ├── README.md │ │ ├── Repositories/ │ │ │ ├── MatchRepository.cs │ │ │ └── PlayerRepository.cs │ │ ├── States/ │ │ │ ├── FinishedState.cs │ │ │ ├── IMatchState.cs │ │ │ ├── InBreakState.cs │ │ │ ├── LiveState.cs │ │ │ └── ScheduledState.cs │ │ ├── Strategy/ │ │ │ ├── IMatchFormatStrategy.cs │ │ │ ├── ODIFormatStrategy.cs │ │ │ └── T20FormatStrategy.cs │ │ └── cricinfo.csproj │ ├── digitalwalletservice/ │ │ ├── Account.cs │ │ ├── BankAccount.cs │ │ ├── CreditCard.cs │ │ ├── Currency.cs │ │ ├── CurrencyConverter.cs │ │ ├── DigitalWallet.cs │ │ ├── DigitalWalletDemo.cs │ │ ├── InsufficientFundsException.cs │ │ ├── PaymentMethod.cs │ │ ├── README.md │ │ ├── Transaction.cs │ │ └── User.cs │ ├── elevatorsystem/ │ │ ├── ElevatorSystem.cs │ │ ├── ElevatorSystemDemo.cs │ │ ├── Enums/ │ │ │ ├── Direction.cs │ │ │ └── RequestSource.cs │ │ ├── Models/ │ │ │ ├── Elevator.cs │ │ │ └── Request.cs │ │ ├── Observer/ │ │ │ ├── Display.cs │ │ │ └── IElevatorObserver.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── IElevatorState.cs │ │ │ ├── IdleState.cs │ │ │ ├── MovingDownState.cs │ │ │ └── MovingUpState.cs │ │ ├── Strategy/ │ │ │ ├── IElevatorSelectionStrategy.cs │ │ │ └── NearestElevatorStrategy.cs │ │ └── elevatorsystem.csproj │ ├── fooddeliveryservice/ │ │ ├── Enums/ │ │ │ └── OrderStatus.cs │ │ ├── FoodDeliveryService.cs │ │ ├── FoodDeliveryServiceDemo.cs │ │ ├── Models/ │ │ │ ├── Address.cs │ │ │ ├── Customer.cs │ │ │ ├── DeliveryAgent.cs │ │ │ ├── Menu.cs │ │ │ ├── MenuItem.cs │ │ │ ├── Order.cs │ │ │ ├── OrderItem.cs │ │ │ ├── Restaurant.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ └── IOrderObserver.cs │ │ ├── README.md │ │ ├── Strategies/ │ │ │ ├── assignment/ │ │ │ │ ├── IDeliveryAssignmentStrategy.cs │ │ │ │ └── NearestAvailableAgentStrategy.cs │ │ │ └── search/ │ │ │ ├── IRestaurantSearchStrategy.cs │ │ │ ├── SearchByCityStrategy.cs │ │ │ ├── SearchByMenuKeywordStrategy.cs │ │ │ └── SearchByProximityStrategy.cs │ │ └── fooddeliveryservice.csproj │ ├── hotelmanagementsystem/ │ │ ├── CashPayment.cs │ │ ├── CreditCardPayment.cs │ │ ├── Guest.cs │ │ ├── HotelManagementSystem.cs │ │ ├── HotelManagementSystemDemo.cs │ │ ├── Payment.cs │ │ ├── README.md │ │ ├── Reservation.cs │ │ ├── ReservationStatus.cs │ │ ├── Room.cs │ │ ├── RoomStatus.cs │ │ └── RoomType.cs │ ├── librarymanagementsystem/ │ │ ├── Enum/ │ │ │ └── ItemType.cs │ │ ├── Factory/ │ │ │ └── ItemFactory.cs │ │ ├── LibraryManagementSystem.cs │ │ ├── LibraryManagementSystemDemo.cs │ │ ├── Models/ │ │ │ ├── Book.cs │ │ │ ├── BookCopy.cs │ │ │ ├── LibraryItem.cs │ │ │ ├── Loan.cs │ │ │ ├── Magazine.cs │ │ │ ├── Member.cs │ │ │ └── TransactionService.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── AvailableState.cs │ │ │ ├── CheckedOutState.cs │ │ │ ├── IItemState.cs │ │ │ └── OnHoldState.cs │ │ ├── Strategy/ │ │ │ ├── ISearchStrategy.cs │ │ │ ├── SearchByAuthorStrategy.cs │ │ │ └── SearchByTitleStrategy.cs │ │ └── librarymanagementsystem.csproj │ ├── linkedIn/ │ │ ├── Enums/ │ │ │ ├── ConnectionStatus.cs │ │ │ └── NotificationType.cs │ │ ├── LinkedInDemo.cs │ │ ├── LinkedInSystem.cs │ │ ├── Models/ │ │ │ ├── Comment.cs │ │ │ ├── Connection.cs │ │ │ ├── Education.cs │ │ │ ├── Experience.cs │ │ │ ├── Like.cs │ │ │ ├── Member.cs │ │ │ ├── NewsFeed.cs │ │ │ ├── Notification.cs │ │ │ ├── Post.cs │ │ │ └── Profile.cs │ │ ├── Observer/ │ │ │ ├── INotificationObserver.cs │ │ │ └── Subject.cs │ │ ├── README.md │ │ ├── Services/ │ │ │ ├── ConnectionService.cs │ │ │ ├── NewsFeedService.cs │ │ │ ├── NotificationService.cs │ │ │ └── SearchService.cs │ │ ├── Strategy/ │ │ │ ├── ChronologicalSortStrategy.cs │ │ │ └── IFeedSortingStrategy.cs │ │ └── linkedIn.csproj │ ├── loggingframework/ │ │ ├── Appenders/ │ │ │ ├── ConsoleAppender.cs │ │ │ ├── FileAppender.cs │ │ │ └── ILogAppender.cs │ │ ├── AsyncLogProcessor.cs │ │ ├── Enum/ │ │ │ └── LogLevel.cs │ │ ├── Formatters/ │ │ │ ├── ILogFormatter.cs │ │ │ └── SimpleTextFormatter.cs │ │ ├── LogManager.cs │ │ ├── Logger.cs │ │ ├── LoggingFrameworkDemo.cs │ │ ├── Models/ │ │ │ └── LogMessage.cs │ │ ├── README.md │ │ └── loggingframework.csproj │ ├── lrucache/ │ │ ├── DoublyLinkedList.cs │ │ ├── LRUCache.cs │ │ ├── LRUCacheDemo.cs │ │ ├── Node.cs │ │ ├── README.md │ │ └── lrucache.csproj │ ├── movieticketbookingsystem/ │ │ ├── BookingManager.cs │ │ ├── Enums/ │ │ │ ├── PaymentStatus.cs │ │ │ ├── SeatStatus.cs │ │ │ └── SeatType.cs │ │ ├── Models/ │ │ │ ├── Booking.cs │ │ │ ├── Cinema.cs │ │ │ ├── City.cs │ │ │ ├── Movie.cs │ │ │ ├── Payment.cs │ │ │ ├── Screen.cs │ │ │ ├── Seat.cs │ │ │ ├── Show.cs │ │ │ └── User.cs │ │ ├── MovieBookingDemo.cs │ │ ├── MovieBookingService.cs │ │ ├── Observer/ │ │ │ ├── IMovieObserver.cs │ │ │ ├── MovieSubject.cs │ │ │ └── UserObserver.cs │ │ ├── README.md │ │ ├── SeatLockManager.cs │ │ ├── Strategies/ │ │ │ ├── Payment/ │ │ │ │ ├── CreditCardPaymentStrategy.cs │ │ │ │ └── IPaymentStrategy.cs │ │ │ └── Pricing/ │ │ │ ├── IPricingStrategy.cs │ │ │ ├── WeekdayPricingStrategy.cs │ │ │ └── WeekendPricingStrategy.cs │ │ └── movieticketbookingsystem.csproj │ ├── musicstreamingservice/ │ │ ├── Commands/ │ │ │ ├── ICommand.cs │ │ │ ├── NextTrackCommand.cs │ │ │ ├── PauseCommand.cs │ │ │ └── PlayCommand.cs │ │ ├── Enums/ │ │ │ ├── PlayerStatus.cs │ │ │ └── SubscriptionTier.cs │ │ ├── Models/ │ │ │ ├── Album.cs │ │ │ ├── Artist.cs │ │ │ ├── IPlayable.cs │ │ │ ├── Player.cs │ │ │ ├── Playlist.cs │ │ │ ├── Song.cs │ │ │ └── User.cs │ │ ├── MusicStreamingDemo.cs │ │ ├── MusicStreamingSystem.cs │ │ ├── Observer/ │ │ │ ├── IArtistObserver.cs │ │ │ └── Subject.cs │ │ ├── README.md │ │ ├── Services/ │ │ │ ├── RecommendationService.cs │ │ │ └── SearchService.cs │ │ ├── States/ │ │ │ ├── PausedState.cs │ │ │ ├── PlayerState.cs │ │ │ ├── PlayingState.cs │ │ │ └── StoppedState.cs │ │ ├── Strategies/ │ │ │ ├── Playback/ │ │ │ │ ├── FreePlaybackStrategy.cs │ │ │ │ ├── PlaybackStrategy.cs │ │ │ │ └── PremiumPlaybackStrategy.cs │ │ │ └── Recommendation/ │ │ │ ├── GenreBasedRecommendationStrategy.cs │ │ │ └── RecommendationStrategy.cs │ │ └── musicstreamingservice.csproj │ ├── obj/ │ │ ├── Debug/ │ │ │ └── net8.0/ │ │ │ ├── .NETCoreApp,Version=v8.0.AssemblyAttributes.cs │ │ │ ├── apphost │ │ │ ├── c#.AssemblyInfo.cs │ │ │ ├── c#.AssemblyInfoInputs.cache │ │ │ ├── c#.GeneratedMSBuildEditorConfig.editorconfig │ │ │ ├── c#.GlobalUsings.g.cs │ │ │ ├── c#.assets.cache │ │ │ ├── c#.csproj.CoreCompileInputs.cache │ │ │ ├── c#.csproj.FileListAbsolute.txt │ │ │ ├── c#.genruntimeconfig.cache │ │ │ ├── c#.pdb │ │ │ └── c#.sourcelink.json │ │ ├── c#.csproj.nuget.dgspec.json │ │ ├── c#.csproj.nuget.g.props │ │ ├── c#.csproj.nuget.g.targets │ │ ├── project.assets.json │ │ └── project.nuget.cache │ ├── onlineauctionsystem/ │ │ ├── AuctionService.cs │ │ ├── AuctionSystemDemo.cs │ │ ├── Enum/ │ │ │ └── AuctionState.cs │ │ ├── Models/ │ │ │ ├── Auction.cs │ │ │ ├── Bid.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ └── IAuctionObserver.cs │ │ ├── README.md │ │ └── onlineauctionsystem.csproj │ ├── onlineshoppingservice/ │ │ ├── Decorators/ │ │ │ ├── GiftWrapDecorator.cs │ │ │ └── ProductDecorator.cs │ │ ├── Enums/ │ │ │ ├── OrderStatus.cs │ │ │ └── ProductCategory.cs │ │ ├── Exceptions/ │ │ │ └── OutOfStockException.cs │ │ ├── Models/ │ │ │ ├── Account.cs │ │ │ ├── Address.cs │ │ │ ├── CartItem.cs │ │ │ ├── Customer.cs │ │ │ ├── Order.cs │ │ │ ├── OrderLineItem.cs │ │ │ ├── Product.cs │ │ │ └── ShoppingCart.cs │ │ ├── Observer/ │ │ │ ├── IOrderObserver.cs │ │ │ └── Subject.cs │ │ ├── OnlineShoppingDemo.cs │ │ ├── OnlineShoppingSystem.cs │ │ ├── README.md │ │ ├── Services/ │ │ │ ├── InventoryService.cs │ │ │ ├── OrderService.cs │ │ │ ├── PaymentService.cs │ │ │ └── SearchService.cs │ │ ├── States/ │ │ │ ├── CancelledState.cs │ │ │ ├── DeliveredState.cs │ │ │ ├── IOrderState.cs │ │ │ ├── PlacedState.cs │ │ │ └── ShippedState.cs │ │ ├── Strategy/ │ │ │ ├── CreditCardPaymentStrategy.cs │ │ │ ├── IPaymentStrategy.cs │ │ │ └── UPIPaymentStrategy.cs │ │ └── onlineshoppingservice.csproj │ ├── onlinestockbrokeragesystem/ │ │ ├── Commands/ │ │ │ ├── BuyStockCommand.cs │ │ │ ├── IOrderCommand.cs │ │ │ └── SellStockCommand.cs │ │ ├── Enums/ │ │ │ ├── OrderStatus.cs │ │ │ ├── OrderType.cs │ │ │ └── TransactionType.cs │ │ ├── Exceptions/ │ │ │ ├── InsufficientFundsException.cs │ │ │ └── InsufficientStockException.cs │ │ ├── Models/ │ │ │ ├── Account.cs │ │ │ ├── Order.cs │ │ │ ├── OrderBuilder.cs │ │ │ ├── Stock.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ └── IStockObserver.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── CancelledState.cs │ │ │ ├── FilledState.cs │ │ │ ├── IOrderState.cs │ │ │ └── OpenState.cs │ │ ├── StockBrokerageSystem.cs │ │ ├── StockBrokerageSystemDemo.cs │ │ ├── StockExchange.cs │ │ ├── Strategy/ │ │ │ ├── IExecutionStrategy.cs │ │ │ ├── LimitOrderStrategy.cs │ │ │ └── MarketOrderStrategy.cs │ │ └── onlinestockbrokeragesystem.csproj │ ├── parkinglot/ │ │ ├── Enums/ │ │ │ └── VehicleSize.cs │ │ ├── Models/ │ │ │ ├── ParkingFloor.cs │ │ │ ├── ParkingSpot.cs │ │ │ ├── ParkingTicket.cs │ │ │ └── Vehicle.cs │ │ ├── ParkingLot.cs │ │ ├── ParkingLotDemo.cs │ │ ├── README.md │ │ ├── Strategies/ │ │ │ ├── Fee/ │ │ │ │ ├── FlatRateFeeStrategy.cs │ │ │ │ ├── IFeeStrategy.cs │ │ │ │ └── VehicleBasedFeeStrategy.cs │ │ │ └── Parking/ │ │ │ ├── BestFitStrategy.cs │ │ │ ├── FarthestFirstStrategy.cs │ │ │ ├── IParkingStrategy.cs │ │ │ └── NearestFirstStrategy.cs │ │ └── parkinglot.csproj │ ├── pubsubsystem/ │ │ ├── Models/ │ │ │ ├── Message.cs │ │ │ └── Topic.cs │ │ ├── PubSubDemo.cs │ │ ├── PubSubService.cs │ │ ├── README.md │ │ ├── Subscribers/ │ │ │ ├── AlertSubscriber.cs │ │ │ ├── ISubscriber.cs │ │ │ └── NewsSubscriber.cs │ │ └── pubsubsystem.csproj │ ├── restaurantmanagementsystem/ │ │ ├── Commands/ │ │ │ ├── ICommand.cs │ │ │ ├── PrepareOrderCommand.cs │ │ │ └── ServeOrderCommand.cs │ │ ├── Decorators/ │ │ │ ├── BillDecorator.cs │ │ │ ├── ServiceChargeDecorator.cs │ │ │ └── TaxDecorator.cs │ │ ├── Enum/ │ │ │ └── TableStatus.cs │ │ ├── Models/ │ │ │ ├── BaseBill.cs │ │ │ ├── Bill.cs │ │ │ ├── Chef.cs │ │ │ ├── IBillComponent.cs │ │ │ ├── Menu.cs │ │ │ ├── MenuItem.cs │ │ │ ├── Order.cs │ │ │ ├── OrderItem.cs │ │ │ ├── Restaurant.cs │ │ │ ├── Staff.cs │ │ │ ├── Table.cs │ │ │ └── Waiter.cs │ │ ├── Observer/ │ │ │ └── IOrderObserver.cs │ │ ├── README.md │ │ ├── RestaurantManagementSystemDemo.cs │ │ ├── RestaurantManagementSystemFacade.cs │ │ ├── States/ │ │ │ ├── IOrderItemState.cs │ │ │ ├── OrderedState.cs │ │ │ ├── PreparingState.cs │ │ │ ├── ReadyForPickupState.cs │ │ │ └── ServedState.cs │ │ └── restaurantmanagementsystem.csproj │ ├── ridesharingservice/ │ │ ├── Enums/ │ │ │ ├── DriverStatus.cs │ │ │ ├── RideType.cs │ │ │ └── TripStatus.cs │ │ ├── Models/ │ │ │ ├── Driver.cs │ │ │ ├── Location.cs │ │ │ ├── Rider.cs │ │ │ ├── Trip.cs │ │ │ ├── User.cs │ │ │ └── Vehicle.cs │ │ ├── Observer/ │ │ │ └── ITripObserver.cs │ │ ├── README.md │ │ ├── RideSharingService.cs │ │ ├── RideSharingServiceDemo.cs │ │ ├── States/ │ │ │ ├── AssignedState.cs │ │ │ ├── CompletedState.cs │ │ │ ├── ITripState.cs │ │ │ ├── InProgressState.cs │ │ │ └── RequestedState.cs │ │ ├── Strategies/ │ │ │ ├── Matching/ │ │ │ │ ├── IDriverMatchingStrategy.cs │ │ │ │ └── NearestDriverMatchingStrategy.cs │ │ │ └── Pricing/ │ │ │ ├── FlatRatePricingStrategy.cs │ │ │ ├── IPricingStrategy.cs │ │ │ └── VehicleBasedPricingStrategy.cs │ │ └── ridesharingservice.csproj │ ├── snakeandladdergame/ │ │ ├── Enums/ │ │ │ └── GameStatus.cs │ │ ├── Game.cs │ │ ├── Models/ │ │ │ ├── Board.cs │ │ │ ├── BoardEntity.cs │ │ │ ├── Dice.cs │ │ │ ├── Ladder.cs │ │ │ ├── Player.cs │ │ │ └── Snake.cs │ │ ├── README.md │ │ ├── SnakeAndLadderDemo.cs │ │ └── snakeandladdergame.csproj │ ├── socialnetworkingservice/ │ │ ├── Models/ │ │ │ ├── Comment.cs │ │ │ ├── CommentableEntity.cs │ │ │ ├── Post.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ ├── IPostObserver.cs │ │ │ └── UserNotifier.cs │ │ ├── README.md │ │ ├── Repositories/ │ │ │ ├── PostRepository.cs │ │ │ └── UserRepository.cs │ │ ├── Services/ │ │ │ ├── NewsFeedService.cs │ │ │ ├── PostService.cs │ │ │ └── UserService.cs │ │ ├── SocialNetworkFacade.cs │ │ ├── SocialNetworkingDemo.cs │ │ ├── Strategy/ │ │ │ ├── ChronologicalStrategy.cs │ │ │ └── INewsFeedGenerationStrategy.cs │ │ └── socialnetworkingservice.csproj │ ├── splitwise/ │ │ ├── Models/ │ │ │ ├── BalanceSheet.cs │ │ │ ├── Expense.cs │ │ │ ├── Group.cs │ │ │ ├── Split.cs │ │ │ ├── Transaction.cs │ │ │ └── User.cs │ │ ├── README.md │ │ ├── SplitwiseDemo.cs │ │ ├── SplitwiseService.cs │ │ ├── Strategy/ │ │ │ ├── EqualSplitStrategy.cs │ │ │ ├── ExactSplitStrategy.cs │ │ │ ├── PercentageSplitStrategy.cs │ │ │ └── SplitStrategy.cs │ │ └── splitwise.csproj │ ├── stackoverflow/ │ │ ├── Enums/ │ │ │ ├── EventType.cs │ │ │ └── VoteType.cs │ │ ├── Models/ │ │ │ ├── Answer.cs │ │ │ ├── Comment.cs │ │ │ ├── Content.cs │ │ │ ├── Post.cs │ │ │ ├── Question.cs │ │ │ ├── Tag.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ ├── Event.cs │ │ │ ├── IPostObserver.cs │ │ │ └── ReputationManager.cs │ │ ├── README.md │ │ ├── StackOverflowDemo.cs │ │ ├── StackOverflowService.cs │ │ ├── Strategy/ │ │ │ ├── ISearchStrategy.cs │ │ │ ├── KeywordSearchStrategy.cs │ │ │ ├── TagSearchStrategy.cs │ │ │ └── UserSearchStrategy.cs │ │ └── stackoverflow.csproj │ ├── taskmanagementsystem/ │ │ ├── Enums/ │ │ │ ├── TaskPriority.cs │ │ │ └── TaskStatus.cs │ │ ├── Models/ │ │ │ ├── ActivityLog.cs │ │ │ ├── Comment.cs │ │ │ ├── Tag.cs │ │ │ ├── Task.cs │ │ │ ├── TaskList.cs │ │ │ └── User.cs │ │ ├── Observer/ │ │ │ ├── ActivityLogger.cs │ │ │ └── ITaskObserver.cs │ │ ├── README.md │ │ ├── State/ │ │ │ ├── DoneState.cs │ │ │ ├── InProgressState.cs │ │ │ ├── TaskState.cs │ │ │ └── TodoState.cs │ │ ├── Strategy/ │ │ │ ├── SortByDueDate.cs │ │ │ ├── SortByPriority.cs │ │ │ └── TaskSortStrategy.cs │ │ ├── TaskManagementSystem.cs │ │ ├── TaskManagementSystemDemo.cs │ │ └── taskmanagementsystem.csproj │ ├── tictactoe/ │ │ ├── Enums/ │ │ │ ├── GameStatus.cs │ │ │ └── Symbol.cs │ │ ├── Exceptions/ │ │ │ └── InvalidMoveException.cs │ │ ├── Models/ │ │ │ ├── Board.cs │ │ │ ├── Cell.cs │ │ │ ├── Game.cs │ │ │ └── Player.cs │ │ ├── Observer/ │ │ │ ├── GameSubject.cs │ │ │ ├── IGameObserver.cs │ │ │ └── Scoreboard.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── DrawState.cs │ │ │ ├── IGameState.cs │ │ │ ├── InProgressState.cs │ │ │ └── WinnerState.cs │ │ ├── Strategy/ │ │ │ ├── ColumnWinningStrategy.cs │ │ │ ├── DiagonalWinningStrategy.cs │ │ │ ├── IWinningStrategy.cs │ │ │ └── RowWinningStrategy.cs │ │ ├── TicTacToeDemo.cs │ │ ├── TicTacToeSystem.cs │ │ └── tictactoe.csproj │ ├── trafficsignalsystem/ │ │ ├── Enums/ │ │ │ ├── Direction.cs │ │ │ └── LightColor.cs │ │ ├── IntersectionController.cs │ │ ├── Observer/ │ │ │ ├── CentralMonitor.cs │ │ │ └── ITrafficObserver.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── Intersection/ │ │ │ │ ├── EastWestGreenState.cs │ │ │ │ ├── IIntersectionState.cs │ │ │ │ └── NorthSouthGreenState.cs │ │ │ └── Light/ │ │ │ ├── GreenState.cs │ │ │ ├── ISignalState.cs │ │ │ ├── RedState.cs │ │ │ └── YellowState.cs │ │ ├── TrafficControlSystem.cs │ │ ├── TrafficLight.cs │ │ ├── TrafficSystemDemo.cs │ │ └── trafficsignalsystem.csproj │ ├── vendingmachine/ │ │ ├── Enum/ │ │ │ └── Coin.cs │ │ ├── Models/ │ │ │ ├── Inventory.cs │ │ │ └── Item.cs │ │ ├── README.md │ │ ├── States/ │ │ │ ├── DispensingState.cs │ │ │ ├── HasMoneyState.cs │ │ │ ├── IdleState.cs │ │ │ ├── ItemSelectedState.cs │ │ │ └── VendingMachineState.cs │ │ ├── VendingMachine.cs │ │ ├── VendingMachineDemo.cs │ │ └── vendingmachine.csproj │ └── votingsystem/ │ └── README.md ├── golang/ │ ├── airlinemanagementsystem/ │ │ ├── README.md │ │ ├── aircraft.go │ │ ├── airline_management_system.go │ │ ├── airline_management_system_demo.go │ │ ├── booking.go │ │ ├── booking_manager.go │ │ ├── flight.go │ │ ├── flight_search.go │ │ ├── passenger.go │ │ ├── payment.go │ │ ├── payment_processor.go │ │ ├── seat.go │ │ └── types.go │ ├── app.log │ ├── atm/ │ │ ├── README.md │ │ ├── account.go │ │ ├── atm.go │ │ ├── atm_demo.go │ │ ├── banking_service.go │ │ ├── card.go │ │ ├── cash_dispenser.go │ │ ├── deposit_transaction.go │ │ ├── errors.go │ │ ├── transaction.go │ │ └── withdrawal_transaction.go │ ├── carrentalsystem/ │ │ ├── README.md │ │ ├── car.go │ │ ├── car_rental_system_demo.go │ │ ├── credit_card_processor.go │ │ ├── customer.go │ │ ├── payment_processor.go │ │ ├── paypal_processor.go │ │ ├── rental_system.go │ │ └── reservation.go │ ├── chessgame/ │ │ ├── README.md │ │ ├── board.go │ │ ├── chess_game.go │ │ ├── chess_game_demo.go │ │ ├── color.go │ │ ├── errors.go │ │ ├── move.go │ │ ├── piece.go │ │ ├── pieces.go │ │ └── player.go │ ├── coffeevendingmachine/ │ │ ├── README.md │ │ ├── coffee.go │ │ ├── coffee_machine.go │ │ ├── coffee_vending_machine_demo.go │ │ ├── ingredient.go │ │ └── payment.go │ ├── concertticketbookingsystem/ │ │ ├── README.md │ │ ├── booking.go │ │ ├── concert.go │ │ ├── concert_booking_system.go │ │ ├── concert_booking_system_demo.go │ │ ├── errors.go │ │ ├── seat.go │ │ ├── types.go │ │ ├── user.go │ │ └── utils.go │ ├── courseregistrationsystem/ │ │ ├── README.md │ │ ├── course.go │ │ ├── course_registration_system.go │ │ ├── course_registration_system_demo.go │ │ ├── registration.go │ │ └── student.go │ ├── cricinfo/ │ │ ├── README.md │ │ ├── ball.go │ │ ├── cricinfo.go │ │ ├── cricinfo_system.go │ │ ├── innings.go │ │ ├── match.go │ │ ├── match_service.go │ │ ├── over.go │ │ ├── player.go │ │ ├── scorecard.go │ │ ├── scorecard_service.go │ │ ├── team.go │ │ └── types.go │ ├── digitalwalletservice/ │ │ ├── README.md │ │ ├── account.go │ │ ├── bank_account.go │ │ ├── credit_card.go │ │ ├── currency_converter.go │ │ ├── digital_wallet.go │ │ ├── digital_wallet_demo.go │ │ ├── errors.go │ │ ├── payment_method.go │ │ ├── transaction.go │ │ ├── types.go │ │ └── user.go │ ├── elevatorsystem/ │ │ ├── README.md │ │ ├── direction.go │ │ ├── elevator.go │ │ ├── elevator_controller.go │ │ ├── elevator_controller_demo.go │ │ └── request.go │ ├── fooddeliveryservice/ │ │ ├── README.md │ │ ├── customer.go │ │ ├── delivery_agent.go │ │ ├── food_delivery_service.go │ │ ├── food_delivery_service_demo.go │ │ ├── menu_item.go │ │ ├── order.go │ │ ├── restaurant.go │ │ └── types.go │ ├── go.mod │ ├── hotelmanagementsystem/ │ │ ├── README.md │ │ ├── guest.go │ │ ├── hotel_management.go │ │ ├── hotel_management_demo.go │ │ ├── payment.go │ │ ├── reservation.go │ │ ├── room.go │ │ └── types.go │ ├── librarymanagementsystem/ │ │ ├── README.md │ │ ├── book.go │ │ ├── library_management_system_demo.go │ │ ├── library_manager.go │ │ └── member.go │ ├── linkedin/ │ │ ├── README.md │ │ ├── connection.go │ │ ├── education.go │ │ ├── experience.go │ │ ├── job_posting.go │ │ ├── linkedin_service.go │ │ ├── linkedin_service_demo.go │ │ ├── message.go │ │ ├── notification.go │ │ ├── profile.go │ │ ├── skill.go │ │ ├── types.go │ │ └── user.go │ ├── loggingframework/ │ │ ├── README.md │ │ ├── console_appender.go │ │ ├── database_appender.go │ │ ├── file_appender.go │ │ ├── log_appender.go │ │ ├── log_level.go │ │ ├── log_message.go │ │ ├── logger.go │ │ ├── logger_config.go │ │ └── logging_framework_demo.go │ ├── lrucache/ │ │ ├── README.md │ │ ├── lru_cache.go │ │ └── lru_cache_demo.go │ ├── main.go │ ├── movieticketbookingsystem/ │ │ ├── README.md │ │ ├── booking.go │ │ ├── movie.go │ │ ├── movie_ticket_booking_system.go │ │ ├── movie_ticket_booking_system_demo.go │ │ ├── seat.go │ │ ├── show.go │ │ ├── theater.go │ │ ├── types.go │ │ └── user.go │ ├── musicstreamingservice/ │ │ ├── README.md │ │ ├── album.go │ │ ├── artist.go │ │ ├── music_library.go │ │ ├── music_player.go │ │ ├── music_recommender.go │ │ ├── music_streaming_service.go │ │ ├── music_streaming_service_demo.go │ │ ├── playlist.go │ │ ├── song.go │ │ ├── user.go │ │ └── userManager.go │ ├── onlineauctionsystem/ │ │ ├── README.md │ │ ├── auction_listing.go │ │ ├── auction_status.go │ │ ├── auction_system.go │ │ ├── bid.go │ │ ├── main.go │ │ └── user.go │ ├── onlineshoppingservice/ │ │ ├── README.md │ │ ├── credit_card_payment.go │ │ ├── online_shopping_service.go │ │ ├── online_shopping_service_demo.go │ │ ├── order.go │ │ ├── order_item.go │ │ ├── order_status.go │ │ ├── payment.go │ │ ├── product.go │ │ ├── shopping_cart.go │ │ └── user.go │ ├── onlinestockbrokeragesystem/ │ │ ├── README.md │ │ ├── account.go │ │ ├── buy_order.go │ │ ├── exceptions.go │ │ ├── order.go │ │ ├── portfolio.go │ │ ├── sell_order.go │ │ ├── stock.go │ │ ├── stock_broker.go │ │ ├── stock_broker_demo.go │ │ ├── types.go │ │ └── user.go │ ├── parkinglot/ │ │ ├── README.md │ │ ├── car.go │ │ ├── level.go │ │ ├── motorcycle.go │ │ ├── parking_lot.go │ │ ├── parking_lot_demo.go │ │ ├── parking_spot.go │ │ ├── truck.go │ │ └── vehicle.go │ ├── pubsubsystem/ │ │ ├── README.md │ │ ├── message.go │ │ ├── print_subscriber.go │ │ ├── publisher.go │ │ ├── pubsub_system_demo.go │ │ ├── subscriber.go │ │ └── topic.go │ ├── restaurantmanagementsystem/ │ │ ├── README.md │ │ ├── menu_item.go │ │ ├── order.go │ │ ├── order_status.go │ │ ├── payment.go │ │ ├── payment_method.go │ │ ├── payment_status.go │ │ ├── reservation.go │ │ ├── restaurant.go │ │ ├── restaurant_management_demo.go │ │ └── staff.go │ ├── ridesharingservice/ │ │ ├── README.md │ │ ├── driver.go │ │ ├── driver_status.go │ │ ├── location.go │ │ ├── passenger.go │ │ ├── ride.go │ │ ├── ride_service.go │ │ ├── ride_sharing_service_demo.go │ │ └── ride_status.go │ ├── snakeandladdergame/ │ │ ├── README.md │ │ ├── board.go │ │ ├── dice.go │ │ ├── game_manager.go │ │ ├── ladder.go │ │ ├── player.go │ │ ├── snake.go │ │ ├── snake_and_ladder_demo.go │ │ └── snake_and_ladder_game.go │ ├── socialnetworkingservice/ │ │ ├── README.md │ │ ├── comment.go │ │ ├── notification.go │ │ ├── post.go │ │ ├── social_networking_service.go │ │ ├── social_networking_service_demo.go │ │ ├── types.go │ │ └── user.go │ ├── splitwise/ │ │ ├── README.md │ │ ├── equal_split.go │ │ ├── expense.go │ │ ├── group.go │ │ ├── percent_split.go │ │ ├── split.go │ │ ├── splitwise_demo.go │ │ ├── splitwise_service.go │ │ ├── transaction.go │ │ └── user.go │ ├── stackOverFlow/ │ │ ├── README.md │ │ ├── answer.go │ │ ├── stackoverflow.go │ │ ├── stackoverflow_demo.go │ │ └── types.go │ ├── taskmanagementsystem/ │ │ ├── README.md │ │ ├── task.go │ │ ├── task_management_system_demo.go │ │ ├── task_manager.go │ │ ├── task_status.go │ │ └── user.go │ ├── tictactoe/ │ │ ├── README.md │ │ ├── board.go │ │ ├── game.go │ │ ├── player.go │ │ └── tictactoe_demo.go │ ├── trafficsignalsystem/ │ │ ├── README.md │ │ ├── road.go │ │ ├── signal.go │ │ ├── traffic_controller.go │ │ ├── traffic_light.go │ │ └── traffic_signal_system_demo.go │ ├── vendingmachine/ │ │ ├── README.md │ │ ├── coin.go │ │ ├── inventory.go │ │ ├── note.go │ │ ├── product.go │ │ ├── state.go │ │ ├── vending_machine.go │ │ └── vending_machine_demo.go │ └── votingsystem/ │ └── README.md ├── java/ │ ├── .gitignore │ ├── pom.xml │ ├── src/ │ │ ├── LLDRunner.java │ │ ├── airlinemanagementsystem/ │ │ │ ├── Aircraft.java │ │ │ ├── AirlineManagementSystem.java │ │ │ ├── AirlineManagementSystemDemo.java │ │ │ ├── Passenger.java │ │ │ ├── README.md │ │ │ ├── booking/ │ │ │ │ ├── Booking.java │ │ │ │ ├── BookingManager.java │ │ │ │ └── BookingStatus.java │ │ │ ├── flight/ │ │ │ │ ├── Flight.java │ │ │ │ ├── FlightSearch.java │ │ │ │ └── FlightStatus.java │ │ │ ├── payment/ │ │ │ │ ├── Payment.java │ │ │ │ ├── PaymentProcessor.java │ │ │ │ └── PaymentStatus.java │ │ │ └── seat/ │ │ │ ├── Seat.java │ │ │ ├── SeatStatus.java │ │ │ └── SeatType.java │ │ ├── atm/ │ │ │ ├── ATMDemo.java │ │ │ ├── ATMSystem.java │ │ │ ├── README.md │ │ │ ├── chainofresponsibility/ │ │ │ │ ├── DispenseChain.java │ │ │ │ ├── NoteDispenser.java │ │ │ │ ├── NoteDispenser100.java │ │ │ │ ├── NoteDispenser20.java │ │ │ │ └── NoteDispenser50.java │ │ │ ├── entities/ │ │ │ │ ├── Account.java │ │ │ │ ├── BankService.java │ │ │ │ ├── Card.java │ │ │ │ └── CashDispenser.java │ │ │ ├── enums/ │ │ │ │ └── OperationType.java │ │ │ └── state/ │ │ │ ├── ATMState.java │ │ │ ├── AuthenticatedState.java │ │ │ ├── HasCardState.java │ │ │ └── IdleState.java │ │ ├── carrentalsystem/ │ │ │ ├── Car.java │ │ │ ├── CarRentalSystem.java │ │ │ ├── CarRentalSystemDemo.java │ │ │ ├── CarStatus.java │ │ │ ├── CarType.java │ │ │ ├── Customer.java │ │ │ ├── README.md │ │ │ ├── Reservation.java │ │ │ └── payment/ │ │ │ ├── CreditCardPaymentProcessor.java │ │ │ ├── PayPalPaymentProcessor.java │ │ │ └── PaymentProcessor.java │ │ ├── chessgame/ │ │ │ ├── Board.java │ │ │ ├── Cell.java │ │ │ ├── ChessGame.java │ │ │ ├── ChessGameDemo.java │ │ │ ├── Color.java │ │ │ ├── InvalidMoveException.java │ │ │ ├── Move.java │ │ │ ├── Player.java │ │ │ ├── README.md │ │ │ └── pieces/ │ │ │ ├── Bishop.java │ │ │ ├── King.java │ │ │ ├── Knight.java │ │ │ ├── Pawn.java │ │ │ ├── Piece.java │ │ │ ├── Queen.java │ │ │ └── Rook.java │ │ ├── coffeevendingmachine/ │ │ │ ├── CoffeeVendingMachine.java │ │ │ ├── CoffeeVendingMachineDemo.java │ │ │ ├── Inventory.java │ │ │ ├── README.md │ │ │ ├── decorator/ │ │ │ │ ├── CaramelSyrupDecorator.java │ │ │ │ ├── Coffee.java │ │ │ │ ├── CoffeeDecorator.java │ │ │ │ └── ExtraSugarDecorator.java │ │ │ ├── enums/ │ │ │ │ ├── CoffeeType.java │ │ │ │ ├── Ingredient.java │ │ │ │ └── ToppingType.java │ │ │ ├── factory/ │ │ │ │ └── CoffeeFactory.java │ │ │ ├── state/ │ │ │ │ ├── OutOfIngredientState.java │ │ │ │ ├── PaidState.java │ │ │ │ ├── ReadyState.java │ │ │ │ ├── SelectingState.java │ │ │ │ └── VendingMachineState.java │ │ │ └── templatemethod/ │ │ │ ├── Cappuccino.java │ │ │ ├── Espresso.java │ │ │ └── Latte.java │ │ ├── concertticketbookingsystem/ │ │ │ ├── Booking.java │ │ │ ├── BookingStatus.java │ │ │ ├── Concert.java │ │ │ ├── ConcertTicketBookingSystem.java │ │ │ ├── ConcertTicketBookingSystemDemo.java │ │ │ ├── README.md │ │ │ ├── Seat.java │ │ │ ├── SeatNotAvailableException.java │ │ │ ├── SeatStatus.java │ │ │ ├── SeatType.java │ │ │ └── User.java │ │ ├── courseregistrationsystem/ │ │ │ ├── CourseRegistrationDemo.java │ │ │ ├── CourseRegistrationService.java │ │ │ ├── CourseRegistrationSystemFacade.java │ │ │ ├── README.md │ │ │ ├── chain/ │ │ │ │ ├── CapacityRuleHandler.java │ │ │ │ ├── PrerequisiteRuleHandler.java │ │ │ │ ├── RegistrationRequest.java │ │ │ │ ├── RegistrationRuleHandler.java │ │ │ │ └── ScheduleConflictRuleHandler.java │ │ │ ├── exception/ │ │ │ │ └── RegistrationException.java │ │ │ ├── model/ │ │ │ │ ├── Course.java │ │ │ │ ├── CourseOffering.java │ │ │ │ ├── Professor.java │ │ │ │ ├── Student.java │ │ │ │ └── TimeSlot.java │ │ │ ├── observer/ │ │ │ │ ├── CourseOfferingObserver.java │ │ │ │ └── WaitlistManager.java │ │ │ └── repository/ │ │ │ ├── CourseRepository.java │ │ │ └── StudentRepository.java │ │ ├── cricinfo/ │ │ │ ├── CommentaryManager.java │ │ │ ├── CricInfoService.java │ │ │ ├── CricinfoDemo.java │ │ │ ├── README.md │ │ │ ├── entity/ │ │ │ │ ├── Ball.java │ │ │ │ ├── Innings.java │ │ │ │ ├── Match.java │ │ │ │ ├── Player.java │ │ │ │ ├── PlayerStats.java │ │ │ │ ├── Team.java │ │ │ │ └── Wicket.java │ │ │ ├── enums/ │ │ │ │ ├── ExtraType.java │ │ │ │ ├── MatchStatus.java │ │ │ │ ├── PlayerRole.java │ │ │ │ └── WicketType.java │ │ │ ├── observer/ │ │ │ │ ├── CommentaryDisplay.java │ │ │ │ ├── MatchObserver.java │ │ │ │ ├── ScorecardDisplay.java │ │ │ │ └── UserNotifier.java │ │ │ ├── repository/ │ │ │ │ ├── MatchRepository.java │ │ │ │ └── PlayerRepository.java │ │ │ ├── state/ │ │ │ │ ├── FinishedState.java │ │ │ │ ├── InBreakState.java │ │ │ │ ├── LiveState.java │ │ │ │ ├── MatchState.java │ │ │ │ └── ScheduledState.java │ │ │ └── strategy/ │ │ │ ├── MatchFormatStrategy.java │ │ │ ├── ODIFormatStrategy.java │ │ │ └── T20FormatStrategy.java │ │ ├── digitalwalletservice/ │ │ │ ├── Account.java │ │ │ ├── BankAccount.java │ │ │ ├── CreditCard.java │ │ │ ├── Currency.java │ │ │ ├── CurrencyConverter.java │ │ │ ├── DigitalWallet.java │ │ │ ├── DigitalWalletDemo.java │ │ │ ├── InsufficientFundsException.java │ │ │ ├── PaymentMethod.java │ │ │ └── README.md │ │ ├── elevatorsystem/ │ │ │ ├── Elevator.java │ │ │ ├── ElevatorSystem.java │ │ │ ├── ElevatorSystemDemo.java │ │ │ ├── README.md │ │ │ ├── enums/ │ │ │ │ ├── Direction.java │ │ │ │ └── RequestSource.java │ │ │ ├── models/ │ │ │ │ └── Request.java │ │ │ ├── observer/ │ │ │ │ ├── ElevatorDisplay.java │ │ │ │ └── ElevatorObserver.java │ │ │ ├── state/ │ │ │ │ ├── ElevatorState.java │ │ │ │ ├── IdleState.java │ │ │ │ ├── MovingDownState.java │ │ │ │ └── MovingUpState.java │ │ │ └── strategy/ │ │ │ ├── ElevatorSelectionStrategy.java │ │ │ └── NearestElevatorStrategy.java │ │ ├── filedirectory/ │ │ │ ├── AbstractNode.java │ │ │ ├── DirectoryNode.java │ │ │ ├── FileNode.java │ │ │ ├── FileSystem.java │ │ │ ├── FileSystemDemo.java │ │ │ ├── chainofresponsibility/ │ │ │ │ ├── FileSizeFilter.java │ │ │ │ ├── FilenameFilter.java │ │ │ │ ├── NodeFilter.java │ │ │ │ └── NodeFilterChain.java │ │ │ └── strategy/ │ │ │ ├── FilenameAndSizeSearchStrategy.java │ │ │ └── NodeSearchStrategy.java │ │ ├── fooddeliveryservice/ │ │ │ ├── FoodDeliveryService.java │ │ │ ├── FoodDeliveryServiceDemo.java │ │ │ ├── README.md │ │ │ ├── entity/ │ │ │ │ ├── Address.java │ │ │ │ ├── Customer.java │ │ │ │ ├── DeliveryAgent.java │ │ │ │ ├── Menu.java │ │ │ │ ├── MenuItem.java │ │ │ │ ├── Restaurant.java │ │ │ │ └── User.java │ │ │ ├── observer/ │ │ │ │ └── OrderObserver.java │ │ │ ├── order/ │ │ │ │ ├── Order.java │ │ │ │ ├── OrderItem.java │ │ │ │ └── OrderStatus.java │ │ │ ├── search/ │ │ │ │ ├── RestaurantSearchStrategy.java │ │ │ │ ├── SearchByCityStrategy.java │ │ │ │ ├── SearchByMenuKeywordStrategy.java │ │ │ │ └── SearchByProximityStrategy.java │ │ │ └── strategy/ │ │ │ ├── DeliveryAssignmentStrategy.java │ │ │ └── NearestAvailableAgentStrategy.java │ │ ├── hotelmanagementsystem/ │ │ │ ├── BookingService.java │ │ │ ├── HotelManagementDemo.java │ │ │ ├── HotelManagerFacade.java │ │ │ ├── PaymentService.java │ │ │ ├── README.md │ │ │ ├── RoomService.java │ │ │ ├── decorator/ │ │ │ │ ├── AmenityDecorator.java │ │ │ │ ├── Bookable.java │ │ │ │ ├── BreakfastDecorator.java │ │ │ │ ├── RoomBooking.java │ │ │ │ └── SpaDecorator.java │ │ │ ├── enums/ │ │ │ │ ├── BookingStatus.java │ │ │ │ ├── RoomStyle.java │ │ │ │ └── RoomType.java │ │ │ ├── factory/ │ │ │ │ └── RoomFactory.java │ │ │ ├── model/ │ │ │ │ ├── Booking.java │ │ │ │ ├── Guest.java │ │ │ │ └── Room.java │ │ │ ├── observer/ │ │ │ │ ├── BookingObserver.java │ │ │ │ ├── EmailNotifier.java │ │ │ │ └── SmsNotifier.java │ │ │ ├── payment/ │ │ │ │ ├── CashPayment.java │ │ │ │ ├── CreditCardPayment.java │ │ │ │ └── Payment.java │ │ │ ├── specification/ │ │ │ │ ├── AbstractSpecification.java │ │ │ │ ├── AndSpecification.java │ │ │ │ ├── RoomAvailableSpecification.java │ │ │ │ ├── RoomStyleSpecification.java │ │ │ │ ├── RoomTypeSpecification.java │ │ │ │ └── Specification.java │ │ │ └── state/ │ │ │ ├── AvailableState.java │ │ │ ├── MaintenanceState.java │ │ │ ├── OccupiedState.java │ │ │ └── RoomState.java │ │ ├── librarymanagementsystem/ │ │ │ ├── LibraryManagementDemo.java │ │ │ ├── LibraryManagementSystem.java │ │ │ ├── README.md │ │ │ ├── TransactionService.java │ │ │ ├── enums/ │ │ │ │ └── ItemType.java │ │ │ ├── factory/ │ │ │ │ └── ItemFactory.java │ │ │ ├── models/ │ │ │ │ ├── Book.java │ │ │ │ ├── BookCopy.java │ │ │ │ ├── LibraryItem.java │ │ │ │ ├── Loan.java │ │ │ │ ├── Magazine.java │ │ │ │ └── Member.java │ │ │ ├── state/ │ │ │ │ ├── AvailableState.java │ │ │ │ ├── CheckedOutState.java │ │ │ │ ├── ItemState.java │ │ │ │ └── OnHoldState.java │ │ │ └── strategy/ │ │ │ ├── SearchByAuthorStrategy.java │ │ │ ├── SearchByTitleStrategy.java │ │ │ └── SearchStrategy.java │ │ ├── linkedin/ │ │ │ ├── LinkedInDemo.java │ │ │ ├── LinkedInSystem.java │ │ │ ├── README.md │ │ │ ├── entities/ │ │ │ │ ├── Comment.java │ │ │ │ ├── Connection.java │ │ │ │ ├── Education.java │ │ │ │ ├── Experience.java │ │ │ │ ├── Like.java │ │ │ │ ├── Member.java │ │ │ │ ├── NewsFeed.java │ │ │ │ ├── Notification.java │ │ │ │ ├── Post.java │ │ │ │ └── Profile.java │ │ │ ├── enums/ │ │ │ │ ├── ConnectionStatus.java │ │ │ │ └── NotificationType.java │ │ │ ├── observer/ │ │ │ │ ├── NotificationObserver.java │ │ │ │ └── Subject.java │ │ │ ├── services/ │ │ │ │ ├── ConnectionService.java │ │ │ │ ├── NewsFeedService.java │ │ │ │ ├── NotificationService.java │ │ │ │ └── SearchService.java │ │ │ └── strategy/ │ │ │ ├── ChronologicalSortStrategy.java │ │ │ └── FeedSortingStrategy.java │ │ ├── loggingframework/ │ │ │ ├── AsyncLogProcessor.java │ │ │ ├── LogManager.java │ │ │ ├── Logger.java │ │ │ ├── LoggingFrameworkDemo.java │ │ │ ├── README.md │ │ │ ├── entities/ │ │ │ │ └── LogMessage.java │ │ │ ├── enums/ │ │ │ │ └── LogLevel.java │ │ │ └── strategies/ │ │ │ ├── appender/ │ │ │ │ ├── ConsoleAppender.java │ │ │ │ ├── FileAppender.java │ │ │ │ └── LogAppender.java │ │ │ └── formatter/ │ │ │ ├── LogFormatter.java │ │ │ └── SimpleTextFormatter.java │ │ ├── lrucache/ │ │ │ ├── DoublyLinkedList.java │ │ │ ├── LRUCache.java │ │ │ ├── LRUCacheDemo.java │ │ │ ├── Node.java │ │ │ └── README.md │ │ ├── movieticketbookingsystem/ │ │ │ ├── BookingManager.java │ │ │ ├── MovieBookingDemo.java │ │ │ ├── MovieBookingService.java │ │ │ ├── README.md │ │ │ ├── SeatLockManager.java │ │ │ ├── entities/ │ │ │ │ ├── Booking.java │ │ │ │ ├── Cinema.java │ │ │ │ ├── City.java │ │ │ │ ├── Movie.java │ │ │ │ ├── Payment.java │ │ │ │ ├── Screen.java │ │ │ │ ├── Seat.java │ │ │ │ ├── Show.java │ │ │ │ └── User.java │ │ │ ├── enums/ │ │ │ │ ├── PaymentStatus.java │ │ │ │ ├── SeatStatus.java │ │ │ │ └── SeatType.java │ │ │ ├── observer/ │ │ │ │ ├── MovieObserver.java │ │ │ │ ├── MovieSubject.java │ │ │ │ └── UserObserver.java │ │ │ └── strategy/ │ │ │ ├── payment/ │ │ │ │ ├── CreditCardPaymentStrategy.java │ │ │ │ └── PaymentStrategy.java │ │ │ └── pricing/ │ │ │ ├── PricingStrategy.java │ │ │ ├── WeekdayPricingStrategy.java │ │ │ └── WeekendPricingStrategy.java │ │ ├── musicstreamingservice/ │ │ │ ├── MusicStreamingDemo.java │ │ │ ├── MusicStreamingSystem.java │ │ │ ├── README.md │ │ │ ├── command/ │ │ │ │ ├── Command.java │ │ │ │ ├── NextTrackCommand.java │ │ │ │ ├── PauseCommand.java │ │ │ │ └── PlayCommand.java │ │ │ ├── entities/ │ │ │ │ ├── Album.java │ │ │ │ ├── Artist.java │ │ │ │ ├── Playable.java │ │ │ │ ├── Player.java │ │ │ │ ├── Playlist.java │ │ │ │ ├── Song.java │ │ │ │ └── User.java │ │ │ ├── enums/ │ │ │ │ ├── PlayerStatus.java │ │ │ │ └── SubscriptionTier.java │ │ │ ├── observer/ │ │ │ │ ├── ArtistObserver.java │ │ │ │ └── Subject.java │ │ │ ├── services/ │ │ │ │ ├── RecommendationService.java │ │ │ │ └── SearchService.java │ │ │ ├── state/ │ │ │ │ ├── PausedState.java │ │ │ │ ├── PlayerState.java │ │ │ │ ├── PlayingState.java │ │ │ │ └── StoppedState.java │ │ │ └── strategies/ │ │ │ ├── playback/ │ │ │ │ ├── FreePlaybackStrategy.java │ │ │ │ ├── PlaybackStrategy.java │ │ │ │ └── PremiumPlaybackStrategy.java │ │ │ └── recommendation/ │ │ │ ├── GenreBasedRecommendationStrategy.java │ │ │ └── RecommendationStrategy.java │ │ ├── onlineauctionsystem/ │ │ │ ├── AuctionService.java │ │ │ ├── AuctionSystemDemo.java │ │ │ ├── README.md │ │ │ ├── entities/ │ │ │ │ ├── Auction.java │ │ │ │ ├── Bid.java │ │ │ │ └── User.java │ │ │ ├── enums/ │ │ │ │ └── AuctionStatus.java │ │ │ └── observer/ │ │ │ └── AuctionObserver.java │ │ ├── onlinelearningplatform/ │ │ │ └── README.md │ │ ├── onlineshoppingservice/ │ │ │ ├── OnlineShoppingDemo.java │ │ │ ├── OnlineShoppingSystem.java │ │ │ ├── README.md │ │ │ ├── decorator/ │ │ │ │ ├── GiftWrapDecorator.java │ │ │ │ └── ProductDecorator.java │ │ │ ├── enums/ │ │ │ │ ├── OrderStatus.java │ │ │ │ └── ProductCategory.java │ │ │ ├── exceptions/ │ │ │ │ └── OutOfStockException.java │ │ │ ├── models/ │ │ │ │ ├── Account.java │ │ │ │ ├── Address.java │ │ │ │ ├── CartItem.java │ │ │ │ ├── Customer.java │ │ │ │ ├── Order.java │ │ │ │ ├── OrderLineItem.java │ │ │ │ ├── Product.java │ │ │ │ └── ShoppingCart.java │ │ │ ├── observer/ │ │ │ │ ├── OrderObserver.java │ │ │ │ └── Subject.java │ │ │ ├── services/ │ │ │ │ ├── InventoryService.java │ │ │ │ ├── OrderService.java │ │ │ │ ├── PaymentService.java │ │ │ │ └── SearchService.java │ │ │ ├── state/ │ │ │ │ ├── CancelledState.java │ │ │ │ ├── DeliveredState.java │ │ │ │ ├── OrderState.java │ │ │ │ ├── PlacedState.java │ │ │ │ └── ShippedState.java │ │ │ └── strategy/ │ │ │ ├── CreditCardPaymentStrategy.java │ │ │ ├── PaymentStrategy.java │ │ │ └── UPIPaymentStrategy.java │ │ ├── onlinestockbrokeragesystem/ │ │ │ ├── BuyOrder.java │ │ │ ├── README.md │ │ │ ├── SellOrder.java │ │ │ ├── StockBrokerageSystem.java │ │ │ ├── StockBrokerageSystemDemo.java │ │ │ ├── StockExchange.java │ │ │ ├── command/ │ │ │ │ ├── BuyStockCommand.java │ │ │ │ ├── OrderCommand.java │ │ │ │ └── SellStockCommand.java │ │ │ ├── entities/ │ │ │ │ ├── Account.java │ │ │ │ ├── Order.java │ │ │ │ ├── OrderBuilder.java │ │ │ │ ├── Stock.java │ │ │ │ └── User.java │ │ │ ├── enums/ │ │ │ │ ├── OrderStatus.java │ │ │ │ ├── OrderType.java │ │ │ │ └── TransactionType.java │ │ │ ├── exceptions/ │ │ │ │ ├── InsufficientFundsException.java │ │ │ │ └── InsufficientStockException.java │ │ │ ├── observer/ │ │ │ │ └── StockObserver.java │ │ │ ├── state/ │ │ │ │ ├── CancelledState.java │ │ │ │ ├── FilledState.java │ │ │ │ ├── OpenState.java │ │ │ │ └── OrderState.java │ │ │ └── strategy/ │ │ │ ├── ExecutionStrategy.java │ │ │ ├── LimitOrderStrategy.java │ │ │ └── MarketOrderStrategy.java │ │ ├── parkinglot/ │ │ │ ├── ParkingLot.java │ │ │ ├── ParkingLotDemo.java │ │ │ ├── README.md │ │ │ ├── entities/ │ │ │ │ ├── ParkingFloor.java │ │ │ │ ├── ParkingSpot.java │ │ │ │ └── ParkingTicket.java │ │ │ ├── strategy/ │ │ │ │ ├── fee/ │ │ │ │ │ ├── FeeStrategy.java │ │ │ │ │ ├── FlatRateFeeStrategy.java │ │ │ │ │ └── VehicleBasedFeeStrategy.java │ │ │ │ └── parking/ │ │ │ │ ├── BestFitStrategy.java │ │ │ │ ├── FarthestFirstStrategy.java │ │ │ │ ├── NearestFirstStrategy.java │ │ │ │ └── ParkingStrategy.java │ │ │ └── vehicle/ │ │ │ ├── Bike.java │ │ │ ├── Car.java │ │ │ ├── Truck.java │ │ │ ├── Vehicle.java │ │ │ └── VehicleSize.java │ │ ├── pubsubsystem/ │ │ │ ├── PubSubDemo.java │ │ │ ├── PubSubService.java │ │ │ ├── README.md │ │ │ ├── entities/ │ │ │ │ ├── Message.java │ │ │ │ └── Topic.java │ │ │ └── subscriber/ │ │ │ ├── AlertSubscriber.java │ │ │ ├── NewsSubscriber.java │ │ │ └── Subscriber.java │ │ ├── restaurantmanagementsystem/ │ │ │ ├── README.md │ │ │ ├── RestaurantManagementSystem.java │ │ │ ├── RestaurantManagementSystemDemo.java │ │ │ ├── RestaurantManagementSystemFacade.java │ │ │ ├── command/ │ │ │ │ ├── Command.java │ │ │ │ ├── PrepareOrderCommand.java │ │ │ │ └── ServeOrderCommand.java │ │ │ ├── decorator/ │ │ │ │ ├── BaseBill.java │ │ │ │ ├── Bill.java │ │ │ │ ├── BillComponent.java │ │ │ │ ├── BillDecorator.java │ │ │ │ ├── ServiceChargeDecorator.java │ │ │ │ └── TaxDecorator.java │ │ │ ├── enums/ │ │ │ │ └── TableStatus.java │ │ │ ├── model/ │ │ │ │ ├── Chef.java │ │ │ │ ├── Menu.java │ │ │ │ ├── MenuItem.java │ │ │ │ ├── Order.java │ │ │ │ ├── OrderItem.java │ │ │ │ ├── Restaurant.java │ │ │ │ ├── Staff.java │ │ │ │ ├── Table.java │ │ │ │ └── Waiter.java │ │ │ ├── observer/ │ │ │ │ └── OrderObserver.java │ │ │ └── state/ │ │ │ ├── OrderItemState.java │ │ │ ├── OrderedState.java │ │ │ ├── PreparingState.java │ │ │ ├── ReadyForPickupState.java │ │ │ └── ServedState.java │ │ ├── ridesharingservice/ │ │ │ ├── README.md │ │ │ ├── RideSharingService.java │ │ │ ├── RideSharingServiceDemo.java │ │ │ ├── entities/ │ │ │ │ ├── Driver.java │ │ │ │ ├── Location.java │ │ │ │ ├── Trip.java │ │ │ │ ├── User.java │ │ │ │ └── Vehicle.java │ │ │ ├── enums/ │ │ │ │ ├── DriverStatus.java │ │ │ │ ├── RideType.java │ │ │ │ └── TripStatus.java │ │ │ ├── observer/ │ │ │ │ ├── Rider.java │ │ │ │ └── TripObserver.java │ │ │ ├── state/ │ │ │ │ ├── AssignedState.java │ │ │ │ ├── CompletedState.java │ │ │ │ ├── InProgressState.java │ │ │ │ ├── RequestedState.java │ │ │ │ └── TripState.java │ │ │ └── strategy/ │ │ │ ├── matching/ │ │ │ │ ├── DriverMatchingStrategy.java │ │ │ │ └── NearestDriverMatchingStrategy.java │ │ │ └── pricing/ │ │ │ ├── FlatRatePricingStrategy.java │ │ │ ├── PricingStrategy.java │ │ │ └── VehicleBasedPricingStrategy.java │ │ ├── snakeandladdergame/ │ │ │ ├── Game.java │ │ │ ├── README.md │ │ │ ├── SnakeAndLadderDemo.java │ │ │ ├── enums/ │ │ │ │ └── GameStatus.java │ │ │ └── models/ │ │ │ ├── Board.java │ │ │ ├── BoardEntity.java │ │ │ ├── Dice.java │ │ │ ├── Ladder.java │ │ │ ├── Player.java │ │ │ └── Snake.java │ │ ├── socialnetworkingservice/ │ │ │ ├── README.md │ │ │ ├── SocialNetworkDemo.java │ │ │ ├── SocialNetworkFacade.java │ │ │ ├── model/ │ │ │ │ ├── Comment.java │ │ │ │ ├── CommentableEntity.java │ │ │ │ ├── Post.java │ │ │ │ └── User.java │ │ │ ├── observer/ │ │ │ │ ├── PostObserver.java │ │ │ │ └── UserNotifier.java │ │ │ ├── repository/ │ │ │ │ ├── PostRepository.java │ │ │ │ └── UserRepository.java │ │ │ ├── service/ │ │ │ │ ├── NewsFeedService.java │ │ │ │ ├── PostService.java │ │ │ │ └── UserService.java │ │ │ └── strategy/ │ │ │ ├── ChronologicalStrategy.java │ │ │ └── NewsFeedGenerationStrategy.java │ │ ├── splitwise/ │ │ │ ├── README.md │ │ │ ├── SplitwiseDemo.java │ │ │ ├── SplitwiseService.java │ │ │ ├── entities/ │ │ │ │ ├── BalanceSheet.java │ │ │ │ ├── Expense.java │ │ │ │ ├── Group.java │ │ │ │ ├── Split.java │ │ │ │ ├── Transaction.java │ │ │ │ └── User.java │ │ │ └── strategy/ │ │ │ ├── EqualSplitStrategy.java │ │ │ ├── ExactSplitStrategy.java │ │ │ ├── PercentageSplitStrategy.java │ │ │ └── SplitStrategy.java │ │ ├── stackoverflow/ │ │ │ ├── README.md │ │ │ ├── StackOverflowDemo.java │ │ │ ├── StackOverflowService.java │ │ │ ├── entities/ │ │ │ │ ├── Answer.java │ │ │ │ ├── Comment.java │ │ │ │ ├── Content.java │ │ │ │ ├── Event.java │ │ │ │ ├── Post.java │ │ │ │ ├── Question.java │ │ │ │ ├── Tag.java │ │ │ │ └── User.java │ │ │ ├── enums/ │ │ │ │ ├── EventType.java │ │ │ │ └── VoteType.java │ │ │ ├── observer/ │ │ │ │ ├── PostObserver.java │ │ │ │ └── ReputationManager.java │ │ │ └── strategy/ │ │ │ ├── KeywordSearchStrategy.java │ │ │ ├── SearchStrategy.java │ │ │ ├── TagSearchStrategy.java │ │ │ └── UserSearchStrategy.java │ │ ├── taskmanagementsystem/ │ │ │ ├── README.md │ │ │ ├── TaskManagementSystem.java │ │ │ ├── TaskManagementSystemDemo.java │ │ │ ├── enums/ │ │ │ │ ├── TaskPriority.java │ │ │ │ └── TaskStatus.java │ │ │ ├── models/ │ │ │ │ ├── ActivityLog.java │ │ │ │ ├── Comment.java │ │ │ │ ├── Tag.java │ │ │ │ ├── Task.java │ │ │ │ ├── TaskList.java │ │ │ │ └── User.java │ │ │ ├── observer/ │ │ │ │ ├── ActivityLogger.java │ │ │ │ └── TaskObserver.java │ │ │ ├── state/ │ │ │ │ ├── DoneState.java │ │ │ │ ├── InProgressState.java │ │ │ │ ├── TaskState.java │ │ │ │ └── TodoState.java │ │ │ └── strategy/ │ │ │ ├── SortByDueDate.java │ │ │ ├── SortByPriority.java │ │ │ └── TaskSortStrategy.java │ │ ├── tictactoe/ │ │ │ ├── Game.java │ │ │ ├── README.md │ │ │ ├── TicTacToeDemo.java │ │ │ ├── TicTacToeSystem.java │ │ │ ├── enums/ │ │ │ │ ├── GameStatus.java │ │ │ │ └── Symbol.java │ │ │ ├── exceptions/ │ │ │ │ └── InvalidMoveException.java │ │ │ ├── models/ │ │ │ │ ├── Board.java │ │ │ │ ├── Cell.java │ │ │ │ └── Player.java │ │ │ ├── observer/ │ │ │ │ ├── GameObserver.java │ │ │ │ ├── GameSubject.java │ │ │ │ └── Scoreboard.java │ │ │ ├── state/ │ │ │ │ ├── DrawState.java │ │ │ │ ├── GameState.java │ │ │ │ ├── InProgressState.java │ │ │ │ └── WinnerState.java │ │ │ └── strategy/ │ │ │ ├── ColumnWinningStrategy.java │ │ │ ├── DiagonalWinningStrategy.java │ │ │ ├── RowWinningStrategy.java │ │ │ └── WinningStrategy.java │ │ ├── trafficsignalcontrolsystem/ │ │ │ ├── IntersectionController.java │ │ │ ├── README.md │ │ │ ├── TrafficControlSystem.java │ │ │ ├── TrafficLight.java │ │ │ ├── TrafficSystemDemo.java │ │ │ ├── enums/ │ │ │ │ ├── Direction.java │ │ │ │ └── LightColor.java │ │ │ ├── observer/ │ │ │ │ ├── CentralMonitor.java │ │ │ │ └── TrafficObserver.java │ │ │ └── states/ │ │ │ ├── intersection/ │ │ │ │ ├── EastWestGreenState.java │ │ │ │ ├── IntersectionState.java │ │ │ │ └── NorthSouthGreenState.java │ │ │ └── light/ │ │ │ ├── GreenState.java │ │ │ ├── RedState.java │ │ │ ├── SignalState.java │ │ │ └── YellowState.java │ │ ├── vendingmachine/ │ │ │ ├── README.md │ │ │ ├── VendingMachine.java │ │ │ ├── VendingMachineDemo.java │ │ │ ├── entity/ │ │ │ │ ├── Inventory.java │ │ │ │ └── Item.java │ │ │ ├── enums/ │ │ │ │ └── Coin.java │ │ │ └── state/ │ │ │ ├── DispensingState.java │ │ │ ├── HasMoneyState.java │ │ │ ├── IdleState.java │ │ │ ├── ItemSelectedState.java │ │ │ └── VendingMachineState.java │ │ └── votingsystem/ │ │ ├── Candidate.java │ │ ├── README.md │ │ ├── VoteRecord.java │ │ ├── Voter.java │ │ ├── VotingSystem.java │ │ └── VotingSystemDemo.java │ └── test/ │ └── coffeevendingmachine/ │ └── CoffeeVendingMachineTest.java ├── python/ │ ├── .gitignore │ ├── airlinemanagementsystem/ │ │ └── README.md │ ├── atm/ │ │ └── README.md │ ├── carrentalsystem/ │ │ └── README.md │ ├── chessgame/ │ │ └── README.md │ ├── coffeevendingmachine/ │ │ └── README.md │ ├── concertticketbookingsystem/ │ │ └── README.md │ ├── courseregistrationsystem/ │ │ └── README.md │ ├── cricinfo/ │ │ └── README.md │ ├── digitalwalletservice/ │ │ └── README.md │ ├── elevatorsystem/ │ │ └── README.md │ ├── fooddeliveryservice/ │ │ └── README.md │ ├── hotelmanagementsystem/ │ │ └── README.md │ ├── librarymanagementsystem/ │ │ └── README.md │ ├── linkedin/ │ │ └── README.md │ ├── loggingframework/ │ │ └── README.md │ ├── lrucache/ │ │ └── README.md │ ├── movieticketbookingsystem/ │ │ └── README.md │ ├── musicstreamingservice/ │ │ └── README.md │ ├── onlineauctionsystem/ │ │ └── README.md │ ├── onlinestockbrokeragesystem/ │ │ └── README.md │ ├── parkinglot/ │ │ └── README.md │ ├── pubsubsystem/ │ │ └── README.md │ ├── restaurantmanagementsystem/ │ │ └── README.md │ ├── ridesharingservice/ │ │ └── README.md │ ├── snakeandladdergame/ │ │ └── README.md │ ├── socialnetworkingservice/ │ │ └── README.md │ ├── splitwise/ │ │ └── README.md │ ├── stackoverflow/ │ │ └── README.md │ ├── taskmanagementsystem/ │ │ └── README.md │ ├── tictactoe/ │ │ └── README.md │ ├── trafficsignalsystem/ │ │ └── README.md │ ├── vendingmachine/ │ │ └── README.md │ └── votingsystem/ │ └── README.md └── typescript/ ├── .gitignore ├── README.md ├── package.json ├── src/ │ ├── CoffeeVendingMachine/ │ │ ├── CoffeeRecipe.ts │ │ ├── CoffeeVendingMachine.ts │ │ ├── CoffeeVendingMachineDemo.ts │ │ ├── Dispenser.ts │ │ ├── IngredientStore.ts │ │ ├── Payment.ts │ │ ├── PaymentProcessor.ts │ │ └── README.md │ ├── LoggingFramework/ │ │ ├── Appender/ │ │ │ ├── ConsoleLogAppender.ts │ │ │ ├── FileLogAppender.ts │ │ │ └── LogAppender.ts │ │ ├── LogFormatter/ │ │ │ ├── LogFormatter.ts │ │ │ └── SimpleLogFormatter.ts │ │ ├── LogLevel.ts │ │ ├── LogManager.ts │ │ ├── LogMessage.ts │ │ ├── Logger.ts │ │ ├── LoggingFrameworkDemo.ts │ │ └── README.md │ ├── ParkingLot/ │ │ ├── Floor.ts │ │ ├── Main.ts │ │ ├── ParkingLot.ts │ │ ├── Spot.ts │ │ ├── Vehicle.ts │ │ ├── readme.md │ │ └── types.ts │ ├── StackOverflow/ │ │ ├── Answer.ts │ │ ├── Comment.ts │ │ ├── Commentable.ts │ │ ├── Question.ts │ │ ├── README.md │ │ ├── ReputationType.ts │ │ ├── StackOverflow.ts │ │ ├── StackOverflowDemo.ts │ │ ├── Tag.ts │ │ ├── User.ts │ │ ├── Votable.ts │ │ ├── Vote.ts │ │ └── VoteTypeEnum.ts │ ├── TaskManagement/ │ │ ├── ActivityLog.ts │ │ ├── Comment.ts │ │ ├── README.md │ │ ├── SortingStrategy/ │ │ │ ├── SortByDueDate.ts │ │ │ ├── SortByPriority.ts │ │ │ └── TaskSortingStrategy.ts │ │ ├── Task.ts │ │ ├── TaskList.ts │ │ ├── TaskManagementSystem.ts │ │ ├── TaskManagementSystemDemo.ts │ │ ├── TaskPriorityEnum.ts │ │ ├── TaskStatusEnum.ts │ │ └── User.ts │ ├── TrafficSignalSystem/ │ │ ├── Direction.ts │ │ ├── Intersection.ts │ │ ├── README.md │ │ ├── SignalState/ │ │ │ ├── GreenState.ts │ │ │ ├── RedState.ts │ │ │ ├── SignalState.ts │ │ │ └── YellowState.ts │ │ ├── TrafficLight.ts │ │ ├── TrafficSignalController.ts │ │ └── TrafficSignalSystemDemo.ts │ ├── VendingMachine/ │ │ ├── Coin.ts │ │ ├── Inventory.ts │ │ ├── Item.ts │ │ ├── README.md │ │ ├── VendingMachine.ts │ │ ├── VendingMachineDemo.ts │ │ └── VendingMachineState/ │ │ ├── DispensingState.ts │ │ ├── HasMoneyState.ts │ │ ├── IdleState.ts │ │ ├── ItemSelectedState.ts │ │ └── VendingMachineState.ts │ └── lldrunner.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea/ .vscode/ solutions/java/.idea/ solutions/java/out/ solutions/c++/.idea/ solutions/c#/bin/ solutions/c#/obj/ *.py ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================

Join Free Newsletter

This repository contains resources to learn Low Level Design (LLD) / Object Oriented Design (OOD) and prepare for interviews. It covers OOP fundamentals, design patterns, UML, concurrency and commonly asked interview questions. 👉 For a better and more comprehensive experience, checkout the [LLD page at AlgoMaster.io](https://algomaster.io/learn/lld) ## 🧱 OOP Fundamentals - [Classes and Objects](https://algomaster.io/learn/lld/classes-and-objects) - [Enums](https://algomaster.io/learn/lld/enums) - [Interfaces](https://algomaster.io/learn/lld/interfaces) - [Encapsulation](https://algomaster.io/learn/lld/encapsulation) - [Abstraction](https://algomaster.io/learn/lld/abstraction) - [Inheritance](https://algomaster.io/learn/lld/inheritance) - [Polymorphism](https://algomaster.io/learn/lld/polymorphism) ## 🔗 Class Relationships - [Association](https://algomaster.io/learn/lld/association) - [Aggregation](https://algomaster.io/learn/lld/aggregation) - [Composition](https://algomaster.io/learn/lld/composition) - [Dependency](https://algomaster.io/learn/lld/dependency) ## 🧭 Design Principles - [DRY Principle](https://algomaster.io/learn/lld/dry) - [YAGNI Principle](https://algomaster.io/learn/lld/yagni) - [KISS Principle](https://algomaster.io/learn/lld/kiss) - [SOLID Principles with Pictures](https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898) - [SOLID Principles with Code](https://blog.algomaster.io/p/solid-principles-explained-with-code) ## 🧩 Design Patterns | **Creational Patterns** | **Structural Patterns** | **Behavioral Patterns** | | ----------------------------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | [Singleton](https://algomaster.io/learn/lld/singleton) | [Adapter](https://algomaster.io/learn/lld/adapter) | [Iterator](https://algomaster.io/learn/lld/iterator) | | [Factory Method](https://algomaster.io/learn/lld/factory-method) | [Bridge](https://algomaster.io/learn/lld/bridge) | [Observer](https://algomaster.io/learn/lld/observer) | | [Abstract Factory](https://algomaster.io/learn/lld/abstract-factory) | [Composite](https://algomaster.io/learn/lld/composite) | [Strategy](https://algomaster.io/learn/lld/strategy) | | [Builder](https://algomaster.io/learn/lld/builder) | [Decorator](https://algomaster.io/learn/lld/decorator) | [Command](https://algomaster.io/learn/lld/command) | | [Prototype](https://algomaster.io/learn/lld/prototype) | [Facade](https://algomaster.io/learn/lld/facade) | [State](https://algomaster.io/learn/lld/state) | | | [Flyweight](https://algomaster.io/learn/lld/flyweight) | [Template Method](https://algomaster.io/learn/lld/template-method) | | | [Proxy](https://algomaster.io/learn/lld/proxy) | [Visitor](https://algomaster.io/learn/lld/visitor) | | | | [Mediator](https://algomaster.io/learn/lld/mediator) | | | | [Memento](https://algomaster.io/learn/lld/memento) | | | | [Chain of Responsibility](https://algomaster.io/learn/lld/chain-of-responsibility) | ## 🗂️ UML - [Class Diagram](https://algomaster.io/learn/lld/class-diagram) - [Use Case Diagram](https://algomaster.io/learn/lld/use-case-diagram) - [Sequence Diagram](https://algomaster.io/learn/lld/sequence-diagram) - [Activity Diagram](https://algomaster.io/learn/lld/activity-diagram) - [State Machine Diagram](https://algomaster.io/learn/lld/state-machine-diagram) ## ⏱️ Concurrency and Multi-threading Concepts ### Concurrency 101 - [Introduction to Concurrency](https://algomaster.io/learn/concurrency-interview/introduction-to-concurrency) - [Concurrency vs Parallelism](https://algomaster.io/learn/concurrency-interview/concurrency-vs-parallelism) - [Processes vs Threads](https://algomaster.io/learn/concurrency-interview/processes-vs-threads) - [Thread Lifecycle and States](https://algomaster.io/learn/concurrency-interview/thread-lifecycle-and-states) - [Race Conditions and Critical Sections](https://algomaster.io/learn/concurrency-interview/race-conditions-and-critical-sections) ### Synchronization Primitives - [Mutex (Mutual Exclusion)](https://algomaster.io/learn/concurrency-interview/mutex) - [Semaphores](https://algomaster.io/learn/concurrency-interview/semaphores) - [Condition Variables](https://algomaster.io/learn/concurrency-interview/condition-variables) - [Coarse-grained vs Fine-grained Locking](https://algomaster.io/learn/concurrency-interview/coarse-vs-fine-grained-locking) - [Reentrant Locks](https://algomaster.io/learn/concurrency-interview/reentrant-locks) - [Try-Lock and Timed Locking](https://algomaster.io/learn/concurrency-interview/try-lock-and-timed-locking) - [Compare-and-Swap (CAS)](https://algomaster.io/learn/concurrency-interview/compare-and-swap) ### Concurrency Challenges - [Deadlock](https://algomaster.io/learn/concurrency-interview/deadlock) - [Livelock](https://algomaster.io/learn/concurrency-interview/livelock) ### Concurrency Patterns - [Signaling Pattern](https://algomaster.io/learn/concurrency-interview/signaling-pattern) - [Thread Pool Pattern](https://algomaster.io/learn/concurrency-interview/thread-pool-pattern) - [Producer-Consumer Pattern](https://algomaster.io/learn/concurrency-interview/producer-consumer-pattern) - [Reader-Writer Pattern](https://algomaster.io/learn/concurrency-interview/reader-writer-pattern) ## ✅ [How to Answer a LLD Interview Problem](https://blog.algomaster.io/p/how-to-answer-a-lld-interview-problem) ## 💻 Low Level Design Interview Problems ### Easy Problems - [Design Parking Lot](problems/parking-lot.md) - [Design Stack Overflow](problems/stack-overflow.md) - [Design a Vending Machine](problems/vending-machine.md) - [Design Logging Framework](problems/logging-framework.md) - [Design Traffic Signal Control System](problems/traffic-signal.md) - [Design Coffee Vending Machine](problems/coffee-vending-machine.md) - [Design a Task Management System](problems/task-management-system.md) ### Medium Problems - [Design ATM](problems/atm.md) - [Design LinkedIn](problems/linkedin.md) - [Design LRU Cache](problems/lru-cache.md) - [Design Tic Tac Toe Game](problems/tic-tac-toe.md) - [Design Pub Sub System](problems/pub-sub-system.md) - [Design an Elevator System](problems/elevator-system.md) - [Design Car Rental System](problems/car-rental-system.md) - [Design an Online Auction System](problems/online-auction-system.md) - [Design Hotel Management System](problems/hotel-management-system.md) - [Design a Digital Wallet Service](problems/digital-wallet-service.md) - [Design Airline Management System](problems/airline-management-system.md) - [Design a Library Management System](problems/library-management-system.md) - [Design a Social Network like Facebook](problems/social-networking-service.md) - [Design Restaurant Management System](problems/restaurant-management-system.md) - [Design a Concert Ticket Booking System](problems/concert-ticket-booking-system.md) ### Hard Problems - [Design CricInfo](problems/cricinfo.md) - [Design Splitwise](problems/splitwise.md) - [Design Chess Game](problems/chess-game.md) - [Design a Snake and Ladder game](problems/snake-and-ladder.md) - [Design Ride-Sharing Service like Uber](problems/ride-sharing-service.md) - [Design Course Registration System](problems/course-registration-system.md) - [Design Movie Ticket Booking System](problems/movie-ticket-booking-system.md) - [Design Online Shopping System like Amazon](problems/online-shopping-service.md) - [Design Online Stock Brokerage System](problems/online-stock-brokerage-system.md) - [Design Music Streaming Service like Spotify](problems/music-streaming-service.md) - [Design Online Food Delivery Service like Swiggy](problems/food-delivery-service.md) ## ⏱️ Concurrency and Multi-threading Problems - [Print FooBar Alternately](https://algomaster.io/learn/concurrency-interview/print-foobar-alternately) - [Print Zero Even Odd](https://algomaster.io/learn/concurrency-interview/print-zero-even-odd) - [Fizz Buzz Multithreaded](https://algomaster.io/learn/concurrency-interview/fizz-buzz-multithreaded) - [Building H2O Molecule](https://algomaster.io/learn/concurrency-interview/building-h2o) - [Design Thread-Safe Cache with TTL](https://algomaster.io/learn/concurrency-interview/design-thread-safe-cache-with-ttl) - [Design Concurrent HashMap](https://algomaster.io/learn/concurrency-interview/design-concurrent-hashmap) - [Design Thread-Safe Blocking Queue](https://algomaster.io/learn/concurrency-interview/design-thread-safe-blocking-queue) - [Design Concurrent Bloom Filter](https://algomaster.io/learn/concurrency-interview/design-concurrent-bloom-filter) - [Multi-threaded Merge Sort](https://algomaster.io/learn/concurrency-interview/multi-threaded-merge-sort) ## 📇 Courses - [Master LLD Interviews - AlgoMaster.io](https://algomaster.io/learn/lld/course-introduction) - [Master Concurrency Interviews - AlgoMaster.io](https://algomaster.io/learn/concurrency-interview) ## 📚 Books - [Head First Design Patterns](https://www.amazon.in/dp/9385889753) - [Clean Code](https://www.amazon.in/dp/B001GSTOAM) - [Refactoring: Improving the Design of Existing Code](https://www.amazon.in/dp/0134757599) ## 📩 Newsletter - [AlgoMaster Newsletter](https://blog.algomaster.io/) ## Additional resources - [Coursera - Object-Oriented Design](https://www.coursera.org/learn/object-oriented-design) - [Coursera - Design Patterns](https://www.coursera.org/learn/design-patterns) - [Github - Awesome Design Patterns](https://github.com/DovAmir/awesome-design-patterns) ## 🤝 Contributing Contributions are welcome! If you'd like to add a new problem, improve existing content, or fix errors: 1. Fork the repository 2. Create a feature branch: `git checkout -b feature/your-feature-name` 3. Commit your changes: `git commit -m 'Add some feature'` 4. Push to the branch: `git push origin feature/your-feature-name` 5. Submit a pull request Please make sure to update Readme files and documentation as appropriate. ---

If you find this resource helpful, please give it a star and share it with others!

================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Chain of Responsibilites/main.js ================================================ const { InternetConnectionTeam, InternetSupportTeam, PhoneConnectionTeam, PhoneSupportTeam, } = require("./supportRequest"); const phoneSupport = new PhoneSupportTeam(null); const phoneConnection = new PhoneConnectionTeam(phoneSupport); const internetSupport = new InternetSupportTeam(phoneConnection); const internetConnection = new InternetConnectionTeam(internetSupport); console.log("Problem 1 - internet connection"); internetConnection.handleRequest("internet", "newConnection"); console.log("Problem 2 - phone connection"); internetConnection.handleRequest("phone", "problem"); console.log("Problem 3 - phone support"); internetConnection.handleRequest("phone", "problem"); console.log("Problem 4 - Invalid support"); internetConnection.handleRequest("Laptop", "problem"); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Chain of Responsibilites/supportRequest.js ================================================ // Creating a chain for attaining support team class supportHandler { constructor(nextHandler) { this.nextHandler = nextHandler; } // Method to handle the request handleRequest(request, type) { if (this.nextHandler) { console.log("Passing to the next executive team to resolve your issue"); this.nextHandler.handleRequest(request, type); } else { console.log("No further handlers available to process the request."); } } } // First level internet support team for connection class InternetConnectionTeam extends supportHandler { handleRequest(request, type) { if (request === "internet" && type === "newConnection") { console.log("Your newConnection request is taken. Thank you! 🙂"); } else if (request === "internet" && type === "problem") { console.log( "Seems you have an issue; we will redirect to the support team" ); super.handleRequest(request, type); // Transferring to the next team } else { console.log( "Unknown request type in InternetConnectionTeam. Passing to next team." ); super.handleRequest(request, type); // Transfer to the next team } } } // Second level internet support team for problem class InternetSupportTeam extends supportHandler { handleRequest(request, type) { if (request === "internet" && type === "problem") { console.log("Your internet request is taken. Thank you! 🙂"); } else { console.log( "Unknown request type in InternetSupportTeam. Passing to next team." ); super.handleRequest(request, type); // Transferring to the next team } } } // Third level connection class PhoneConnectionTeam extends supportHandler { handleRequest(request, type) { if (request === "phone" && type === "newConnection") { console.log("Your newConnection request is taken. Thank you! 🙂"); } else if (request === "phone" && type === "problem") { console.log( "Seems you have an issue; we will redirect to the support team" ); super.handleRequest(request, type); // Transferring to the next team } else { console.log( "Unknown request type in PhoneConnectionTeam. Passing to next team." ); super.handleRequest(request, type); // Transferring to the next team } } } // Last level phone support team for problem class PhoneSupportTeam extends supportHandler { handleRequest(request, type) { if (request === "phone" && type === "problem") { console.log("Your phone request is taken. Thank you! 🙂"); } else { console.log( "Unknown request type in PhoneSupportTeam. This is the last support level." ); } } } // Main module export module.exports = { InternetConnectionTeam, InternetSupportTeam, PhoneConnectionTeam, PhoneSupportTeam, }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Command Design Pattern/command.js ================================================ // Abstract Command class Command { execute() {} } // Concrete Command class LightOnCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOn(); } } class LightOffCommand extends Command { constructor(light) { super(); this.light = light; } execute() { this.light.turnOff(); } } // Concrete Command to turn on the fan class FanOnCommand extends Command { constructor(fan) { super(); this.fan = fan; } execute() { this.fan.turnOn(); } } // Concrete Command to turn off the fan class FanOffCommand extends Command { constructor(fan) { super(); this.fan = fan; } execute() { this.fan.turnOff(); } } module.exports = { LightOnCommand, LightOffCommand, FanOnCommand, FanOffCommand, }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Command Design Pattern/invoker.js ================================================ // Invoker class class RemoteControl { setCommand(command) { this.command = command; } pressButton() { this.command.execute(); } } module.exports = {RemoteControl} ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Command Design Pattern/main.js ================================================ // Client code const { LightOnCommand, LightOffCommand, FanOnCommand, FanOffCommand, } = require("./command"); const{Light, Fan} = require('./receiver') const {RemoteControl} = require ('./invoker') const light = new Light(); const fan = new Fan(); const lightOn = new LightOnCommand(light); const lightOff = new LightOffCommand(light); const fanOn = new FanOnCommand(fan); const fanOff = new FanOffCommand(fan); const remote = new RemoteControl(); // Turning on the light remote.setCommand(lightOn); remote.pressButton(); // Output: "The light is on." // Turning off the light remote.setCommand(lightOff); remote.pressButton(); // Output: "The light is off." // Turning on the fan remote.setCommand(fanOn); remote.pressButton(); // Output: "The fan is on." // Turning off the fan remote.setCommand(fanOff); remote.pressButton(); // Output: "The fan is off." ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Command Design Pattern/receiver.js ================================================ // Receiver for Light class Light { turnOn() { console.log("The light is on."); } turnOff() { console.log("The light is off."); } } // Receiver for Fan class Fan { turnOn() { console.log("The fan is on."); } turnOff() { console.log("The fan is off."); } } module.exports = { Light, Fan }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Iterator Design Pattern/aggregate.js ================================================ const { LibraryIterator } = require("./iterator"); const Book = require("./book"); class Aggregate { createIterator() { throw new Error("Method 'createIterator()' must be implemented."); } } class ConcreteAggregate extends Aggregate { constructor() { super(); this.books = []; } addBook(book) { this.books.push(book); } createIterator() { return new LibraryIterator(this.books); } } module.exports = ConcreteAggregate; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Iterator Design Pattern/book.js ================================================ class Book { constructor(title, author) { this.title = title; this.author = author; } getDetails() { return `${this.title} by ${this.author}`; } } module.exports = Book; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Iterator Design Pattern/iterator.js ================================================ class Iterator { next() { throw new Error("Method 'next()' must be implemented."); } hasNext() { throw new Error("Method 'hasNext()' must be implemented."); } } // Concrete Iterator class LibraryIterator extends Iterator { constructor(collection) { super(); this.collection = collection; this.index = 0; } hasNext() { return this.index < this.collection.length; } next() { console.log("Current index: " + this.index); return this.collection[this.index++]; } } module.exports = { Iterator, LibraryIterator }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Iterator Design Pattern/main.js ================================================ const ConcreteAggregate = require("./aggregate"); const Book = require("./book"); const library = new ConcreteAggregate(); // Adding books to the library library.addBook(new Book("To Kill a Mockingbird", "Harper Lee")); library.addBook(new Book("1984", "George Orwell")); library.addBook(new Book("The Great Gatsby", "F. Scott Fitzgerald")); library.addBook(new Book("Moby Dick", "Herman Melville")); // Creating an iterator for the library const iterator = library.createIterator(); // Iterating through the collection of books while (iterator.hasNext()) { const book = iterator.next(); console.log(book.getDetails()); } ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Mediator Design Pattern/main.js ================================================ // Client code to handle users registration and messages communication const User = require("./user"); const ChatRoom = require("./mediator"); // Object for chatRoom (mediator) const chatRoom = new ChatRoom(); // Objects for users const user1 = new User("User1", chatRoom); const user2 = new User("User2", chatRoom); const user3 = new User("User3", chatRoom); // Register users with chatRoom chatRoom.register(user1); chatRoom.register(user2); chatRoom.register(user3); // Send message user1.send("Hello everyone!"); user2.send("Hi User1!"); user3.send("Hi User2!"); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Mediator Design Pattern/mediator.js ================================================ // Abstract Mediator class Mediator { register(user) { throw new Error("Method 'register()' must be implemented"); } send(message, user) { throw new Error("Method 'send()' must be implemented"); } } // Concrete Mediator class ChatRoom extends Mediator { constructor() { super(); this.users = []; } register(user) { this.users.push(user); } send(message, from) { this.users.forEach((user) => { if (user !== from) { // send senderMessage only to other users user.receive(message, from); } }); } } module.exports = ChatRoom; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Mediator Design Pattern/user.js ================================================ class User { constructor(name, mediator) { this.name = name; this.mediator = mediator; } send(message) { console.log(`${this.name} sent: ${message}`); this.mediator.send(message, this); } receive(message) { console.log(`${this.name} receives message: ${message}`); } } module.exports = User; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/Example2/canvas.js ================================================ // Import CanvasMemento from memento.js const CanvasMemento = require("./memento"); // <-- Add this line class DrawingCanvas { constructor() { this.shapes = []; // The current shapes drawn on the canvas } // Method to draw a new shape addShape(shape) { this.shapes.push(shape); } // Method to remove the last added shape (simulating undo) removeLastShape() { this.shapes.pop(); } // Create a memento (save the current state) save() { return new CanvasMemento([...this.shapes]); // Copy the current shapes to a new Memento } // Restore the canvas state from a memento restore(memento) { this.shapes = memento.getState(); // Replace current shapes with the saved shapes } // Print all shapes (to simulate displaying them on the canvas) show() { console.log("Current shapes on canvas:", this.shapes); } } module.exports = DrawingCanvas; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/Example2/careTaker.js ================================================ // CareTaker -> Manages mementos class History { constructor() { this.mementos = []; // List of saved mementos } // Save a memento saveMemento(memento) { this.mementos.push(memento); } // Get a memento getMemento(index) { return this.mementos[index]; } // Remove the last memento removeMemento() { return this.mementos.pop(); } getLatestMemento() { return this.mementos.length > 0 ? this.mementos[this.mementos.length - 1] : null; } removeLastMemento() { if (this.mementos.length > 0) { this.mementos.pop(); } } } module.exports = History; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/Example2/main.js ================================================ const DrawingCanvas = require('./canvas'); const CanvasMemento = require('./memento'); const History = require('./careTaker'); // Create a new drawing canvas (Originator) const canvas = new DrawingCanvas(); // Create a new History (Caretaker) const history = new History(); // Draw some shapes on the canvas canvas.addShape("Circle"); canvas.addShape("Square"); // Show current state of canvas console.log("Initial Drawing:"); canvas.show(); // Output: Circle, Square // Save the current state of the canvas history.saveMemento(canvas.save()); // Save: Circle, Square // Draw more shapes canvas.addShape("Triangle"); canvas.addShape("Hexagon"); // Show current state of canvas console.log("\nAfter Drawing More Shapes:"); canvas.show(); // Output: Circle, Square, Triangle, Hexagon // Save the current state again history.saveMemento(canvas.save()); // Save: Circle, Square, Triangle, Hexagon // Draw another shape canvas.addShape("Pentagon"); // Show current state of canvas console.log("\nAfter Adding Pentagon:"); canvas.show(); // Output: Circle, Square, Triangle, Hexagon, Pentagon // Undo the last action by restoring the previous memento canvas.restore(history.getLatestMemento()); history.removeLastMemento(); // Remove the latest snapshot console.log("\nAfter Undo (Restoring Previous State):"); canvas.show(); // Output: Circle, Square, Triangle, Hexagon // Undo another action canvas.restore(history.getLatestMemento()); history.removeLastMemento(); // Remove the latest snapshot console.log("\nAfter Another Undo:"); canvas.show(); // Output: Circle, Square ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/Example2/memento.js ================================================ // Memento -> Stores the snapshot of canvas state class CanvasMemento { constructor(state) { this.state = state; // The saved shapes at this point } // Returns the saved state getState() { return this.state; } } module.exports = CanvasMemento; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/careTaker.js ================================================ // careTaker.js class CareTaker { constructor() { this.mementos = []; } saveMemento(memento) { this.mementos.push(memento); } getMemento(index) { return this.mementos[index]; } } module.exports = CareTaker; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/main.js ================================================ const TextEditor = require("./orginator"); const Caretaker = require("./careTaker"); // Create a TextEditor instance const textEditor = new TextEditor(); const caretaker = new Caretaker(); // Write some content textEditor.write("Hello, "); caretaker.saveMemento(textEditor.save()); // Save the current state textEditor.write("world!"); console.log(textEditor.getContent()); // Output: "Hello, world!" caretaker.saveMemento(textEditor.save()); // Save the current state again textEditor.write(" How are you?"); console.log(textEditor.getContent()); // Output: "Hello, world! How are you?" // Restore to the previous state textEditor.restore(caretaker.getMemento(1)); console.log(textEditor.getContent()); // Output: "Hello, world!" // Restore to the initial state textEditor.restore(caretaker.getMemento(0)); console.log(textEditor.getContent()); // Output: "Hello, " ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/memento.js ================================================ // Memento class Memento { constructor(state) { this.state = state; } getState() { return this.state; } } module.exports = Memento; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Memento Design Pattern/orginator.js ================================================ // Orginator file const Memento = require("./memento"); class TextEditor { constructor() { this.content = ""; } write(content) { this.content += content; } getContent() { return this.content; } save() { return new Memento(this.content); } restore(memento) { this.content = memento.getState(); } } module.exports = TextEditor; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Observer Design Pattern/main.js ================================================ const { WebUI, MobileUI } = require("./observer"); const WeatherStation = require("./publisher"); // Create a WeatherStation instance const weatherStation = new WeatherStation(); // Create observers const webUI = new WebUI(); const mobileUI = new MobileUI(); // Register observers with the weather station weatherStation.addObserver(webUI); weatherStation.addObserver(mobileUI); // Change the temperature weatherStation.setTemperature(25); // Notify the data all observers weatherStation.setTemperature(30); // Notify the updated data all observers // Adding another observer const webUI2 = new WebUI(); weatherStation.addObserver(webUI2); weatherStation.setTemperature(35); // Removing an observer weatherStation.removeObserver(webUI); weatherStation.setTemperature(40); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Observer Design Pattern/observer.js ================================================ class Observer { update(temperature) { throw new Error("Method 'update()' must be implemented"); } } class WebUI extends Observer { update(temperature) { console.log(`Temperature showing in web UI: ${temperature}`); } } class MobileUI extends Observer { update(temperature) { console.log(`Temperature showing in mobile UI: ${temperature}`); } } module.exports = { WebUI, MobileUI, }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Observer Design Pattern/publisher.js ================================================ class WeatherStation { constructor() { this.observers = []; this.temperature = 0; } //Method to add Subscribers to the list addObserver(observer) { this.observers.push(observer); } // Remove Subscribers from the list removeObserver(observer) { this.observers = this.observers.filter((obs) => obs !== observer); } // Notify all subscribers notifyObservers() { this.observers.forEach((observer) => observer.update(this.temperature)); } //Method to set the temperature setTemperature(temperature) { this.temperature = temperature; this.notifyObservers(); } } module.exports = WeatherStation; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/State Design Pattern/context.js ================================================ const {Idle} = require("./state"); // Context Class class Phone { constructor() { this.state = new Idle(); // Inital state } setState(state) { this.state = state; } alert() { this.state.alert(); } answer() { this.state.answer(this); } hangup() { this.state.hangup(this); } } module.exports = Phone; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/State Design Pattern/main.js ================================================ const Phone = require("./context"); const {Ringing} = require("./state"); const phone = new Phone(); phone.alert(); // Output: Phone is idle. phone.answer(); // Output: No incoming call to answer. phone.setState(new Ringing()); phone.alert(); // Output: Phone is ringing... phone.answer(); // Output: Answering the call. phone.alert(); // Output: Phone is in a call. phone.hangup(); // Output: Hanging up the call. phone.alert(); // Output: Phone is idle. ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/State Design Pattern/state.js ================================================ // Abstract class for phoneState class PhoneState { alert() {} answer() {} hangup() {} } // Concerte Class for phoneState // State-1 : Phone is in Ringing State class Ringing extends PhoneState { alert() { console.log("Phone is ringing..."); } answer(context) { console.log("Phone is answering..."); context.setState(new InCall()); } hangup() { console.log("Cannot hangup while ringing"); } } // State-2 : Phone is in InCall State class InCall extends PhoneState { alert() { console.log("Phone is in call..."); } answer() { console.log("Cannot answer while in call"); } hangup(context) { console.log("Phone is hanging up..."); context.setState(new Idle()); } } // State-3 : Phone is in Idle State class Idle extends PhoneState { alert() { console.log("Phone is idle..."); } answer() { console.log("Phone is answering..."); this.hangup(); } hangup() { console.log("Cannot hangup while idle"); } } module.exports = { Ringing, InCall, Idle }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Strategy Design Pattern/main.js ================================================ const ShoppinCart = require("./shoppingCart_Context"); const { Cash, UPI, Card, InternetBanking } = require("./paymentStrategy"); // Creating a shopping cart Instance const shoppingCart = new ShoppinCart(); // Adding items to the shopping cart shoppingCart.addItem({ name: "Laptop", price: 500 }); shoppingCart.addItem({ name: "Mobile", price: 200 }); shoppingCart.addItem({ name: "TV", price: 1000 }); // View cart after adding items shoppingCart.viewCart(); // Checkout in method - 1 shoppingCart.setPaymentMethod(new Card(123456789, 123)); shoppingCart.checkout(); // Checkout in method - 2 shoppingCart.setPaymentMethod(new Cash(123)); shoppingCart.checkout(); // Checkout in method - 3 shoppingCart.setPaymentMethod(new UPI(123456789, 123)); shoppingCart.checkout(); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Strategy Design Pattern/paymentStrategy.js ================================================ // Strategy class // Abstract class class PaymentGateway { pay(amount) { throw new Error("Method 'pay()' must be implemented!"); } } // Concrete class for paymentGateway // Cash payment method class Cash extends PaymentGateway { pay(amount) { console.log(`Payment of ${amount} done using Cash`); } } // UPI payment method class UPI extends PaymentGateway { constructor(UPI_ID, UPI_PIN) { super(); this.UPI_ID = UPI_ID; this.UPI_PIN = UPI_PIN; } pay(amount) { console.log( `Payment of ${amount} done using UPI with ID ${this.UPI_ID} and PIN ${this.UPI_PIN}` ); } } // Card payment method class Card extends PaymentGateway { constructor(cardNumber, CVV) { super(); this.cardNumber = cardNumber; this.CVV = CVV; } pay(amount) { console.log( `Payment of ${amount} done using Card Number ${this.cardNumber} and CVV ${this.CVV}` ); } } // Internet Banking payment method class InternetBanking extends PaymentGateway { constructor(accountNumber, IFSC) { super(); this.accountNumber = accountNumber; this.IFSC = IFSC; } pay(amount) { console.log( `Payment of ${amount} done using Internet Banking with Account Number ${this.accountNumber} and IFSC ${this.IFSC}` ); } } module.exports = { Cash, UPI, Card, InternetBanking }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Strategy Design Pattern/shoppingCart_Context.js ================================================ // Context file as shoppingCart class class ShoppinCart { constructor() { this.items = []; this.paymentMethod = null; } // Adding items to the shopping cart addItem(item) { this.items.push(item); } // View cart after adding items viewCart() { console.log("Your cart contains: "); this.items.forEach((item, index) => { console.log(`${index + 1}. ${item.name} - $${item.price}`); }); } // Selecting the payment method setPaymentMethod(paymentMethod) { this.paymentMethod = paymentMethod; } // Checkout checkout() { // Adding reduce method to calculate the total bill const Total = this.items.reduce((total, item) => total + item.price, 0); // Checks if paymentMethod is choosen to proceed for checkout if (this.paymentMethod) { console.log(`Total Bill: $${Total}`); this.paymentMethod.pay(Total); } else { console.log("Please confirm your payment method"); } } } module.exports = ShoppinCart; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Template Design Pattern/beverages.js ================================================ // Abstract class in Template Pattern class Food { prepareFood() { this.boilWater(); this.brew(); this.pourInCup(); this.addCondiments(); this.noNeedVegetables(); // Setting as optional from template pattern } boilWater() { console.log("Boiling the water..."); } brew() { throw new error("Method 'brew()' must be implemented"); } pourInCup() { console.log("Pouring into cup..."); } addCondiments() { throw new error("Method 'addCondiments()' must be implemented"); } // private method noNeedVegetables() { if (this.shouldAddVegetables()) { this.addVegetables(); } } addVegetables() { console.log("No vegetables added here!"); } // Default is set to false shouldAddVegetables() { return false; } } module.exports = Food; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Template Design Pattern/beveragesTypes.js ================================================ // Concrete classes for Food // Make using of superClasses from templatePattern and modifying here (subClasses) const Food = require("./beverages"); class Tea extends Food { brew() { console.log("Steeping the tea..."); } addCondiments() { console.log("Adding lemon..."); } addVegetables() { console.log("Adding mint leaves to tea..."); } shouldAddVegetables() { return true; // Tea includes vegetables } } class Coffee extends Food { brew() { console.log("Dripping coffee through filter..."); } addCondiments() { console.log("Adding sugar and milk..."); } } module.exports = { Tea, Coffee }; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Template Design Pattern/main.js ================================================ const { Tea, Coffee } = require("./beveragesTypes"); // Meal 1 console.log("Preparing Tea.."); const tea = new Tea(); tea.prepareFood(); console.log(""); // For spacing // Meal 2 console.log("Preparing Coffee.."); const coffee = new Coffee(); coffee.prepareFood(); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Visitor Design Pattern/element.js ================================================ // element.js class Shape { accept(visitor) { throw new Error("This method should be overridden!"); } } class Circle extends Shape { constructor(radius) { super(); this.radius = radius; } accept(visitor) { visitor.visitCircle(this); } } class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } accept(visitor) { visitor.visitRectangle(this); } } module.exports = {Circle,Rectangle}; ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Visitor Design Pattern/main.js ================================================ const { Circle, Rectangle } = require("./element"); const { AreaVisitor, PerimeterVisitor } = require("./visitor"); const shapes = [ new Circle(5), new Rectangle(10, 20), ]; // Create visitors const areaVisitor = new AreaVisitor(); const perimeterVisitor = new PerimeterVisitor(); // Calculate areas console.log("Calculating Areas:"); shapes.forEach((shape) => { shape.accept(areaVisitor); }); // Calculate perimeters console.log("\nCalculating Perimeters:"); shapes.forEach((shape) => { shape.accept(perimeterVisitor); }); ================================================ FILE: design-patterns/Javascript/Behavioral Pattern/Visitor Design Pattern/visitor.js ================================================ // Visitor Interface class ShapeVisitor { visitCircle(circle) { throw new Error(`This circle method should be overridden!`); } visitRectangle(rectangle) { throw new Error(`This rectangke method should be overridden!`); } } // Concrete visitor classes class AreaVisitor extends ShapeVisitor { visitCircle(circle) { const area = Math.PI * circle.radius * circle.radius; console.log(`Aread of circle: ${area}`); } visitRectangle(rectangle) { const area = rectangle.width * rectangle.height; console.log(`Area of rectangle: ${area}`); } } class PerimeterVisitor extends ShapeVisitor { visitCircle(circle) { const perimeter = 2 * Math.PI * circle.radius; console.log(`Perimeter of circle: ${perimeter}`); } visitRectangle(rectangle) { const perimeter = 2 * (rectangle.width + rectangle.height); console.log(`Perimeter of rectangle: ${perimeter}`); } } module.exports = { AreaVisitor, PerimeterVisitor }; ================================================ FILE: design-patterns/Javascript/Creational Pattern/AbstractFactory Design Pattern/abstract.js ================================================ // Abstract product class Chair { sitOn() { throw new error("Sitting on chair"); } } class Sofa { lieOn() { throw new error("Lying on sofa"); } } // Concrete product for modernStyle class ModernChair extends Chair { sitOn() { console.log("Sitting on modern chair"); } } class ModernSofa extends Sofa { lieOn() { console.log("Lying on modern sofa"); } } // Concrete product for classicStyle class ClassicChair extends Chair { sitOn() { console.log("Sitting on classic chair"); } } class ClassicSofa extends Sofa { lieOn() { console.log("Lying on classic sofa"); } } // Abstract factory class FurnitureFactory { createChair() { throw new error("Creating chair"); } createSofa() { throw new error("Creating sofa"); } } // Concrete factory for modernStyle class ModernFurnitureFactory extends FurnitureFactory { createChair() { return new ModernChair(); } createSofa() { return new ModernSofa(); } } // Concrete factory for classicStyle class ClassicFurnitureFactory extends FurnitureFactory { createChair() { return new ClassicChair(); } createSofa() { return new ClassicSofa(); } } module.exports = { ModernFurnitureFactory, ClassicFurnitureFactory, }; ================================================ FILE: design-patterns/Javascript/Creational Pattern/AbstractFactory Design Pattern/main.js ================================================ const { ModernFurnitureFactory, ClassicFurnitureFactory, } = require("./abstract"); function createFurniture(factory) { const chair = factory.createChair(); const sofa = factory.createSofa(); chair.sitOn(); sofa.lieOn(); } // Use the Modern Furniture Factory const modernFactory = new ModernFurnitureFactory(); createFurniture(modernFactory); // Use the Victorian Furniture Factory const classicFactory = new ClassicFurnitureFactory(); createFurniture(classicFactory); ================================================ FILE: design-patterns/Javascript/Creational Pattern/Builder Design Pattern/app.js ================================================ const ComputerBuilder = require("./computerBuilder"); const myComputer = new ComputerBuilder("Intel", "4GB") .addStorage("1TB") .addMoniter("LG") .build(); // Finally build the computer console.log(myComputer); ================================================ FILE: design-patterns/Javascript/Creational Pattern/Builder Design Pattern/computerBuilder.js ================================================ class Computer { constructor(builder) { this.cpu = builder.cpu; this.ram = builder.ram; this.hardDisk = builder.hardDisk; this.moniter = builder.moniter; } } class ComputerBuilder { constructor(cpu, ram) { this.cpu = cpu; this.ram = ram; } // Methods with chaining addStorage(hardDisk) { this.hardDisk = hardDisk; return this; } addMoniter(moniter) { this.moniter = moniter; return this; } build() { return new Computer(this); // Pass the builder methods to the computer } } module.exports = ComputerBuilder; ================================================ FILE: design-patterns/Javascript/Creational Pattern/Factory Design Pattern/factory.js ================================================ const { cheesePizza, pepperoniPizza } = require("./pizza"); class pizzaFactory { static createPizza(pizzaType) { if (pizzaType === "cheese") { return new cheesePizza(); } else if (pizzaType === "pepperoni") { return new pepperoniPizza(); } else { throw new Error("Invalid pizza type"); } } } module.exports = pizzaFactory; ================================================ FILE: design-patterns/Javascript/Creational Pattern/Factory Design Pattern/main.js ================================================ const pizzaFactory = require("./factory"); function main() { const pizzaType = process.argv[2] || "cheese"; try { const pizza = pizzaFactory.createPizza(pizzaType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } catch (error) { console.log(error.message); } } main(); ================================================ FILE: design-patterns/Javascript/Creational Pattern/Factory Design Pattern/pizza.js ================================================ class Pizza { prepare() { throw new error('Method "prepare()" must be implemented'); } bake() { console.log("Baking for 25 minutes"); } cut() { console.log("Cutting the pizza"); } box() { console.log("boxing the pizza"); } } class cheesePizza extends Pizza { prepare() { console.log("Preparing cheese pizza"); } } class pepperoniPizza extends Pizza { prepare() { console.log("Preparing pepperoni pizza"); } } module.exports = { cheesePizza, pepperoniPizza, }; ================================================ FILE: design-patterns/Javascript/Creational Pattern/Prototype Design Pattern/app.js ================================================ class Car{ constructor(model, year, color){ this.model = model; this.year = year; this.color = color; } clone(){ // Clone method to clone the current object return new Car(this.model, this.year, this.color); // Return the new object with same properties } getDetails(){ return `Model: ${this.model}, Year: ${this.year}, Color: ${this.color}` } } const prototypeCar = new Car("Mustang", 2019, "red"); const cloneCar1 = prototypeCar.clone(); // 1st clone cloneCar1.color = "blue"; const cloneCar2 = prototypeCar.clone(); // 2nd clone cloneCar2.color = "green"; console.log(prototypeCar.getDetails()); console.log(cloneCar1.getDetails()); console.log(cloneCar2.getDetails()); ================================================ FILE: design-patterns/Javascript/Creational Pattern/Singleton Design Pattern/app.js ================================================ // Importing const singleton = require("./singleton"); const Singleton1 = require("./singleton"); const Singleton2 = require("./singleton"); Singleton1.increment(); console.log(Singleton1.getData()); console.log(Singleton2.getData()); console.log(Singleton1 === Singleton2); // True ================================================ FILE: design-patterns/Javascript/Creational Pattern/Singleton Design Pattern/singleton.js ================================================ //Variable to hold the instance let instance = null; class Singleton { constructor() { if (instance) { //check if instance already exists return instance; //return existing instance } this.data = 0; instance = this; } // Method to modify data increment() { this.data += 1; } // Method to get the current data getData() { return this.data; } } module.exports = new Singleton(); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Adapter Design Pattern/adapter.js ================================================ // usbAdapter.js // No need to import USB_A_Connector here class USB_Adapter { constructor(connector) { this.connector = connector; // Store the USB-A connector instance } plugIn() { return this.connector.connect(); // Use the method of the passed instances } } module.exports = USB_Adapter; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Adapter Design Pattern/main.js ================================================ const USB_A_Connector = require("./usbA_connector"); const Adapter = require("./adapter"); // Creating instances for imported classes const usbAConnector = new USB_A_Connector(); const adapter = new Adapter(usbAConnector); console.log(adapter.plugIn()); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Adapter Design Pattern/usbA_connector.js ================================================ // USB A plug class // Old system class USB_A_Connector { connect() { return "USB-A connector connected"; } } module.exports = USB_A_Connector; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Adapter Design Pattern/usbC_device.js ================================================ // Device class to connect USB A cable // New system class USB_C_Device { plugIn() { return "USB C device connected"; } } module.exports = USB_C_Device; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Bridge Design Pattern/device.js ================================================ // Device.js // The Device interface class Device { turnOn() { throw new Error("Method 'turnOn()' must be implemented."); } turnOff() { throw new Error("Method 'turnOff()' must be implemented."); } } // Concrete class for TV class TV extends Device { turnOn() { console.log("TV is now ON."); } turnOff() { console.log("TV is now OFF."); } } // Concrete class for Radio class Radio extends Device { turnOn() { console.log("Radio is now ON."); } turnOff() { console.log("Radio is now OFF."); } } // Exporting the device classes module.exports = { TV, Radio, }; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Bridge Design Pattern/main.js ================================================ // main.js const { TV, Radio } = require("./device"); const RemoteControl = require("./remoteControl"); // Creating instances of devices const tv = new TV(); const radio = new Radio(); // Creating a remote control for the TV const tvRemote = new RemoteControl(tv); tvRemote.pressOn(); tvRemote.pressOff(); // Creating a remote control for the Radio const radioRemote = new RemoteControl(radio); radioRemote.pressOn(); radioRemote.pressOff(); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Bridge Design Pattern/remoteControl.js ================================================ // RemoteControl.js class RemoteControl { constructor(device) { this.device = device; // This is the bridge to the device } pressOn() { this.device.turnOn(); // Call the device's turnOn method } pressOff() { this.device.turnOff(); // Call the device's turnOff method } } module.exports = RemoteControl; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Composite Design Pattern/app.js ================================================ const File = require("./file"); const Folder = require("./folder"); // Let's create some files with random file extensions const file1 = new File("File1.js"); const file2 = new File("File2.py"); const file3 = new File("File3.cpp"); const file4 = new File("File4.txt"); const file5 = new File("File5.docx"); const file6 = new File("File6.xlsx"); const file7 = new File("File7.pptx"); const file8 = new File("File8.pdf"); const file9 = new File("File9.png"); const file10 = new File("File10.jpg"); // Let's create a folder to add files const folder1 = new Folder("Folder1"); folder1.add(file1); folder1.add(file2); folder1.add(file4); const folder2 = new Folder("Folder2"); folder2.add(file3); folder2.add(file8); const folder3 = new Folder("Folder3"); folder3.add(file5); folder3.add(file9); folder3.add(file10); const folder4 = new Folder("Folder4"); folder4.add(file6); folder4.add(file7); // Let's create a root folder const rootFolder = new Folder("Root"); rootFolder.add(folder1); rootFolder.add(folder2); rootFolder.add(folder3); rootFolder.add(folder4); // Let's show the details from the root folder rootFolder.showDetails(); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Composite Design Pattern/component.js ================================================ // Abstract Class or Component class class Component { showDetails() { throw new error("This method is overriden by subclasses"); } } module.exports = Component; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Composite Design Pattern/file.js ================================================ const Component = require("./component"); class File extends Component { constructor(name) { super(); this.name = name; } showDetails() { console.log(`File: ${this.name}`); } } module.exports = File; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Composite Design Pattern/folder.js ================================================ const Component = require("./component"); // Composite: Folder that can hold files or other folders class Folder extends Component { constructor(name) { super(); this.name = name; this.files = []; } add(file) { this.files.push(file); } showDetails() { console.log(`Folder: ${this.name}`); this.files.forEach((file) => file.showDetails()); } } module.exports = Folder; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Decorator Design Pattern/additional.js ================================================ // Additional behavior class class Cream { constructor(coffee) { this.coffee = coffee; } cost() { return this.coffee.cost() + 5; // Add cost of cream to the base coffee class } } class Sugar { constructor(coffee) { this.coffee = coffee; // Store the coffee instance } cost() { return this.coffee.cost() + 2; // Add cost of sugar to the base coffee class } } class Ice{ constructor(coffee) { this.coffee = coffee; // Store the coffee instance } cost() { return this.coffee.cost() + 1; // Add cost of ice to the base coffee class } } module.exports = {Cream, Sugar, Ice}; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Decorator Design Pattern/coffee.js ================================================ // Base class component class Coffee { cost() { return 10; // Base price of coffee is 10 } } module.exports = Coffee; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Decorator Design Pattern/main.js ================================================ const Coffee = require("./coffee"); const {Cream, Sugar, Ice} = require("./additional"); // Create an instance of coffee let myCoffee = new Coffee(); console.log(`Base amount: ${myCoffee.cost()}`); // Get base cost of coffee myCoffee = new Sugar(myCoffee); console.log(`Sugar amount: ${myCoffee.cost()}`); // Add cost of sugar myCoffee = new Cream(myCoffee); console.log(`Cream amount: ${myCoffee.cost()}`); // Add cost of cream myCoffee = new Ice(myCoffee); console.log(`Ice amount: ${myCoffee.cost()}`); // Add cost of ice ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/dvdPlayer.js ================================================ // Class for DVD player functionality class DVDPlayer { on() { console.log("DVD player is on"); } play(movie) { console.log(`Playing ${movie}`); } off() { console.log("DVD player is off"); } } module.exports = DVDPlayer; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/lights.js ================================================ // Class for lights functionality class Lights { on() { console.log("Lights on, take you're seat!"); } off() { console.log("Lights off, get ready to see the show!"); } } module.exports = Lights; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/main.js ================================================ // client code for facade design pattern const MovieFacade = require("./movieFacade"); const movieFacade = new MovieFacade(); // By getting the required data, we can proceed all the functionality using facade design pattern. movieFacade.watchMovie("Goat 🍾🎉"); movieFacade.getSnacks("Popcorn"); movieFacade.endMovie(); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/movieFacade.js ================================================ const SoundSystem = require("./soundSystem"); const DVDPlayer = require("./dvdPlayer"); const Projector = require("./projector"); const Lights = require("./lights"); const Snacks = require("./snacks"); class MovieFacade { constructor() { this.soundSystem = new SoundSystem(); this.dvdPlayer = new DVDPlayer(); this.projector = new Projector(); this.lights = new Lights(); this.snacks = new Snacks(); } watchMovie(movie) { console.log(`Starting to watch a movie ${movie}`); this.lights.on(); this.projector.on(); this.projector.connect("DVD Player"); this.dvdPlayer.on(); this.soundSystem.on(); this.dvdPlayer.play(movie); this.soundSystem.setVolume("High"); } getSnacks(snacks) { console.log("1st part of the movie is great! Let's order some snacks"); this.snacks.noteOrder(snacks); this.snacks.prepare(); this.snacks.serve(snacks); } endMovie() { console.log("End of the movie, shutting down"); this.lights.off(); this.projector.off(); this.dvdPlayer.off(); this.soundSystem.off(); } } module.exports = MovieFacade; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/projector.js ================================================ // Class for projector functionality class Projector { on() { console.log("Projector on"); } connect(source) { console.log(`Connecting projector to ${source}`); } off() { console.log("Projector off"); } } module.exports = Projector; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/snacks.js ================================================ // Class for snacks functionality class Snacks { noteOrder(snacks) { console.log(`Ordering ${snacks}`); } prepare() { console.log("Preparing snacks 🍿"); } serve(snacks) { console.log(`Here is your ${snacks} sir!, enjoy your movie 😊`); } } module.exports = Snacks; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Facade Design Pattern/soundSystem.js ================================================ // Class for sound system functionality class SoundSystem { on() { console.log("Sound system is on"); } setVolume(volume) { console.log(`Setting volume to ${volume}`); } off() { console.log("Sound system is off"); } } module.exports = SoundSystem; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Flyweight Design Pattern/circle.js ================================================ // Intrinsic state class Circle{ constructor(color){ this.color = color; } draw(size, x, y){ console.log(`Drawing a circle of size ${size} at position (${x}, ${y})`); } } module.exports = Circle; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Flyweight Design Pattern/circleFactory.js ================================================ // circleFactory.js const Circle = require("./circle"); class CircleFactory { constructor() { this.circles = {}; // Store the created circles } getCircle(color) { // Check if the circle exists if (!this.circles[color]) { // Create a new circle if it doesn't exist this.circles[color] = new Circle(color); } return this.circles[color]; } } module.exports = CircleFactory; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Flyweight Design Pattern/main.js ================================================ const CircleFactory = require("./circleFactory"); const circleFactory = new CircleFactory(); const redCircle = circleFactory.getCircle("red"); redCircle.draw("big", 20, 30); const blueCircle = circleFactory.getCircle("blue"); blueCircle.draw("medium", 200, 300); const greenCircle = circleFactory.getCircle("red"); greenCircle.draw("medium", 200, 300); // Here it won't create a new object as it already exists. console.log( `Total unique circle instance created are: ${ Object.keys(circleFactory.circles).length }` ); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Proxy Design Pattern/main.js ================================================ const proxyImage = require("./proxyImage"); const image = new proxyImage("test.jpg"); console.log('First call to display:'); image.display(); console.log('Second call to display:'); image.display(); ================================================ FILE: design-patterns/Javascript/Structural Pattern/Proxy Design Pattern/proxyImage.js ================================================ // Proxy object const realImage = require("./real_Image"); class ProxyImage { constructor(fileName) { this.fileName = fileName; this.realImage = null; // LAZY LOADING (Image not loaded yet) } display() { // Loading the image only if requested if (!this.realImage) { this.realImage = new realImage(this.fileName); } this.realImage.display(); } } module.exports = ProxyImage; ================================================ FILE: design-patterns/Javascript/Structural Pattern/Proxy Design Pattern/real_Image.js ================================================ class realImage { constructor(fileName) { this.fileName = fileName; this.loadFromDisk(); } loadFromDisk() { console.log(`Loading image from disk: ${this.fileName}`); } display() { console.log(`Displaying image: ${this.fileName}`); } } module.exports = realImage; ================================================ FILE: design-patterns/cpp/adapter/in_house_payment_processor.cpp ================================================ #include "in_house_payment_processor.h" #include #include #include void InHousePaymentProcessor::processPayment(double amount, const std::string& currency) { std::cout << "InHousePaymentProcessor: Processing payment of " << amount << " " << currency << std::endl; // Process payment logic auto now = std::chrono::system_clock::now(); auto now_ms = std::chrono::duration_cast(now.time_since_epoch()); transactionId = "TXN_" + std::to_string(now_ms.count()); isPaymentSuccessful = true; std::cout << "InHousePaymentProcessor: Payment successful. Txn ID: " << transactionId << std::endl; } bool InHousePaymentProcessor::isPaymentSuccessful() { return isPaymentSuccessful; } std::string InHousePaymentProcessor::getTransactionId() { return transactionId; } ================================================ FILE: design-patterns/cpp/adapter/in_house_payment_processor.h ================================================ #pragma once #include "payment_processor.h" #include class InHousePaymentProcessor : public PaymentProcessor { public: void processPayment(double amount, const std::string& currency) override; bool isPaymentSuccessful() override; std::string getTransactionId() override; private: std::string transactionId; bool isPaymentSuccessful = false; }; ================================================ FILE: design-patterns/cpp/adapter/legacy_gateway.cpp ================================================ #include "legacy_gateway.h" #include #include void LegacyGateway::executeTransaction(double totalAmount, const std::string& currency) { std::cout << "LegacyGateway: Executing transaction for " << currency << " " << totalAmount << std::endl; auto now = std::chrono::high_resolution_clock::now(); transactionReference = now.time_since_epoch().count(); isPaymentSuccessful = true; std::cout << "LegacyGateway: Transaction executed successfully. Txn ID: " << transactionReference << std::endl; } bool LegacyGateway::checkStatus(long transactionReference) { std::cout << "LegacyGateway: Checking status for ref: " << transactionReference << std::endl; return isPaymentSuccessful; } long LegacyGateway::getReferenceNumber() { return transactionReference; } ================================================ FILE: design-patterns/cpp/adapter/legacy_gateway.h ================================================ #pragma once #include class LegacyGateway { public: void executeTransaction(double totalAmount, const std::string& currency); bool checkStatus(long transactionReference); long getReferenceNumber(); private: long transactionReference; bool isPaymentSuccessful = false; }; ================================================ FILE: design-patterns/cpp/adapter/legacy_gateway_adapter.cpp ================================================ #include "legacy_gateway_adapter.h" #include LegacyGatewayAdapter::LegacyGatewayAdapter(LegacyGateway* legacyGateway) : legacyGateway(legacyGateway) {} void LegacyGatewayAdapter::processPayment(double amount, const std::string& currency) { std::cout << "LegacyGatewayAdapter: Processing payment of " << amount << " " << currency << std::endl; legacyGateway->executeTransaction(amount, currency); std::cout << "LegacyGatewayAdapter: Payment processed successfully. Txn ID: " << legacyGateway->getReferenceNumber() << std::endl; } bool LegacyGatewayAdapter::isPaymentSuccessful() { return legacyGateway->checkStatus(legacyGateway->getReferenceNumber()); } std::string LegacyGatewayAdapter::getTransactionId() { return std::to_string(legacyGateway->getReferenceNumber()); } ================================================ FILE: design-patterns/cpp/adapter/legacy_gateway_adapter.h ================================================ #pragma once #include "payment_processor.h" #include "legacy_gateway.h" class LegacyGatewayAdapter : public PaymentProcessor { public: explicit LegacyGatewayAdapter(LegacyGateway* legacyGateway); void processPayment(double amount, const std::string& currency) override; bool isPaymentSuccessful() override; std::string getTransactionId() override; private: LegacyGateway* legacyGateway; }; ================================================ FILE: design-patterns/cpp/adapter/main.cpp ================================================ #include "in_house_payment_processor.h" #include "legacy_gateway.h" #include "legacy_gateway_adapter.h" #include int main() { std::cout << "Adapter Pattern Demo\n" << std::endl; // Using the new payment processor std::cout << "Using InHousePaymentProcessor:" << std::endl; PaymentProcessor* processor = new InHousePaymentProcessor(); processor->processPayment(100.0, "USD"); std::cout << "Payment successful: " << (processor->isPaymentSuccessful() ? "Yes" : "No") << std::endl; std::cout << "Transaction ID: " << processor->getTransactionId() << std::endl; delete processor; std::cout << "\nUsing LegacyGateway through adapter:" << std::endl; LegacyGateway* legacyGateway = new LegacyGateway(); PaymentProcessor* adapter = new LegacyGatewayAdapter(legacyGateway); adapter->processPayment(200.0, "EUR"); std::cout << "Payment successful: " << (adapter->isPaymentSuccessful() ? "Yes" : "No") << std::endl; std::cout << "Transaction ID: " << adapter->getTransactionId() << std::endl; delete adapter; delete legacyGateway; return 0; } ================================================ FILE: design-patterns/cpp/adapter/payment_processor.h ================================================ #pragma once #include class PaymentProcessor { public: virtual ~PaymentProcessor() = default; virtual void processPayment(double amount, const std::string& currency) = 0; virtual bool isPaymentSuccessful() = 0; virtual std::string getTransactionId() = 0; }; ================================================ FILE: design-patterns/cpp/bridge/circle.cpp ================================================ #include "circle.h" Circle::Circle(Renderer* renderer, float radius) : Shape(renderer), radius(radius) {} void Circle::draw() { renderer->renderCircle(radius); } ================================================ FILE: design-patterns/cpp/bridge/circle.h ================================================ #pragma once #include "shape.h" class Circle : public Shape { public: Circle(Renderer* renderer, float radius); void draw() override; private: float radius; }; ================================================ FILE: design-patterns/cpp/bridge/main.cpp ================================================ #include "vector_renderer.h" #include "raster_renderer.h" #include "circle.h" #include "rectangle.h" #include int main() { VectorRenderer vectorRenderer; RasterRenderer rasterRenderer; Circle vectorCircle(&vectorRenderer, 5.0f); Rectangle vectorRectangle(&vectorRenderer, 4.0f, 3.0f); Circle rasterCircle(&rasterRenderer, 7.0f); Rectangle rasterRectangle(&rasterRenderer, 6.0f, 2.0f); std::cout << "Vector Circle: "; vectorCircle.draw(); std::cout << "Vector Rectangle: "; vectorRectangle.draw(); std::cout << "Raster Circle: "; rasterCircle.draw(); std::cout << "Raster Rectangle: "; rasterRectangle.draw(); return 0; } ================================================ FILE: design-patterns/cpp/bridge/raster_renderer.cpp ================================================ #include "raster_renderer.h" #include void RasterRenderer::renderCircle(float radius) { std::cout << "Drawing circle as raster with radius: " << radius << std::endl; } void RasterRenderer::renderRectangle(float width, float height) { std::cout << "Drawing rectangle as raster with width: " << width << ", height: " << height << std::endl; } ================================================ FILE: design-patterns/cpp/bridge/raster_renderer.h ================================================ #pragma once #include "renderer.h" class RasterRenderer : public Renderer { public: void renderCircle(float radius) override; void renderRectangle(float width, float height) override; }; ================================================ FILE: design-patterns/cpp/bridge/rectangle.cpp ================================================ #include "rectangle.h" Rectangle::Rectangle(Renderer* renderer, float width, float height) : Shape(renderer), width(width), height(height) {} void Rectangle::draw() { renderer->renderRectangle(width, height); } ================================================ FILE: design-patterns/cpp/bridge/rectangle.h ================================================ #pragma once #include "shape.h" class Rectangle : public Shape { public: Rectangle(Renderer* renderer, float width, float height); void draw() override; private: float width; float height; }; ================================================ FILE: design-patterns/cpp/bridge/renderer.h ================================================ #pragma once class Renderer { public: virtual ~Renderer() = default; virtual void renderCircle(float radius) = 0; virtual void renderRectangle(float width, float height) = 0; }; ================================================ FILE: design-patterns/cpp/bridge/shape.cpp ================================================ #include "shape.h" Shape::Shape(Renderer* renderer) : renderer(renderer) {} ================================================ FILE: design-patterns/cpp/bridge/shape.h ================================================ #pragma once #include "renderer.h" class Shape { protected: Renderer* renderer; public: explicit Shape(Renderer* renderer); virtual ~Shape() = default; virtual void draw() = 0; }; ================================================ FILE: design-patterns/cpp/bridge/vector_renderer.cpp ================================================ ================================================ FILE: design-patterns/cpp/bridge/vector_renderer.h ================================================ #pragma once #include "renderer.h" class VectorRenderer : public Renderer { public: void renderCircle(float radius) override; void renderRectangle(float width, float height) override; }; ================================================ FILE: design-patterns/cpp/builder/http_request.cpp ================================================ ================================================ FILE: design-patterns/cpp/builder/http_request.h ================================================ #pragma once #include #include #include class HttpRequest { public: class Builder; std::string getUrl() const; std::string getMethod() const; const std::map& getHeaders() const; const std::map& getQueryParams() const; std::string getBody() const; int getTimeout() const; friend std::ostream& operator<<(std::ostream& os, const HttpRequest& req); private: std::string url; std::string method; std::map headers; std::map queryParams; std::string body; int timeout; HttpRequest(const Builder& builder); }; ================================================ FILE: design-patterns/cpp/builder/http_request_builder.cpp ================================================ #include "http_request_builder.h" #include #include HttpRequest::Builder::Builder(const std::string& url) : url(url) { if (url.empty()) { throw std::invalid_argument("URL cannot be empty."); } } HttpRequest::Builder& HttpRequest::Builder::method(const std::string& m) { method = m.empty() ? "GET" : m; std::transform(method.begin(), method.end(), method.begin(), ::toupper); return *this; } HttpRequest::Builder& HttpRequest::Builder::header(const std::string& key, const std::string& value) { if (!key.empty() && !value.empty()) headers[key] = value; return *this; } HttpRequest::Builder& HttpRequest::Builder::queryParam(const std::string& key, const std::string& value) { if (!key.empty() && !value.empty()) queryParams[key] = value; return *this; } HttpRequest::Builder& HttpRequest::Builder::body(const std::string& b) { body = b; return *this; } HttpRequest::Builder& HttpRequest::Builder::timeout(int timeoutMillis) { if (timeoutMillis > 0) timeout = timeoutMillis; return *this; } HttpRequest HttpRequest::Builder::build() { if ((method == "POST" || method == "PUT") && body.empty()) { std::cout << "Warning: Building " << method << " request without a body for URL: " << url << std::endl; } return HttpRequest(*this); } ================================================ FILE: design-patterns/cpp/builder/http_request_builder.h ================================================ ================================================ FILE: design-patterns/cpp/builder/main.cpp ================================================ #include "http_request.h" #include "http_request_builder.h" #include int main() { // Example 1: Simple GET request HttpRequest getRequest = HttpRequest::Builder("https://api.example.com/users") .method("GET") .header("Accept", "application/json") .timeout(5000) .build(); std::cout << "GET Request: " << getRequest << std::endl; // Example 2: POST request with body and custom headers HttpRequest postRequest = HttpRequest::Builder("https://api.example.com/posts") .method("POST") .header("Content-Type", "application/json") .header("X-Auth-Token", "some_secret_token") .body("{\"title\":\"New Post\",\"content\":\"Hello Builder!\"}") .queryParam("userId", "123") .build(); std::cout << "POST Request: " << postRequest << std::endl; // Example 3: Request with only required URL (defaults for others) HttpRequest defaultRequest = HttpRequest::Builder("https://api.example.com/status").build(); std::cout << "Default Request: " << defaultRequest << std::endl; // Example 4: Illustrating potential warning from builder HttpRequest putNoBodyRequest = HttpRequest::Builder("https://api.example.com/resource/1") .method("PUT") // .body("updated data") // Body intentionally omitted .build(); std::cout << "PUT Request (no body): " << putNoBodyRequest << std::endl; // Example of trying to build with invalid required parameter try { HttpRequest invalidRequest = HttpRequest::Builder("").build(); } catch (const std::invalid_argument& e) { std::cerr << "Error creating request: " << e.what() << std::endl; } } ================================================ FILE: design-patterns/cpp/chainofresponsibility/auth_handler.h ================================================ #pragma once #include "base_handler.h" #include class AuthHandler : public BaseHandler { public: void handle(Request& request) override { if (request.user.empty()) { std::cout << "AuthHandler: ❌ User not authenticated." << std::endl; return; } std::cout << "AuthHandler: ✅ Authenticated." << std::endl; forward(request); } }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/authorization_handler.h ================================================ #pragma once #include "base_handler.h" #include class AuthorizationHandler : public BaseHandler { public: void handle(Request& request) override { if (request.userRole != "ADMIN") { std::cout << "AuthorizationHandler: ❌ Access denied." << std::endl; return; } std::cout << "AuthorizationHandler: ✅ Authorized." << std::endl; forward(request); } }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/base_handler.cpp ================================================ #include "base_handler.h" void BaseHandler::setNext(RequestHandler* nextHandler) { next = nextHandler; } void BaseHandler::forward(Request& request) { if (next) { next->handle(request); } } ================================================ FILE: design-patterns/cpp/chainofresponsibility/base_handler.h ================================================ #pragma once #include "request_handler.h" class BaseHandler : public RequestHandler { protected: RequestHandler* next = nullptr; public: void setNext(RequestHandler* next) override; void forward(Request& request); }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/business_logic_handler.h ================================================ #pragma once #include "base_handler.h" #include class BusinessLogicHandler : public BaseHandler { public: void handle(Request& request) override { std::cout << "BusinessLogicHandler: 🚀 Processing request..." << std::endl; // Core application logic goes here } }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/main.cpp ================================================ #include "auth_handler.h" #include "authorization_handler.h" #include "rate_limit_handler.h" #include "validation_handler.h" #include "business_logic_handler.h" #include "request.h" #include int main() { // Create handlers AuthHandler auth; AuthorizationHandler authorization; RateLimitHandler rateLimit; ValidationHandler validation; BusinessLogicHandler businessLogic; // Build the chain auth.setNext(&authorization); authorization.setNext(&rateLimit); rateLimit.setNext(&validation); validation.setNext(&businessLogic); // Send a request through the chain Request request("john", "ADMIN", 10, "{ \"data\": \"valid\" }"); auth.handle(request); std::cout << "\n--- Trying an invalid request ---" << std::endl; Request badRequest("", "USER", 150, ""); auth.handle(badRequest); return 0; } ================================================ FILE: design-patterns/cpp/chainofresponsibility/rate_limit_handler.h ================================================ #pragma once #include "base_handler.h" #include class RateLimitHandler : public BaseHandler { public: void handle(Request& request) override { if (request.requestCount >= 100) { std::cout << "RateLimitHandler: ❌ Rate limit exceeded." << std::endl; return; } std::cout << "RateLimitHandler: ✅ Within rate limit." << std::endl; forward(request); } }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/request.cpp ================================================ #include "request.h" Request::Request(const std::string& user, const std::string& role, int requestCount, const std::string& payload) : user(user), userRole(role), requestCount(requestCount), payload(payload) {} ================================================ FILE: design-patterns/cpp/chainofresponsibility/request.h ================================================ #pragma once #include class Request { public: std::string user; std::string userRole; int requestCount; std::string payload; Request(const std::string& user, const std::string& role, int requestCount, const std::string& payload); }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/request_handler.h ================================================ #pragma once #include "request.h" class RequestHandler { public: virtual ~RequestHandler() = default; virtual void setNext(RequestHandler* next) = 0; virtual void handle(Request& request) = 0; }; ================================================ FILE: design-patterns/cpp/chainofresponsibility/validation_handler.h ================================================ #pragma once #include "base_handler.h" #include class ValidationHandler : public BaseHandler { public: void handle(Request& request) override { if (request.payload.empty() || request.payload.find_first_not_of(" \t\n\r") == std::string::npos) { std::cout << "ValidationHandler: ❌ Invalid payload." << std::endl; return; } std::cout << "ValidationHandler: ✅ Payload valid." << std::endl; forward(request); } }; ================================================ FILE: design-patterns/cpp/composite/file.cpp ================================================ #include "file.h" #include File::File(const std::string& name, int size) : name(name), size(size) {} int File::getSize() const { return size; } void File::printStructure(const std::string& indent) const { std::cout << indent << "- " << name << " (" << size << " KB)" << std::endl; } void File::delete() { std::cout << "Deleting file: " << name << std::endl; } ================================================ FILE: design-patterns/cpp/composite/file.h ================================================ #pragma once #include "file_system_item.h" #include class File : public FileSystemItem { public: File(const std::string& name, int size); int getSize() const override; void printStructure(const std::string& indent) const override; void delete() override; private: std::string name; int size; }; ================================================ FILE: design-patterns/cpp/composite/file_system_item.h ================================================ #pragma once #include class FileSystemItem { public: virtual ~FileSystemItem() = default; virtual int getSize() const = 0; virtual void printStructure(const std::string& indent) const = 0; virtual void delete() = 0; }; ================================================ FILE: design-patterns/cpp/composite/folder.cpp ================================================ ================================================ FILE: design-patterns/cpp/composite/folder.h ================================================ #pragma once #include "file_system_item.h" #include #include #include class Folder : public FileSystemItem { public: explicit Folder(const std::string& name); void addItem(std::shared_ptr item); int getSize() const override; void printStructure(const std::string& indent) const override; void delete() override; private: std::string name; std::vector> children; }; ================================================ FILE: design-patterns/cpp/composite/main.cpp ================================================ #include "file.h" #include "folder.h" #include #include int main() { auto file1 = std::make_shared("readme.txt", 5); auto file2 = std::make_shared("photo.jpg", 1500); auto file3 = std::make_shared("data.csv", 300); auto documents = std::make_shared("Documents"); documents->addItem(file1); documents->addItem(file3); auto pictures = std::make_shared("Pictures"); pictures->addItem(file2); auto home = std::make_shared("Home"); home->addItem(documents); home->addItem(pictures); std::cout << "---- File Structure ----" << std::endl; home->printStructure(""); std::cout << "\nTotal Size: " << home->getSize() << " KB" << std::endl; std::cout << "\n---- Deleting All ----" << std::endl; home->delete(); return 0; } ================================================ FILE: design-patterns/cpp/decorator/bold_decorator.cpp ================================================ #include "bold_decorator.h" #include BoldDecorator::BoldDecorator(TextView* inner) : TextDecorator(inner) {} void BoldDecorator::render() { std::cout << ""; inner->render(); std::cout << ""; } ================================================ FILE: design-patterns/cpp/decorator/bold_decorator.h ================================================ #pragma once #include "text_decorator.h" class BoldDecorator : public TextDecorator { public: explicit BoldDecorator(TextView* inner); void render() override; }; ================================================ FILE: design-patterns/cpp/decorator/italic_decorator.cpp ================================================ #include "italic_decorator.h" #include ItalicDecorator::ItalicDecorator(TextView* inner) : TextDecorator(inner) {} void ItalicDecorator::render() { std::cout << ""; inner->render(); std::cout << ""; } ================================================ FILE: design-patterns/cpp/decorator/italic_decorator.h ================================================ #pragma once #include "text_decorator.h" class ItalicDecorator : public TextDecorator { public: explicit ItalicDecorator(TextView* inner); void render() override; }; ================================================ FILE: design-patterns/cpp/decorator/main.cpp ================================================ #include "plain_text_view.h" #include "bold_decorator.h" #include "italic_decorator.h" #include "underline_decorator.h" #include int main() { TextView* plain = new PlainTextView("Hello, world!"); std::cout << "Plain: "; plain->render(); std::cout << std::endl; std::cout << "Bold: "; TextView* bold = new BoldDecorator(plain); bold->render(); std::cout << std::endl; std::cout << "Italic + Bold: "; TextView* italicBold = new ItalicDecorator(bold); italicBold->render(); std::cout << std::endl; std::cout << "Underline + Italic + Bold: "; TextView* fullStyle = new UnderlineDecorator(italicBold); fullStyle->render(); std::cout << std::endl; // Clean up delete fullStyle; delete italicBold; delete bold; delete plain; return 0; } ================================================ FILE: design-patterns/cpp/decorator/plain_text_view.cpp ================================================ #include "plain_text_view.h" #include PlainTextView::PlainTextView(const std::string& text) : text(text) {} void PlainTextView::render() { std::cout << text; } ================================================ FILE: design-patterns/cpp/decorator/plain_text_view.h ================================================ #pragma once #include "text_view.h" #include class PlainTextView : public TextView { public: explicit PlainTextView(const std::string& text); void render() override; private: std::string text; }; ================================================ FILE: design-patterns/cpp/decorator/text_decorator.cpp ================================================ #include "text_decorator.h" TextDecorator::TextDecorator(TextView* inner) : inner(inner) {} ================================================ FILE: design-patterns/cpp/decorator/text_decorator.h ================================================ #pragma once #include "text_view.h" class TextDecorator : public TextView { protected: TextView* inner; public: explicit TextDecorator(TextView* inner); }; ================================================ FILE: design-patterns/cpp/decorator/text_view.h ================================================ #pragma once class TextView { public: virtual ~TextView() = default; virtual void render() = 0; }; ================================================ FILE: design-patterns/cpp/decorator/underline_decorator.cpp ================================================ #include "underline_decorator.h" #include UnderlineDecorator::UnderlineDecorator(TextView* inner) : TextDecorator(inner) {} void UnderlineDecorator::render() { std::cout << ""; inner->render(); std::cout << ""; } ================================================ FILE: design-patterns/cpp/decorator/underline_decorator.h ================================================ #pragma once #include "text_decorator.h" class UnderlineDecorator : public TextDecorator { public: explicit UnderlineDecorator(TextView* inner); void render() override; }; ================================================ FILE: design-patterns/cpp/facade/build_system.cpp ================================================ #include "build_system.h" bool BuildSystem::compileProject() { std::cout << "BuildSystem: Compiling project..." << std::endl; simulateDelay(2000); std::cout << "BuildSystem: Build successful." << std::endl; return true; } std::string BuildSystem::getArtifactPath() { std::string path = "target/myapplication-1.0.jar"; std::cout << "BuildSystem: Artifact located at " << path << std::endl; return path; } void BuildSystem::simulateDelay(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } ================================================ FILE: design-patterns/cpp/facade/build_system.h ================================================ #pragma once #include #include #include #include class BuildSystem { public: bool compileProject(); std::string getArtifactPath(); private: void simulateDelay(int ms); }; ================================================ FILE: design-patterns/cpp/facade/deployment_facade.cpp ================================================ #include "deployment_facade.h" #include DeploymentFacade::DeploymentFacade() : vcs(std::make_unique()) , buildSystem(std::make_unique()) , testingFramework(std::make_unique()) , deploymentTarget(std::make_unique()) {} bool DeploymentFacade::deployApplication(const std::string& branch, const std::string& serverAddress) { std::cout << "\nFACADE: --- Initiating FULL DEPLOYMENT for branch: " << branch << " to " << serverAddress << " ---" << std::endl; bool success = true; try { // Step 1: Pull latest code vcs->pullLatestChanges(branch); // Step 2: Build the project if (!buildSystem->compileProject()) { std::cerr << "FACADE: DEPLOYMENT FAILED - Build compilation failed." << std::endl; return false; } std::string artifactPath = buildSystem->getArtifactPath(); // Step 3: Run tests if (!testingFramework->runUnitTests()) { std::cerr << "FACADE: DEPLOYMENT FAILED - Unit tests failed." << std::endl; return false; } if (!testingFramework->runIntegrationTests()) { std::cerr << "FACADE: DEPLOYMENT FAILED - Integration tests failed." << std::endl; return false; } // Step 4: Deploy to production deploymentTarget->transferArtifact(artifactPath, serverAddress); deploymentTarget->activateNewVersion(serverAddress); std::cout << "FACADE: APPLICATION DEPLOYED SUCCESSFULLY TO " << serverAddress << "!" << std::endl; } catch (const std::exception& e) { std::cerr << "FACADE: DEPLOYMENT FAILED - An unexpected error occurred: " << e.what() << std::endl; success = false; } return success; } bool DeploymentFacade::deployHotfix(const std::string& branch, const std::string& serverAddress) { std::cout << "\nFACADE: --- Initiating HOTFIX DEPLOYMENT for branch: " << branch << " to " << serverAddress << " ---" << std::endl; bool success = true; try { // Step 1: Pull latest code vcs->pullLatestChanges(branch); // Step 2: Build the project if (!buildSystem->compileProject()) { std::cerr << "FACADE: HOTFIX FAILED - Build compilation failed." << std::endl; return false; } std::string artifactPath = buildSystem->getArtifactPath(); // Step 3: For a hotfix, we skip extensive tests std::cout << "FACADE: Skipping full test suite for hotfix deployment (or running minimal smoke tests)." << std::endl; // Step 4: Deploy to production deploymentTarget->transferArtifact(artifactPath, serverAddress); deploymentTarget->activateNewVersion(serverAddress); std::cout << "FACADE: HOTFIX DEPLOYED SUCCESSFULLY TO " << serverAddress << "!" << std::endl; } catch (const std::exception& e) { std::cerr << "FACADE: HOTFIX FAILED - An unexpected error occurred: " << e.what() << std::endl; success = false; } return success; } ================================================ FILE: design-patterns/cpp/facade/deployment_facade.h ================================================ #pragma once #include "version_control_system.h" #include "build_system.h" #include "testing_framework.h" #include "deployment_target.h" #include #include class DeploymentFacade { public: DeploymentFacade(); bool deployApplication(const std::string& branch, const std::string& serverAddress); bool deployHotfix(const std::string& branch, const std::string& serverAddress); private: std::unique_ptr vcs; std::unique_ptr buildSystem; std::unique_ptr testingFramework; std::unique_ptr deploymentTarget; }; ================================================ FILE: design-patterns/cpp/facade/deployment_target.cpp ================================================ #include "deployment_target.h" void DeploymentTarget::transferArtifact(const std::string& artifactPath, const std::string& server) { std::cout << "Deployment: Transferring " << artifactPath << " to " << server << "..." << std::endl; simulateDelay(1000); std::cout << "Deployment: Transfer complete." << std::endl; } void DeploymentTarget::activateNewVersion(const std::string& server) { std::cout << "Deployment: Activating new version on " << server << "..." << std::endl; simulateDelay(500); std::cout << "Deployment: Now live on " << server << "!" << std::endl; } void DeploymentTarget::simulateDelay(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } ================================================ FILE: design-patterns/cpp/facade/deployment_target.h ================================================ #pragma once #include #include #include #include class DeploymentTarget { public: void transferArtifact(const std::string& artifactPath, const std::string& server); void activateNewVersion(const std::string& server); private: void simulateDelay(int ms); }; ================================================ FILE: design-patterns/cpp/facade/main.cpp ================================================ #include "deployment_facade.h" #include int main() { DeploymentFacade facade; // Example 1: Full deployment std::cout << "=== Full Deployment Example ===" << std::endl; facade.deployApplication("main", "production-server"); // Example 2: Hotfix deployment std::cout << "\n=== Hotfix Deployment Example ===" << std::endl; facade.deployHotfix("hotfix/security-patch", "production-server"); return 0; } ================================================ FILE: design-patterns/cpp/facade/testing_framework.cpp ================================================ #include "testing_framework.h" bool TestingFramework::runUnitTests() { std::cout << "Testing: Running unit tests..." << std::endl; simulateDelay(1500); std::cout << "Testing: Unit tests passed." << std::endl; return true; } bool TestingFramework::runIntegrationTests() { std::cout << "Testing: Running integration tests..." << std::endl; simulateDelay(3000); std::cout << "Testing: Integration tests passed." << std::endl; return true; } void TestingFramework::simulateDelay(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } ================================================ FILE: design-patterns/cpp/facade/testing_framework.h ================================================ #pragma once #include #include #include class TestingFramework { public: bool runUnitTests(); bool runIntegrationTests(); private: void simulateDelay(int ms); }; ================================================ FILE: design-patterns/cpp/facade/version_control_system.cpp ================================================ #include "version_control_system.h" void VersionControlSystem::pullLatestChanges(const std::string& branch) { std::cout << "VCS: Pulling latest changes from '" << branch << "'..." << std::endl; simulateDelay(); std::cout << "VCS: Pull complete." << std::endl; } void VersionControlSystem::simulateDelay() { std::this_thread::sleep_for(std::chrono::seconds(1)); } ================================================ FILE: design-patterns/cpp/facade/version_control_system.h ================================================ #pragma once #include #include #include #include class VersionControlSystem { public: void pullLatestChanges(const std::string& branch); private: void simulateDelay(); }; ================================================ FILE: design-patterns/cpp/factory/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(factory) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(factory main.cpp email_notification.cpp sms_notification.cpp push_notification.cpp notification_factory.cpp ) ================================================ FILE: design-patterns/cpp/factory/email_notification.cpp ================================================ ================================================ FILE: design-patterns/cpp/factory/email_notification.h ================================================ #pragma once #include "notification.h" class EmailNotification : public Notification { public: void send(const std::string& message) override; }; ================================================ FILE: design-patterns/cpp/factory/main.cpp ================================================ #include "notification_factory.h" #include int main() { try { // Create different types of notifications using the factory auto emailNotification = NotificationFactory::createNotification("EMAIL"); auto smsNotification = NotificationFactory::createNotification("SMS"); auto pushNotification = NotificationFactory::createNotification("PUSH"); // Send messages using the notifications emailNotification->send("Hello via Email!"); smsNotification->send("Hello via SMS!"); pushNotification->send("Hello via Push!"); // Try to create an invalid notification type auto invalidNotification = NotificationFactory::createNotification("INVALID"); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ================================================ FILE: design-patterns/cpp/factory/notification.h ================================================ #pragma once #include class Notification { public: virtual ~Notification() = default; virtual void send(const std::string& message) = 0; }; ================================================ FILE: design-patterns/cpp/factory/notification_factory.cpp ================================================ #include "notification_factory.h" #include "email_notification.h" #include "sms_notification.h" #include "push_notification.h" #include std::unique_ptr NotificationFactory::createNotification(const std::string& type) { if (type == "EMAIL") { return std::make_unique(); } else if (type == "SMS") { return std::make_unique(); } else if (type == "PUSH") { return std::make_unique(); } throw std::invalid_argument("Unknown notification type"); } ================================================ FILE: design-patterns/cpp/factory/notification_factory.h ================================================ #pragma once #include "notification.h" #include #include class NotificationFactory { public: static std::unique_ptr createNotification(const std::string& type); }; ================================================ FILE: design-patterns/cpp/factory/push_notification.cpp ================================================ #include "push_notification.h" #include void PushNotification::send(const std::string& message) { std::cout << "Sending push notification: " << message << std::endl; } ================================================ FILE: design-patterns/cpp/factory/push_notification.h ================================================ #pragma once #include "notification.h" class PushNotification : public Notification { public: void send(const std::string& message) override; }; ================================================ FILE: design-patterns/cpp/factory/sms_notification.cpp ================================================ #include "sms_notification.h" #include void SMSNotification::send(const std::string& message) { std::cout << "Sending SMS: " << message << std::endl; } ================================================ FILE: design-patterns/cpp/factory/sms_notification.h ================================================ #pragma once #include "notification.h" class SMSNotification : public Notification { public: void send(const std::string& message) override; }; ================================================ FILE: design-patterns/cpp/flyweight/circle.cpp ================================================ #include "circle.h" #include Circle::Circle(const std::string& color) : color(color) {} void Circle::draw() { std::cout << "Drawing Circle[ color: " << color << ", x: " << x << ", y: " << y << ", radius: " << radius << " ]" << std::endl; } ================================================ FILE: design-patterns/cpp/flyweight/circle.h ================================================ #pragma once #include "shape.h" #include class Circle : public Shape { public: Circle(const std::string& color); void draw() override; private: std::string color; int x = 0; int y = 0; int radius = 0; }; ================================================ FILE: design-patterns/cpp/flyweight/main.cpp ================================================ #include "shape_factory.h" #include int main() { std::cout << "Flyweight Pattern Demo\n" << std::endl; // Get circles of different colors Shape* redCircle = ShapeFactory::getCircle("Red"); redCircle->draw(); Shape* greenCircle = ShapeFactory::getCircle("Green"); greenCircle->draw(); Shape* blueCircle = ShapeFactory::getCircle("Blue"); blueCircle->draw(); // Try to get a red circle again Shape* redCircle2 = ShapeFactory::getCircle("Red"); redCircle2->draw(); std::cout << "\nTotal number of circle objects created: " << ShapeFactory::getCircleCount() << std::endl; return 0; } ================================================ FILE: design-patterns/cpp/flyweight/shape.h ================================================ #pragma once #include class Shape { public: virtual ~Shape() = default; virtual void draw() = 0; }; ================================================ FILE: design-patterns/cpp/flyweight/shape_factory.cpp ================================================ #include "shape_factory.h" #include "circle.h" std::unordered_map ShapeFactory::circleMap; Shape* ShapeFactory::getCircle(const std::string& color) { auto it = circleMap.find(color); if (it == circleMap.end()) { Circle* circle = new Circle(color); circleMap[color] = circle; std::cout << "Creating circle of color: " << color << std::endl; return circle; } return it->second; } int ShapeFactory::getCircleCount() { return circleMap.size(); } ================================================ FILE: design-patterns/cpp/flyweight/shape_factory.h ================================================ #pragma once #include "shape.h" #include #include #include class ShapeFactory { public: static Shape* getCircle(const std::string& color); static int getCircleCount(); private: static std::unordered_map circleMap; }; ================================================ FILE: design-patterns/cpp/iterator/container.h ================================================ #pragma once #include "iterator.h" class Container { public: virtual ~Container() = default; virtual Iterator* getIterator() = 0; }; ================================================ FILE: design-patterns/cpp/iterator/iterator.h ================================================ #pragma once #include class Iterator { public: virtual ~Iterator() = default; virtual bool hasNext() = 0; virtual std::string next() = 0; }; ================================================ FILE: design-patterns/cpp/iterator/main.cpp ================================================ #include "name_repository.h" #include int main() { NameRepository namesRepository; std::cout << "Names: "; for (Iterator* iter = namesRepository.getIterator(); iter->hasNext();) { std::string name = iter->next(); std::cout << name << " "; } std::cout << std::endl; return 0; } ================================================ FILE: design-patterns/cpp/iterator/name_iterator.cpp ================================================ #include "name_iterator.h" NameIterator::NameIterator(const std::vector& names) : names(names), index(0) {} bool NameIterator::hasNext() { return index < names.size(); } std::string NameIterator::next() { if (hasNext()) { return names[index++]; } return ""; } ================================================ FILE: design-patterns/cpp/iterator/name_iterator.h ================================================ #pragma once #include "iterator.h" #include #include class NameIterator : public Iterator { public: explicit NameIterator(const std::vector& names); bool hasNext() override; std::string next() override; private: std::vector names; size_t index; }; ================================================ FILE: design-patterns/cpp/iterator/name_repository.cpp ================================================ #include "name_repository.h" #include "name_iterator.h" NameRepository::NameRepository() { names = {"Robert", "John", "Julie", "Lora"}; } Iterator* NameRepository::getIterator() { return new NameIterator(names); } ================================================ FILE: design-patterns/cpp/iterator/name_repository.h ================================================ #pragma once #include "container.h" #include #include class NameRepository : public Container { public: NameRepository(); Iterator* getIterator() override; private: std::vector names; }; ================================================ FILE: design-patterns/cpp/mediator/button.cpp ================================================ #include "button.h" #include Button::Button(UIMediator* mediator) : UIComponent(mediator), enabled(false) {} void Button::click() { if (enabled) { std::cout << "Login Button clicked!" << std::endl; notifyMediator(); // Will trigger login attempt } else { std::cout << "Login Button is disabled." << std::endl; } } void Button::setEnabled(bool value) { enabled = value; std::cout << "Login Button is now " << (enabled ? "ENABLED" : "DISABLED") << std::endl; } ================================================ FILE: design-patterns/cpp/mediator/button.h ================================================ #pragma once #include "ui_component.h" class Button : public UIComponent { public: explicit Button(UIMediator* mediator); void click(); void setEnabled(bool value); private: bool enabled; }; ================================================ FILE: design-patterns/cpp/mediator/form_mediator.cpp ================================================ #include "form_mediator.h" #include void FormMediator::setUsernameField(TextField* field) { usernameField = field; } void FormMediator::setPasswordField(TextField* field) { passwordField = field; } void FormMediator::setLoginButton(Button* button) { loginButton = button; } void FormMediator::setStatusLabel(Label* label) { statusLabel = label; } void FormMediator::componentChanged(UIComponent* component) { if (component == usernameField || component == passwordField) { bool enableButton = !usernameField->getText().empty() && !passwordField->getText().empty(); loginButton->setEnabled(enableButton); } else if (component == loginButton) { const std::string& username = usernameField->getText(); const std::string& password = passwordField->getText(); if (username == "admin" && password == "1234") { statusLabel->setText("✅ Login successful!"); } else { statusLabel->setText("❌ Invalid credentials."); } } } ================================================ FILE: design-patterns/cpp/mediator/form_mediator.h ================================================ #pragma once #include "ui_mediator.h" #include "text_field.h" #include "button.h" #include "label.h" class FormMediator : public UIMediator { public: void setUsernameField(TextField* field); void setPasswordField(TextField* field); void setLoginButton(Button* button); void setStatusLabel(Label* label); void componentChanged(UIComponent* component) override; private: TextField* usernameField = nullptr; TextField* passwordField = nullptr; Button* loginButton = nullptr; Label* statusLabel = nullptr; }; ================================================ FILE: design-patterns/cpp/mediator/label.cpp ================================================ #include "label.h" #include Label::Label(UIMediator* mediator) : UIComponent(mediator) {} void Label::setText(const std::string& message) { text = message; std::cout << "Status: " << text << std::endl; } ================================================ FILE: design-patterns/cpp/mediator/label.h ================================================ #pragma once #include "ui_component.h" #include class Label : public UIComponent { public: explicit Label(UIMediator* mediator); void setText(const std::string& message); private: std::string text; }; ================================================ FILE: design-patterns/cpp/mediator/main.cpp ================================================ #include "form_mediator.h" #include "text_field.h" #include "button.h" #include "label.h" #include int main() { // Create the mediator FormMediator mediator; // Create UI components TextField usernameField(&mediator); TextField passwordField(&mediator); Button loginButton(&mediator); Label statusLabel(&mediator); // Register components with the mediator mediator.setUsernameField(&usernameField); mediator.setPasswordField(&passwordField); mediator.setLoginButton(&loginButton); mediator.setStatusLabel(&statusLabel); std::cout << "=== Login Form Demo ===\n" << std::endl; // Test with empty fields std::cout << "Test 1: Empty fields" << std::endl; loginButton.click(); // Test with username only std::cout << "\nTest 2: Username only" << std::endl; usernameField.setText("admin"); loginButton.click(); // Test with both fields std::cout << "\nTest 3: Both fields filled" << std::endl; passwordField.setText("1234"); loginButton.click(); // Test with wrong credentials std::cout << "\nTest 4: Wrong credentials" << std::endl; usernameField.setText("user"); passwordField.setText("pass"); loginButton.click(); return 0; } ================================================ FILE: design-patterns/cpp/mediator/text_field.cpp ================================================ #include "text_field.h" #include TextField::TextField(UIMediator* mediator) : UIComponent(mediator) {} void TextField::setText(const std::string& newText) { text = newText; std::cout << "TextField updated: " << newText << std::endl; notifyMediator(); } const std::string& TextField::getText() const { return text; } ================================================ FILE: design-patterns/cpp/mediator/text_field.h ================================================ #pragma once #include "ui_component.h" #include class TextField : public UIComponent { public: explicit TextField(UIMediator* mediator); void setText(const std::string& newText); const std::string& getText() const; private: std::string text; }; ================================================ FILE: design-patterns/cpp/mediator/ui_component.cpp ================================================ #include "ui_component.h" UIComponent::UIComponent(UIMediator* mediator) : mediator(mediator) {} void UIComponent::notifyMediator() { mediator->componentChanged(this); } ================================================ FILE: design-patterns/cpp/mediator/ui_component.h ================================================ #pragma once #include "ui_mediator.h" class UIComponent { public: explicit UIComponent(UIMediator* mediator); virtual ~UIComponent() = default; protected: void notifyMediator(); UIMediator* mediator; }; ================================================ FILE: design-patterns/cpp/mediator/ui_mediator.h ================================================ #pragma once // Forward declaration class UIComponent; class UIMediator { public: virtual ~UIMediator() = default; virtual void componentChanged(UIComponent* component) = 0; }; ================================================ FILE: design-patterns/cpp/memento/main.cpp ================================================ #include "text_editor.h" #include "text_editor_undo_manager.h" #include int main() { TextEditor editor; TextEditorUndoManager undoManager; std::cout << "=== Text Editor with Undo Demo ===\n" << std::endl; // Type some text and save state std::cout << "Typing and saving initial text:" << std::endl; editor.type("Hello, "); undoManager.save(editor); // Type more text and save state std::cout << "\nTyping and saving more text:" << std::endl; editor.type("World!"); undoManager.save(editor); // Type additional text std::cout << "\nTyping additional text:" << std::endl; editor.type(" How are you?"); // Show current content std::cout << "\nCurrent content: " << editor.getContent() << std::endl; // Undo last change std::cout << "\nUndoing last change:" << std::endl; undoManager.undo(editor); // Show content after undo std::cout << "\nContent after undo: " << editor.getContent() << std::endl; // Undo again std::cout << "\nUndoing again:" << std::endl; undoManager.undo(editor); // Show content after second undo std::cout << "\nContent after second undo: " << editor.getContent() << std::endl; // Try to undo when nothing is left std::cout << "\nTrying to undo when nothing is left:" << std::endl; undoManager.undo(editor); return 0; } ================================================ FILE: design-patterns/cpp/memento/text_editor.cpp ================================================ #include "text_editor.h" #include void TextEditor::type(const std::string& newText) { content += newText; std::cout << "Typed: " << newText << std::endl; } std::string TextEditor::getContent() const { return content; } TextEditorMemento TextEditor::save() const { std::cout << "Saving state: \"" << content << "\"" << std::endl; return TextEditorMemento(content); } void TextEditor::restore(const TextEditorMemento& memento) { content = memento.getState(); std::cout << "Restored state to: \"" << content << "\"" << std::endl; } ================================================ FILE: design-patterns/cpp/memento/text_editor.h ================================================ #pragma once #include "text_editor_memento.h" #include class TextEditor { public: void type(const std::string& newText); std::string getContent() const; TextEditorMemento save() const; void restore(const TextEditorMemento& memento); private: std::string content; }; ================================================ FILE: design-patterns/cpp/memento/text_editor_memento.cpp ================================================ #include "text_editor_memento.h" TextEditorMemento::TextEditorMemento(const std::string& state) : state(state) {} std::string TextEditorMemento::getState() const { return state; } ================================================ FILE: design-patterns/cpp/memento/text_editor_memento.h ================================================ #pragma once #include class TextEditorMemento { public: explicit TextEditorMemento(const std::string& state); std::string getState() const; private: const std::string state; }; ================================================ FILE: design-patterns/cpp/memento/text_editor_undo_manager.cpp ================================================ #include "text_editor_undo_manager.h" #include void TextEditorUndoManager::save(TextEditor& editor) { history.push(editor.save()); } void TextEditorUndoManager::undo(TextEditor& editor) { if (!history.empty()) { editor.restore(history.top()); history.pop(); } else { std::cout << "Nothing to undo." << std::endl; } } ================================================ FILE: design-patterns/cpp/memento/text_editor_undo_manager.h ================================================ #pragma once #include "text_editor.h" #include class TextEditorUndoManager { public: void save(TextEditor& editor); void undo(TextEditor& editor); private: std::stack history; }; ================================================ FILE: design-patterns/cpp/observer/fitness_data.cpp ================================================ #include "fitness_data.h" #include FitnessData::FitnessData() : steps(0), activeMinutes(0), calories(0) {} void FitnessData::registerObserver(FitnessDataObserver* observer) { observers.push_back(observer); } void FitnessData::removeObserver(FitnessDataObserver* observer) { auto it = std::find(observers.begin(), observers.end(), observer); if (it != observers.end()) { observers.erase(it); } } void FitnessData::notifyObservers() { for (auto observer : observers) { observer->update(*this); } } void FitnessData::newFitnessDataPushed(int steps, int activeMinutes, int calories) { this->steps = steps; this->activeMinutes = activeMinutes; this->calories = calories; std::cout << "\nFitnessData: New data received — Steps: " << steps << ", Active Minutes: " << activeMinutes << ", Calories: " << calories << std::endl; notifyObservers(); } void FitnessData::dailyReset() { steps = 0; activeMinutes = 0; calories = 0; std::cout << "\nFitnessData: Daily reset performed." << std::endl; notifyObservers(); } ================================================ FILE: design-patterns/cpp/observer/fitness_data.h ================================================ #pragma once #include "fitness_data_subject.h" #include #include class FitnessData : public FitnessDataSubject { public: FitnessData(); // Subject interface implementation void registerObserver(FitnessDataObserver* observer) override; void removeObserver(FitnessDataObserver* observer) override; void notifyObservers() override; // Fitness data methods void newFitnessDataPushed(int steps, int activeMinutes, int calories); void dailyReset(); // Getters int getSteps() const { return steps; } int getActiveMinutes() const { return activeMinutes; } int getCalories() const { return calories; } private: int steps; int activeMinutes; int calories; std::vector observers; }; ================================================ FILE: design-patterns/cpp/observer/fitness_data_observer.h ================================================ #pragma once // Forward declaration class FitnessData; class FitnessDataObserver { public: virtual ~FitnessDataObserver() = default; virtual void update(const FitnessData& data) = 0; }; ================================================ FILE: design-patterns/cpp/observer/fitness_data_subject.h ================================================ #pragma once #include "fitness_data_observer.h" class FitnessDataSubject { public: virtual ~FitnessDataSubject() = default; virtual void registerObserver(FitnessDataObserver* observer) = 0; virtual void removeObserver(FitnessDataObserver* observer) = 0; virtual void notifyObservers() = 0; }; ================================================ FILE: design-patterns/cpp/observer/goal_notifier.cpp ================================================ #include "goal_notifier.h" #include "fitness_data.h" #include void GoalNotifier::update(const FitnessData& data) { if (data.getSteps() >= 10000) { std::cout << "GoalNotifier: Congratulations! You've reached your daily step goal!" << std::endl; } if (data.getActiveMinutes() >= 30) { std::cout << "GoalNotifier: Great job! You've met your active minutes goal!" << std::endl; } if (data.getCalories() >= 2000) { std::cout << "GoalNotifier: Amazing! You've burned your target calories!" << std::endl; } } ================================================ FILE: design-patterns/cpp/observer/goal_notifier.h ================================================ #pragma once #include "fitness_data_observer.h" class GoalNotifier : public FitnessDataObserver { public: void update(const FitnessData& data) override; }; ================================================ FILE: design-patterns/cpp/observer/live_activity_display.cpp ================================================ #include "live_activity_display.h" #include "fitness_data.h" #include void LiveActivityDisplay::update(const FitnessData& data) { std::cout << "LiveActivityDisplay: Current Activity — Steps: " << data.getSteps() << ", Active Minutes: " << data.getActiveMinutes() << ", Calories: " << data.getCalories() << std::endl; } ================================================ FILE: design-patterns/cpp/observer/live_activity_display.h ================================================ #pragma once #include "fitness_data_observer.h" class LiveActivityDisplay : public FitnessDataObserver { public: void update(const FitnessData& data) override; }; ================================================ FILE: design-patterns/cpp/observer/main.cpp ================================================ #include "fitness_data.h" #include "live_activity_display.h" #include "progress_logger.h" #include "goal_notifier.h" #include int main() { // Create the subject FitnessData fitnessData; // Create observers LiveActivityDisplay liveDisplay; ProgressLogger logger; GoalNotifier notifier; // Register observers fitnessData.registerObserver(&liveDisplay); fitnessData.registerObserver(&logger); fitnessData.registerObserver(¬ifier); // Simulate fitness data updates std::cout << "=== Fitness App Observer Demo ===\n" << std::endl; // First update std::cout << "Update 1:" << std::endl; fitnessData.newFitnessDataPushed(5000, 15, 1000); // Second update std::cout << "\nUpdate 2:" << std::endl; fitnessData.newFitnessDataPushed(12000, 45, 2500); // Daily reset std::cout << "\nDaily Reset:" << std::endl; fitnessData.dailyReset(); return 0; } ================================================ FILE: design-patterns/cpp/observer/progress_logger.cpp ================================================ ================================================ FILE: design-patterns/cpp/observer/progress_logger.h ================================================ #pragma once #include "fitness_data_observer.h" class ProgressLogger : public FitnessDataObserver { public: void update(const FitnessData& data) override; }; ================================================ FILE: design-patterns/cpp/prototype/enemy.cpp ================================================ #include "enemy.h" #include Enemy::Enemy(const std::string& type, int health, double speed, bool armored, const std::string& weapon) : type(type), health(health), speed(speed), armored(armored), weapon(weapon) {} Enemy* Enemy::clone() const { return new Enemy(type, health, speed, armored, weapon); } void Enemy::setHealth(int health) { this->health = health; } void Enemy::printStats() const { std::cout << type << " [Health: " << health << ", Speed: " << speed << ", Armored: " << (armored ? "true" : "false") << ", Weapon: " << weapon << "]" << std::endl; } ================================================ FILE: design-patterns/cpp/prototype/enemy.h ================================================ #pragma once #include "enemy_prototype.h" #include class Enemy : public EnemyPrototype { public: Enemy(const std::string& type, int health, double speed, bool armored, const std::string& weapon); // Clone method implementation Enemy* clone() const override; // Setter for health void setHealth(int health); // Print enemy stats void printStats() const; private: std::string type; int health; double speed; bool armored; std::string weapon; }; ================================================ FILE: design-patterns/cpp/prototype/enemy_prototype.h ================================================ #pragma once class EnemyPrototype { public: virtual ~EnemyPrototype() = default; virtual EnemyPrototype* clone() const = 0; }; ================================================ FILE: design-patterns/cpp/prototype/enemy_registry.cpp ================================================ ================================================ FILE: design-patterns/cpp/prototype/enemy_registry.h ================================================ #pragma once #include "enemy.h" #include #include #include #include class EnemyRegistry { public: void registerPrototype(const std::string& key, std::unique_ptr prototype); std::unique_ptr get(const std::string& key) const; private: std::unordered_map> prototypes; }; ================================================ FILE: design-patterns/cpp/prototype/main.cpp ================================================ ================================================ FILE: design-patterns/cpp/proxy/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(proxy_pattern) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Add executable for version 1 add_executable(image_gallery_v1 image_gallery_app_v1.cpp high_resolution_image.cpp ) # Add executable for version 2 add_executable(image_gallery_v2 image_gallery_app_v2.cpp high_resolution_image.cpp image_proxy.cpp ) ================================================ FILE: design-patterns/cpp/proxy/high_resolution_image.cpp ================================================ #include "high_resolution_image.h" #include HighResolutionImage::HighResolutionImage(const std::string& fileName) : fileName(fileName) { loadImageFromDisk(); } void HighResolutionImage::loadImageFromDisk() { std::cout << "Loading image: " << fileName << " from disk (Expensive Operation)..." << std::endl; // Simulate disk read and memory allocation std::this_thread::sleep_for(std::chrono::seconds(2)); // Simulate delay imageData.resize(10 * 1024 * 1024); // 10MB std::cout << "Image " << fileName << " loaded successfully." << std::endl; } void HighResolutionImage::display() { std::cout << "Displaying image: " << fileName << std::endl; // Actual rendering logic would go here } std::string HighResolutionImage::getFileName() const { return fileName; } ================================================ FILE: design-patterns/cpp/proxy/high_resolution_image.h ================================================ ================================================ FILE: design-patterns/cpp/proxy/image.h ================================================ #pragma once #include class Image { public: virtual ~Image() = default; virtual void display() = 0; virtual std::string getFileName() const = 0; }; ================================================ FILE: design-patterns/cpp/proxy/image_gallery_app_v1.cpp ================================================ #include "high_resolution_image.h" #include int main() { // Create high-resolution images directly std::cout << "Creating high-resolution images..." << std::endl; HighResolutionImage image1("nature.jpg"); HighResolutionImage image2("city.jpg"); HighResolutionImage image3("people.jpg"); // Display images std::cout << "\nDisplaying images..." << std::endl; image1.display(); image2.display(); image3.display(); // Note: All images are loaded at creation time, even if not displayed std::cout << "\nNote: All images were loaded at creation time, even if not displayed" << std::endl; return 0; } ================================================ FILE: design-patterns/cpp/proxy/image_gallery_app_v2.cpp ================================================ #include "image_proxy.h" #include int main() { // Create image proxies std::cout << "Creating image proxies..." << std::endl; ImageProxy image1("nature.jpg"); ImageProxy image2("city.jpg"); ImageProxy image3("people.jpg"); // Note: Images are not loaded yet std::cout << "\nNote: Images are not loaded yet, only proxies are created" << std::endl; // Display images (this will trigger loading) std::cout << "\nDisplaying images..." << std::endl; image1.display(); // This will load the image image2.display(); // This will load the image image3.display(); // This will load the image // Display again (should use cached images) std::cout << "\nDisplaying images again..." << std::endl; image1.display(); // Should use cached image image2.display(); // Should use cached image image3.display(); // Should use cached image return 0; } ================================================ FILE: design-patterns/cpp/proxy/image_proxy.cpp ================================================ #include "image_proxy.h" #include "high_resolution_image.h" #include ImageProxy::ImageProxy(const std::string& fileName) : fileName(fileName) { std::cout << "ImageProxy: Created for " << fileName << ". Real image not loaded yet." << std::endl; } void ImageProxy::display() { // Lazy initialization: Load only when display() is called if (!realImage) { std::cout << "ImageProxy: display() requested for " << fileName << ". Loading high-resolution image..." << std::endl; realImage = std::make_unique(fileName); } else { std::cout << "ImageProxy: Using cached high-resolution image for " << fileName << std::endl; } // Delegate the display call to the real image realImage->display(); } std::string ImageProxy::getFileName() const { // Can safely return without loading the image return fileName; } ================================================ FILE: design-patterns/cpp/proxy/image_proxy.h ================================================ #pragma once #include "image.h" #include class HighResolutionImage; class ImageProxy : public Image { public: explicit ImageProxy(const std::string& fileName); void display() override; std::string getFileName() const override; private: std::string fileName; std::unique_ptr realImage; }; ================================================ FILE: design-patterns/cpp/singleton/double_checked_singleton.cpp ================================================ #include "double_checked_singleton.h" // Initialize the static instance pointer and mutex std::atomic DoubleCheckedSingleton::instance = nullptr; std::mutex DoubleCheckedSingleton::mutex; DoubleCheckedSingleton& DoubleCheckedSingleton::getInstance() { // First check (not synchronized) DoubleCheckedSingleton* p = instance.load(std::memory_order_acquire); if (!p) { // Lock the mutex std::lock_guard lock(mutex); // Second check (synchronized) p = instance.load(std::memory_order_relaxed); if (!p) { // Create the instance p = new DoubleCheckedSingleton(); instance.store(p, std::memory_order_release); } } return *p; } ================================================ FILE: design-patterns/cpp/singleton/double_checked_singleton.h ================================================ #pragma once #include #include #include class DoubleCheckedSingleton { public: // Delete copy constructor and assignment operator DoubleCheckedSingleton(const DoubleCheckedSingleton&) = delete; DoubleCheckedSingleton& operator=(const DoubleCheckedSingleton&) = delete; // Public method to get the instance static DoubleCheckedSingleton& getInstance(); private: // Private constructor to prevent instantiation DoubleCheckedSingleton() = default; // The single instance, initially null static std::atomic instance; // Mutex for thread safety static std::mutex mutex; }; ================================================ FILE: design-patterns/cpp/singleton/eager_singleton.cpp ================================================ #include "eager_singleton.h" // Define the static instance EagerSingleton EagerSingleton::instance; EagerSingleton& EagerSingleton::getInstance() { return instance; } ================================================ FILE: design-patterns/cpp/singleton/eager_singleton.h ================================================ #pragma once class EagerSingleton { public: // Delete copy constructor and assignment operator EagerSingleton(const EagerSingleton&) = delete; EagerSingleton& operator=(const EagerSingleton&) = delete; // Public method to get the instance static EagerSingleton& getInstance(); private: // Private constructor to prevent instantiation EagerSingleton() = default; // The single instance, created immediately static EagerSingleton instance; }; ================================================ FILE: design-patterns/cpp/singleton/lazy_singleton.cpp ================================================ #include "lazy_singleton.h" // Initialize the static instance pointer std::unique_ptr LazySingleton::instance = nullptr; LazySingleton& LazySingleton::getInstance() { // Check if instance is null if (!instance) { // If null, create a new instance instance = std::unique_ptr(new LazySingleton()); } // Return the instance (either newly created or existing) return *instance; } ================================================ FILE: design-patterns/cpp/singleton/lazy_singleton.h ================================================ #pragma once #include class LazySingleton { public: // Delete copy constructor and assignment operator LazySingleton(const LazySingleton&) = delete; LazySingleton& operator=(const LazySingleton&) = delete; // Public method to get the instance static LazySingleton& getInstance(); private: // Private constructor to prevent instantiation LazySingleton() = default; // The single instance, initially null static std::unique_ptr instance; }; ================================================ FILE: design-patterns/cpp/singleton/main.cpp ================================================ #include "eager_singleton.h" #include "lazy_singleton.h" #include "thread_safe_singleton.h" #include "double_checked_singleton.h" #include int main() { std::cout << "=== Singleton Pattern Demo ===\n" << std::endl; // Test EagerSingleton std::cout << "Testing EagerSingleton:" << std::endl; EagerSingleton& eager1 = EagerSingleton::getInstance(); EagerSingleton& eager2 = EagerSingleton::getInstance(); std::cout << "EagerSingleton instances are the same: " << (&eager1 == &eager2) << std::endl; // Test LazySingleton std::cout << "\nTesting LazySingleton:" << std::endl; LazySingleton& lazy1 = LazySingleton::getInstance(); LazySingleton& lazy2 = LazySingleton::getInstance(); std::cout << "LazySingleton instances are the same: " << (&lazy1 == &lazy2) << std::endl; // Test ThreadSafeSingleton std::cout << "\nTesting ThreadSafeSingleton:" << std::endl; ThreadSafeSingleton& threadSafe1 = ThreadSafeSingleton::getInstance(); ThreadSafeSingleton& threadSafe2 = ThreadSafeSingleton::getInstance(); std::cout << "ThreadSafeSingleton instances are the same: " << (&threadSafe1 == &threadSafe2) << std::endl; // Test DoubleCheckedSingleton std::cout << "\nTesting DoubleCheckedSingleton:" << std::endl; DoubleCheckedSingleton& doubleChecked1 = DoubleCheckedSingleton::getInstance(); DoubleCheckedSingleton& doubleChecked2 = DoubleCheckedSingleton::getInstance(); std::cout << "DoubleCheckedSingleton instances are the same: " << (&doubleChecked1 == &doubleChecked2) << std::endl; return 0; } ================================================ FILE: design-patterns/cpp/singleton/thread_safe_singleton.cpp ================================================ #include "thread_safe_singleton.h" // Initialize the static instance pointer and mutex std::unique_ptr ThreadSafeSingleton::instance = nullptr; std::mutex ThreadSafeSingleton::mutex; ThreadSafeSingleton& ThreadSafeSingleton::getInstance() { // Lock the mutex for thread safety std::lock_guard lock(mutex); // Check if instance is null if (!instance) { // If null, create a new instance instance = std::unique_ptr(new ThreadSafeSingleton()); } // Return the instance (either newly created or existing) return *instance; } ================================================ FILE: design-patterns/cpp/singleton/thread_safe_singleton.h ================================================ #pragma once #include #include class ThreadSafeSingleton { public: // Delete copy constructor and assignment operator ThreadSafeSingleton(const ThreadSafeSingleton&) = delete; ThreadSafeSingleton& operator=(const ThreadSafeSingleton&) = delete; // Public method to get the instance static ThreadSafeSingleton& getInstance(); private: // Private constructor to prevent instantiation ThreadSafeSingleton() = default; // The single instance, initially null static std::unique_ptr instance; // Mutex for thread safety static std::mutex mutex; }; ================================================ FILE: design-patterns/cpp/state/dispensing_state.cpp ================================================ #include "dispensing_state.h" #include "vending_machine.h" #include "idle_state.h" #include void DispensingState::selectItem(VendingMachine& context, const std::string& itemCode) { std::cout << "Please wait, item is being dispensed." << std::endl; } void DispensingState::insertCoin(VendingMachine& context, double amount) { std::cout << "Please wait, item is being dispensed." << std::endl; } void DispensingState::dispenseItem(VendingMachine& context) { std::cout << "Item dispensed. Thank you for your purchase!" << std::endl; context.reset(); context.setState(std::make_unique()); } ================================================ FILE: design-patterns/cpp/state/dispensing_state.h ================================================ #pragma once #include "machine_state.h" class DispensingState : public MachineState { public: void selectItem(VendingMachine& context, const std::string& itemCode) override; void insertCoin(VendingMachine& context, double amount) override; void dispenseItem(VendingMachine& context) override; }; ================================================ FILE: design-patterns/cpp/state/has_money_state.cpp ================================================ #include "has_money_state.h" #include "vending_machine.h" #include "dispensing_state.h" #include void HasMoneyState::selectItem(VendingMachine& context, const std::string& itemCode) { std::cout << "Item already selected. Please dispense current item or cancel." << std::endl; } void HasMoneyState::insertCoin(VendingMachine& context, double amount) { std::cout << "Additional money inserted: $" << amount << std::endl; context.setInsertedAmount(context.getInsertedAmount() + amount); } void HasMoneyState::dispenseItem(VendingMachine& context) { std::cout << "Dispensing item: " << context.getSelectedItem() << std::endl; context.setState(std::make_unique()); } ================================================ FILE: design-patterns/cpp/state/has_money_state.h ================================================ #pragma once #include "machine_state.h" class HasMoneyState : public MachineState { public: void selectItem(VendingMachine& context, const std::string& itemCode) override; void insertCoin(VendingMachine& context, double amount) override; void dispenseItem(VendingMachine& context) override; }; ================================================ FILE: design-patterns/cpp/state/idle_state.cpp ================================================ #include "idle_state.h" #include "vending_machine.h" #include "item_selected_state.h" #include void IdleState::selectItem(VendingMachine& context, const std::string& itemCode) { std::cout << "Item selected: " << itemCode << std::endl; context.setSelectedItem(itemCode); context.setState(std::make_unique()); } void IdleState::insertCoin(VendingMachine& context, double amount) { std::cout << "Please select an item first." << std::endl; } void IdleState::dispenseItem(VendingMachine& context) { std::cout << "Please select an item first." << std::endl; } ================================================ FILE: design-patterns/cpp/state/idle_state.h ================================================ #pragma once #include "machine_state.h" class IdleState : public MachineState { public: void selectItem(VendingMachine& context, const std::string& itemCode) override; void insertCoin(VendingMachine& context, double amount) override; void dispenseItem(VendingMachine& context) override; }; ================================================ FILE: design-patterns/cpp/state/item_selected_state.cpp ================================================ #include "item_selected_state.h" #include "vending_machine.h" #include "has_money_state.h" #include void ItemSelectedState::selectItem(VendingMachine& context, const std::string& itemCode) { std::cout << "Item already selected. Please insert money or cancel." << std::endl; } void ItemSelectedState::insertCoin(VendingMachine& context, double amount) { std::cout << "Money inserted: $" << amount << std::endl; context.setInsertedAmount(amount); context.setState(std::make_unique()); } void ItemSelectedState::dispenseItem(VendingMachine& context) { std::cout << "Please insert money first." << std::endl; } ================================================ FILE: design-patterns/cpp/state/item_selected_state.h ================================================ #pragma once #include "machine_state.h" class ItemSelectedState : public MachineState { public: void selectItem(VendingMachine& context, const std::string& itemCode) override; void insertCoin(VendingMachine& context, double amount) override; void dispenseItem(VendingMachine& context) override; }; ================================================ FILE: design-patterns/cpp/state/machine_state.h ================================================ #pragma once #include class VendingMachine; // Forward declaration class MachineState { public: virtual ~MachineState() = default; virtual void selectItem(VendingMachine& context, const std::string& itemCode) = 0; virtual void insertCoin(VendingMachine& context, double amount) = 0; virtual void dispenseItem(VendingMachine& context) = 0; }; ================================================ FILE: design-patterns/cpp/state/main.cpp ================================================ #include "vending_machine.h" #include int main() { VendingMachine machine; // Test the vending machine workflow std::cout << "=== Vending Machine Demo ===\n" << std::endl; // Try to insert coin before selecting item std::cout << "Attempting to insert coin before selecting item:" << std::endl; machine.insertCoin(1.0); // Select an item std::cout << "\nSelecting item A1:" << std::endl; machine.selectItem("A1"); // Insert coin std::cout << "\nInserting coin:" << std::endl; machine.insertCoin(1.0); // Try to select another item std::cout << "\nAttempting to select another item:" << std::endl; machine.selectItem("B2"); // Insert more money std::cout << "\nInserting more money:" << std::endl; machine.insertCoin(0.5); // Dispense item std::cout << "\nDispensing item:" << std::endl; machine.dispenseItem(); // Try to interact after dispensing std::cout << "\nAttempting to interact after dispensing:" << std::endl; machine.selectItem("C3"); machine.insertCoin(1.0); machine.dispenseItem(); return 0; } ================================================ FILE: design-patterns/cpp/state/vending_machine.cpp ================================================ #include "vending_machine.h" #include "idle_state.h" VendingMachine::VendingMachine() : currentState(std::make_unique()) , selectedItem("") , insertedAmount(0.0) {} void VendingMachine::setState(std::unique_ptr newState) { currentState = std::move(newState); } void VendingMachine::setSelectedItem(const std::string& itemCode) { selectedItem = itemCode; } void VendingMachine::setInsertedAmount(double amount) { insertedAmount = amount; } const std::string& VendingMachine::getSelectedItem() const { return selectedItem; } double VendingMachine::getInsertedAmount() const { return insertedAmount; } void VendingMachine::selectItem(const std::string& itemCode) { currentState->selectItem(*this, itemCode); } void VendingMachine::insertCoin(double amount) { currentState->insertCoin(*this, amount); } void VendingMachine::dispenseItem() { currentState->dispenseItem(*this); } void VendingMachine::reset() { selectedItem = ""; insertedAmount = 0.0; currentState = std::make_unique(); } ================================================ FILE: design-patterns/cpp/state/vending_machine.h ================================================ #pragma once #include "machine_state.h" #include #include class VendingMachine { public: VendingMachine(); void setState(std::unique_ptr newState); void setSelectedItem(const std::string& itemCode); void setInsertedAmount(double amount); const std::string& getSelectedItem() const; double getInsertedAmount() const; void selectItem(const std::string& itemCode); void insertCoin(double amount); void dispenseItem(); void reset(); private: std::unique_ptr currentState; std::string selectedItem; double insertedAmount; }; ================================================ FILE: design-patterns/cpp/strategy/distance_based_shipping.cpp ================================================ #include "distance_based_shipping.h" #include #include double DistanceBasedShipping::calculateCost(const Order& order) { std::cout << "Calculating distance-based shipping cost..." << std::endl; // Zone-based rates std::map zoneRates = { {"ZoneA", 5.0}, {"ZoneB", 10.0}, {"ZoneC", 15.0} }; auto it = zoneRates.find(order.getDestinationZone()); if (it != zoneRates.end()) { return it->second; } return 20.0; // Default rate for unknown zones } ================================================ FILE: design-patterns/cpp/strategy/distance_based_shipping.h ================================================ #pragma once #include "shipping_strategy.h" class DistanceBasedShipping : public ShippingStrategy { public: double calculateCost(const Order& order) override; }; ================================================ FILE: design-patterns/cpp/strategy/ecommerce_app.cpp ================================================ ================================================ FILE: design-patterns/cpp/strategy/flat_rate_shipping.cpp ================================================ #include "flat_rate_shipping.h" #include double FlatRateShipping::calculateCost(const Order& order) { std::cout << "Calculating flat rate shipping cost..." << std::endl; return 10.0; // Fixed rate of $10 } ================================================ FILE: design-patterns/cpp/strategy/flat_rate_shipping.h ================================================ #pragma once #include "shipping_strategy.h" class FlatRateShipping : public ShippingStrategy { public: double calculateCost(const Order& order) override; }; ================================================ FILE: design-patterns/cpp/strategy/order.h ================================================ #pragma once #include class Order { public: double getTotalWeight() const { return 5.0; } // kg std::string getDestinationZone() const { return "ZoneA"; } double getOrderValue() const { return 150.0; } // ... other order details }; ================================================ FILE: design-patterns/cpp/strategy/shipping_cost_service.cpp ================================================ #include "shipping_cost_service.h" ShippingCostService::ShippingCostService(std::unique_ptr strategy) : strategy(std::move(strategy)) {} void ShippingCostService::setStrategy(std::unique_ptr newStrategy) { strategy = std::move(newStrategy); } double ShippingCostService::calculateShippingCost(const Order& order) { return strategy->calculateCost(order); } ================================================ FILE: design-patterns/cpp/strategy/shipping_cost_service.h ================================================ #pragma once #include "shipping_strategy.h" #include class ShippingCostService { public: explicit ShippingCostService(std::unique_ptr strategy); void setStrategy(std::unique_ptr strategy); double calculateShippingCost(const Order& order); private: std::unique_ptr strategy; }; ================================================ FILE: design-patterns/cpp/strategy/shipping_strategy.h ================================================ #pragma once #include "order.h" class ShippingStrategy { public: virtual ~ShippingStrategy() = default; virtual double calculateCost(const Order& order) = 0; }; ================================================ FILE: design-patterns/cpp/strategy/third_party_api_shipping.cpp ================================================ #include "third_party_api_shipping.h" #include double ThirdPartyApiShipping::calculateCost(const Order& order) { std::cout << "Calculating shipping cost using third-party API..." << std::endl; // Simulate API call return order.getOrderValue() * 0.1; // 10% of order value } ================================================ FILE: design-patterns/cpp/strategy/third_party_api_shipping.h ================================================ #pragma once #include "shipping_strategy.h" class ThirdPartyApiShipping : public ShippingStrategy { public: double calculateCost(const Order& order) override; }; ================================================ FILE: design-patterns/cpp/strategy/weight_based_shipping.cpp ================================================ #include "weight_based_shipping.h" #include double WeightBasedShipping::calculateCost(const Order& order) { std::cout << "Calculating weight-based shipping cost..." << std::endl; return order.getTotalWeight() * 2.0; // $2 per kg } ================================================ FILE: design-patterns/cpp/strategy/weight_based_shipping.h ================================================ #pragma once #include "shipping_strategy.h" class WeightBasedShipping : public ShippingStrategy { public: double calculateCost(const Order& order) override; }; ================================================ FILE: design-patterns/cpp/templatemethod/CMakeLists.txt ================================================ ================================================ FILE: design-patterns/cpp/templatemethod/abstract_report_exporter.cpp ================================================ #include "abstract_report_exporter.h" #include void AbstractReportExporter::exportReport(const ReportData& data, const std::string& filePath) { prepareData(data); openFile(filePath); writeHeader(data); writeDataRows(data); writeFooter(data); closeFile(filePath); std::cout << "Report exported to " << filePath << std::endl; } void AbstractReportExporter::prepareData(const ReportData& data) { std::cout << "Preparing report data..." << std::endl; } void AbstractReportExporter::openFile(const std::string& filePath) { std::cout << "Opening file: " << filePath << std::endl; } void AbstractReportExporter::writeFooter(const ReportData& data) { std::cout << "Writing footer..." << std::endl; } void AbstractReportExporter::closeFile(const std::string& filePath) { std::cout << "Closing file: " << filePath << std::endl; } ================================================ FILE: design-patterns/cpp/templatemethod/abstract_report_exporter.h ================================================ #pragma once #include "report_data.h" #include class AbstractReportExporter { public: virtual ~AbstractReportExporter() = default; // Template method void exportReport(const ReportData& data, const std::string& filePath); protected: // Hook methods - optional for subclasses to override virtual void prepareData(const ReportData& data); virtual void openFile(const std::string& filePath); virtual void writeHeader(const ReportData& data) = 0; virtual void writeDataRows(const ReportData& data) = 0; virtual void writeFooter(const ReportData& data); virtual void closeFile(const std::string& filePath); }; ================================================ FILE: design-patterns/cpp/templatemethod/csv_report_exporter.cpp ================================================ #include "csv_report_exporter.h" #include #include void CsvReportExporter::writeHeader(const ReportData& data) { std::cout << "Writing CSV header..." << std::endl; const auto& headers = data.getHeaders(); for (size_t i = 0; i < headers.size(); ++i) { std::cout << headers[i]; if (i < headers.size() - 1) { std::cout << ","; } } std::cout << std::endl; } void CsvReportExporter::writeDataRows(const ReportData& data) { std::cout << "Writing CSV data rows..." << std::endl; for (const auto& row : data.getRows()) { for (const auto& header : data.getHeaders()) { const auto& value = row.at(header); std::visit([](const auto& v) { std::cout << v; }, value); if (&header != &data.getHeaders().back()) { std::cout << ","; } } std::cout << std::endl; } } ================================================ FILE: design-patterns/cpp/templatemethod/csv_report_exporter.h ================================================ #pragma once #include "abstract_report_exporter.h" class CsvReportExporter : public AbstractReportExporter { protected: void writeHeader(const ReportData& data) override; void writeDataRows(const ReportData& data) override; }; ================================================ FILE: design-patterns/cpp/templatemethod/excel_report_exporter.cpp ================================================ #include "excel_report_exporter.h" #include void ExcelReportExporter::writeHeader(const ReportData& data) { std::cout << "Writing Excel header..." << std::endl; std::cout << "| "; for (const auto& header : data.getHeaders()) { std::cout << header << " | "; } std::cout << std::endl; std::cout << "|"; for (size_t i = 0; i < data.getHeaders().size(); ++i) { std::cout << "---|"; } std::cout << std::endl; } void ExcelReportExporter::writeDataRows(const ReportData& data) { std::cout << "Writing Excel data rows..." << std::endl; for (const auto& row : data.getRows()) { std::cout << "| "; for (const auto& header : data.getHeaders()) { const auto& value = row.at(header); std::visit([](const auto& v) { std::cout << v; }, value); std::cout << " | "; } std::cout << std::endl; } } ================================================ FILE: design-patterns/cpp/templatemethod/excel_report_exporter.h ================================================ #pragma once #include "abstract_report_exporter.h" class ExcelReportExporter : public AbstractReportExporter { protected: void writeHeader(const ReportData& data) override; void writeDataRows(const ReportData& data) override; }; ================================================ FILE: design-patterns/cpp/templatemethod/pdf_report_exporter.cpp ================================================ #include "pdf_report_exporter.h" #include void PdfReportExporter::writeHeader(const ReportData& data) { std::cout << "Writing PDF header..." << std::endl; std::cout << "=== Report Header ===" << std::endl; for (const auto& header : data.getHeaders()) { std::cout << header << "\t"; } std::cout << std::endl; std::cout << "===================" << std::endl; } void PdfReportExporter::writeDataRows(const ReportData& data) { std::cout << "Writing PDF data rows..." << std::endl; for (const auto& row : data.getRows()) { for (const auto& header : data.getHeaders()) { const auto& value = row.at(header); std::visit([](const auto& v) { std::cout << v; }, value); std::cout << "\t"; } std::cout << std::endl; } } ================================================ FILE: design-patterns/cpp/templatemethod/pdf_report_exporter.h ================================================ #pragma once #include "abstract_report_exporter.h" class PdfReportExporter : public AbstractReportExporter { protected: void writeHeader(const ReportData& data) override; void writeDataRows(const ReportData& data) override; }; ================================================ FILE: design-patterns/cpp/templatemethod/report_app.cpp ================================================ #include "report_data.h" #include "csv_report_exporter.h" #include "pdf_report_exporter.h" #include "excel_report_exporter.h" #include int main() { ReportData data; // Export to CSV std::cout << "\nExporting to CSV..." << std::endl; CsvReportExporter csvExporter; csvExporter.exportReport(data, "report.csv"); // Export to PDF std::cout << "\nExporting to PDF..." << std::endl; PdfReportExporter pdfExporter; pdfExporter.exportReport(data, "report.pdf"); // Export to Excel std::cout << "\nExporting to Excel..." << std::endl; ExcelReportExporter excelExporter; excelExporter.exportReport(data, "report.xlsx"); return 0; } ================================================ FILE: design-patterns/cpp/templatemethod/report_data.cpp ================================================ #include "report_data.h" std::vector ReportData::getHeaders() const { return {"ID", "Name", "Value"}; } std::vector>> ReportData::getRows() const { return { { {"ID", 1}, {"Name", "Item A"}, {"Value", 100.0} }, { {"ID", 2}, {"Name", "Item B"}, {"Value", 150.5} }, { {"ID", 3}, {"Name", "Item C"}, {"Value", 75.25} } }; } ================================================ FILE: design-patterns/cpp/templatemethod/report_data.h ================================================ #pragma once #include #include #include #include class ReportData { public: std::vector getHeaders() const; std::vector>> getRows() const; }; ================================================ FILE: design-patterns/csharp/adapter/CheckoutService.cs ================================================ using System; namespace Adapter { public class CheckoutService { private readonly IPaymentProcessor paymentProcessor; public CheckoutService(IPaymentProcessor paymentProcessor) { this.paymentProcessor = paymentProcessor; } public bool Checkout(double amount, string currency) { Console.WriteLine($"CheckoutService: Initiating checkout for {currency} {amount}"); paymentProcessor.ProcessPayment(amount, currency); if (paymentProcessor.IsPaymentSuccessful()) { Console.WriteLine($"CheckoutService: Payment successful. Transaction ID: {paymentProcessor.GetTransactionId()}"); return true; } Console.WriteLine("CheckoutService: Payment failed."); return false; } } } ================================================ FILE: design-patterns/csharp/adapter/IPaymentProcessor.cs ================================================ namespace Adapter { public interface IPaymentProcessor { void ProcessPayment(double amount, string currency); bool IsPaymentSuccessful(); string GetTransactionId(); } } ================================================ FILE: design-patterns/csharp/adapter/InHousePaymentProcessor.cs ================================================ using System; namespace Adapter { public class InHousePaymentProcessor : IPaymentProcessor { private string transactionId; private bool isPaymentSuccessful; public void ProcessPayment(double amount, string currency) { try { Console.WriteLine($"InHousePaymentProcessor: Processing payment of {currency} {amount}"); transactionId = Guid.NewGuid().ToString(); isPaymentSuccessful = true; Console.WriteLine($"InHousePaymentProcessor: Payment processed successfully. Txn ID: {transactionId}"); } catch (Exception ex) { Console.WriteLine($"Error processing payment: {ex.Message}"); isPaymentSuccessful = false; } } public bool IsPaymentSuccessful() { return isPaymentSuccessful; } public string GetTransactionId() { return transactionId; } } } ================================================ FILE: design-patterns/csharp/adapter/LegacyGateway.cs ================================================ using System; namespace Adapter { public class LegacyGateway { private long transactionReference; private bool isPaymentSuccessful; public void ExecuteTransaction(double totalAmount, string currency) { Console.WriteLine($"LegacyGateway: Executing transaction for {currency} {totalAmount}"); transactionReference = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); isPaymentSuccessful = true; Console.WriteLine($"LegacyGateway: Transaction executed successfully. Txn ID: {transactionReference}"); } public bool CheckStatus(long transactionReference) { Console.WriteLine($"LegacyGateway: Checking status for ref: {transactionReference}"); return isPaymentSuccessful; } public long GetReferenceNumber() { return transactionReference; } } } ================================================ FILE: design-patterns/csharp/adapter/LegacyGatewayAdapter.cs ================================================ using System; namespace Adapter { public class LegacyGatewayAdapter : IPaymentProcessor { private readonly LegacyGateway legacyGateway; private bool isPaymentSuccessful; public LegacyGatewayAdapter() { legacyGateway = new LegacyGateway(); } public void ProcessPayment(double amount, string currency) { try { legacyGateway.ExecuteTransaction(amount, currency); isPaymentSuccessful = true; } catch (Exception ex) { Console.WriteLine($"Error processing payment: {ex.Message}"); isPaymentSuccessful = false; } } public bool IsPaymentSuccessful() { return isPaymentSuccessful && legacyGateway.CheckStatus(legacyGateway.GetReferenceNumber()); } public string GetTransactionId() { return legacyGateway.GetReferenceNumber().ToString(); } } } ================================================ FILE: design-patterns/csharp/adapter/Program.cs ================================================ using System; namespace Adapter { class Program { static void Main(string[] args) { // Example 1: Using the in-house payment processor Console.WriteLine("=== Using In-House Payment Processor ==="); var inHouseProcessor = new InHousePaymentProcessor(); var checkoutService1 = new CheckoutService(inHouseProcessor); checkoutService1.Checkout(100.00, "USD"); Console.WriteLine("\n=== Using Legacy Gateway Adapter ==="); var legacyAdapter = new LegacyGatewayAdapter(); var checkoutService2 = new CheckoutService(legacyAdapter); checkoutService2.Checkout(200.00, "EUR"); } } } ================================================ FILE: design-patterns/csharp/bridge/Circle.cs ================================================ namespace Bridge { public class Circle : Shape { private readonly float radius; public Circle(IRenderer renderer, float radius) : base(renderer) { this.radius = radius; } public override void Draw() { renderer.RenderCircle(radius); } } } ================================================ FILE: design-patterns/csharp/bridge/IRenderer.cs ================================================ namespace Bridge { public interface IRenderer { void RenderCircle(float radius); void RenderRectangle(float width, float height); } } ================================================ FILE: design-patterns/csharp/bridge/Program.cs ================================================ using System; namespace Bridge { class Program { static void Main(string[] args) { // Create renderers var vectorRenderer = new VectorRenderer(); var rasterRenderer = new RasterRenderer(); // Create shapes with vector renderer Console.WriteLine("=== Drawing with Vector Renderer ==="); var vectorCircle = new Circle(vectorRenderer, 5); var vectorRectangle = new Rectangle(vectorRenderer, 10, 5); vectorCircle.Draw(); vectorRectangle.Draw(); // Create shapes with raster renderer Console.WriteLine("\n=== Drawing with Raster Renderer ==="); var rasterCircle = new Circle(rasterRenderer, 5); var rasterRectangle = new Rectangle(rasterRenderer, 10, 5); rasterCircle.Draw(); rasterRectangle.Draw(); } } } ================================================ FILE: design-patterns/csharp/bridge/RasterRenderer.cs ================================================ using System; namespace Bridge { public class RasterRenderer : IRenderer { public void RenderCircle(float radius) { Console.WriteLine($"Drawing a circle of radius {radius} using raster graphics"); } public void RenderRectangle(float width, float height) { Console.WriteLine($"Drawing a rectangle of width {width} and height {height} using raster graphics"); } } } ================================================ FILE: design-patterns/csharp/bridge/Rectangle.cs ================================================ namespace Bridge { public class Rectangle : Shape { private readonly float width; private readonly float height; public Rectangle(IRenderer renderer, float width, float height) : base(renderer) { this.width = width; this.height = height; } public override void Draw() { renderer.RenderRectangle(width, height); } } } ================================================ FILE: design-patterns/csharp/bridge/Shape.cs ================================================ namespace Bridge { public abstract class Shape { protected readonly IRenderer renderer; protected Shape(IRenderer renderer) { this.renderer = renderer; } public abstract void Draw(); } } ================================================ FILE: design-patterns/csharp/bridge/VectorRenderer.cs ================================================ using System; namespace Bridge { public class VectorRenderer : IRenderer { public void RenderCircle(float radius) { Console.WriteLine($"Drawing a circle of radius {radius} using vector graphics"); } public void RenderRectangle(float width, float height) { Console.WriteLine($"Drawing a rectangle of width {width} and height {height} using vector graphics"); } } } ================================================ FILE: design-patterns/csharp/builder/HttpRequest.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Builder { public class HttpRequest { public string Url { get; } // Required public string Method { get; } // Optional, default GET public IReadOnlyDictionary Headers { get; } // Optional public IReadOnlyDictionary QueryParams { get; } // Optional public string Body { get; } // Optional public int Timeout { get; } // Optional, default 30s // Private constructor, only accessible by the Builder private HttpRequest(Builder builder) { Url = builder.Url; Method = builder.Method; Headers = new Dictionary(builder.Headers); // Defensive copy QueryParams = new Dictionary(builder.QueryParams); // Defensive copy Body = builder.Body; Timeout = builder.Timeout; } public override string ToString() { return $"HttpRequest{{" + $"url='{Url}', " + $"method='{Method}', " + $"headers={{{string.Join(", ", Headers.Select(kv => $"{kv.Key}={kv.Value}"))}}}, " + $"queryParams={{{string.Join(", ", QueryParams.Select(kv => $"{kv.Key}={kv.Value}"))}}}, " + $"body='{(Body != null ? (Body.Length > 10 ? Body.Substring(0, 10) + "..." : Body) : "null")}', " + $"timeout={Timeout}}}"; } // --- Builder Class --- public class Builder { // Required parameter public string Url { get; } // Optional parameters - initialized to default values public string Method { get; private set; } = "GET"; public Dictionary Headers { get; } = new Dictionary(); public Dictionary QueryParams { get; } = new Dictionary(); public string Body { get; private set; } public int Timeout { get; private set; } = 30000; // 30 seconds default // Builder constructor for required fields public Builder(string url) { if (string.IsNullOrWhiteSpace(url)) { throw new ArgumentException("URL cannot be null or empty.", nameof(url)); } Url = url; } // Setter-like methods for optional fields, returning the Builder for fluency public Builder WithMethod(string method) { Method = string.IsNullOrWhiteSpace(method) ? "GET" : method.ToUpper(); return this; } public Builder WithHeader(string key, string value) { if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) { Headers[key] = value; } return this; } public Builder WithQueryParam(string key, string value) { if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) { QueryParams[key] = value; } return this; } public Builder WithBody(string body) { Body = body; return this; } public Builder WithTimeout(int timeoutMillis) { if (timeoutMillis > 0) { Timeout = timeoutMillis; } return this; } // The final build method that creates the HttpRequest object public HttpRequest Build() { // Optionally, add validation logic here before creating the object if ((Method == "POST" || Method == "PUT") && string.IsNullOrEmpty(Body)) { Console.WriteLine($"Warning: Building {Method} request without a body for URL: {Url}"); } return new HttpRequest(this); } } } } ================================================ FILE: design-patterns/csharp/builder/Program.cs ================================================ using System; namespace Builder { class Program { static void Main(string[] args) { // Example 1: Simple GET request var getRequest = new HttpRequest.Builder("https://api.example.com/users") .WithHeader("Accept", "application/json") .WithQueryParam("page", "1") .WithQueryParam("limit", "10") .Build(); Console.WriteLine("=== GET Request ==="); Console.WriteLine(getRequest); // Example 2: POST request with body var postRequest = new HttpRequest.Builder("https://api.example.com/users") .WithMethod("POST") .WithHeader("Content-Type", "application/json") .WithHeader("Authorization", "Bearer token123") .WithBody("{\"name\":\"John Doe\",\"email\":\"john@example.com\"}") .WithTimeout(5000) .Build(); Console.WriteLine("\n=== POST Request ==="); Console.WriteLine(postRequest); // Example 3: PUT request with validation warning var putRequest = new HttpRequest.Builder("https://api.example.com/users/123") .WithMethod("PUT") .WithHeader("Content-Type", "application/json") .WithHeader("Authorization", "Bearer token123") .WithTimeout(10000) .Build(); Console.WriteLine("\n=== PUT Request (with warning) ==="); Console.WriteLine(putRequest); } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/AuthHandler.cs ================================================ using System; namespace ChainOfResponsibility { public class AuthHandler : BaseHandler { public override void Handle(Request request) { if (string.IsNullOrEmpty(request.User)) { Console.WriteLine("AuthHandler: User is not authenticated"); return; } Console.WriteLine($"AuthHandler: User {request.User} is authenticated"); HandleNext(request); } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/AuthorizationHandler.cs ================================================ using System; namespace ChainOfResponsibility { public class AuthorizationHandler : BaseHandler { public override void Handle(Request request) { if (string.IsNullOrEmpty(request.UserRole) || request.UserRole != "ADMIN") { Console.WriteLine($"AuthorizationHandler: User {request.User} is not authorized"); return; } Console.WriteLine($"AuthorizationHandler: User {request.User} is authorized"); HandleNext(request); } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/BaseHandler.cs ================================================ namespace ChainOfResponsibility { public abstract class BaseHandler : IRequestHandler { protected IRequestHandler Next { get; private set; } public void SetNext(IRequestHandler next) { Next = next; } public abstract void Handle(Request request); protected void HandleNext(Request request) { if (Next != null) { Next.Handle(request); } } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/BusinessLogicHandler.cs ================================================ using System; namespace ChainOfResponsibility { public class BusinessLogicHandler : BaseHandler { public override void Handle(Request request) { Console.WriteLine($"BusinessLogicHandler: Processing request for user {request.User}"); HandleNext(request); } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/IRequestHandler.cs ================================================ ================================================ FILE: design-patterns/csharp/chainofresponsibility/Program.cs ================================================ ================================================ FILE: design-patterns/csharp/chainofresponsibility/RateLimitHandler.cs ================================================ using System; namespace ChainOfResponsibility { public class RateLimitHandler : BaseHandler { private const int MAX_REQUESTS = 5; public override void Handle(Request request) { if (request.RequestCount > MAX_REQUESTS) { Console.WriteLine($"RateLimitHandler: User {request.User} has exceeded the rate limit"); return; } Console.WriteLine($"RateLimitHandler: User {request.User} is within rate limit"); HandleNext(request); } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/Request.cs ================================================ namespace ChainOfResponsibility { public class Request { public string User { get; } public string UserRole { get; } public int RequestCount { get; } public string Payload { get; } public Request(string user, string role, int requestCount, string payload) { User = user; UserRole = role; RequestCount = requestCount; Payload = payload; } } } ================================================ FILE: design-patterns/csharp/chainofresponsibility/ValidationHandler.cs ================================================ using System; namespace ChainOfResponsibility { public class ValidationHandler : BaseHandler { public override void Handle(Request request) { if (string.IsNullOrEmpty(request.Payload)) { Console.WriteLine("ValidationHandler: Request payload is empty"); return; } Console.WriteLine("ValidationHandler: Request payload is valid"); HandleNext(request); } } } ================================================ FILE: design-patterns/csharp/composite/File.cs ================================================ using System; namespace Composite { public class File : IFileSystemItem { private readonly string name; private readonly int size; public File(string name, int size) { this.name = name; this.size = size; } public int GetSize() { return size; } public void PrintStructure(string indent) { Console.WriteLine($"{indent}File: {name} ({size} bytes)"); } public void Delete() { Console.WriteLine($"Deleting file: {name}"); } } } ================================================ FILE: design-patterns/csharp/composite/Folder.cs ================================================ using System; using System.Collections.Generic; namespace Composite { public class Folder : IFileSystemItem { private readonly string name; private readonly List children; public Folder(string name) { this.name = name; this.children = new List(); } public void Add(IFileSystemItem item) { children.Add(item); } public void Remove(IFileSystemItem item) { children.Remove(item); } public int GetSize() { int totalSize = 0; foreach (var child in children) { totalSize += child.GetSize(); } return totalSize; } public void PrintStructure(string indent) { Console.WriteLine($"{indent}Folder: {name}"); foreach (var child in children) { child.PrintStructure(indent + " "); } } public void Delete() { Console.WriteLine($"Deleting folder: {name}"); foreach (var child in children) { child.Delete(); } } } } ================================================ FILE: design-patterns/csharp/composite/IFileSystemItem.cs ================================================ namespace Composite { public interface IFileSystemItem { int GetSize(); void PrintStructure(string indent); void Delete(); } } ================================================ FILE: design-patterns/csharp/composite/Program.cs ================================================ using System; namespace Composite { class Program { static void Main(string[] args) { // Create a file system structure var root = new Folder("Root"); var documents = new Folder("Documents"); var downloads = new Folder("Downloads"); var pictures = new Folder("Pictures"); var file1 = new File("readme.txt", 1024); var file2 = new File("document.pdf", 2048); var file3 = new File("image.jpg", 4096); var file4 = new File("video.mp4", 8192); // Build the structure root.Add(documents); root.Add(downloads); root.Add(pictures); documents.Add(file1); documents.Add(file2); downloads.Add(file3); pictures.Add(file4); // Print the structure Console.WriteLine("=== File System Structure ==="); root.PrintStructure(""); // Get total size Console.WriteLine($"\nTotal size: {root.GetSize()} bytes"); // Delete a folder Console.WriteLine("\n=== Deleting Documents Folder ==="); documents.Delete(); } } } ================================================ FILE: design-patterns/csharp/decorator/BoldDecorator.cs ================================================ using System; namespace Decorator { public class BoldDecorator : TextDecorator { public BoldDecorator(ITextView inner) : base(inner) { } public override void Render() { Console.Write(""); inner.Render(); Console.Write(""); } } } ================================================ FILE: design-patterns/csharp/decorator/ITextView.cs ================================================ namespace Decorator { public interface ITextView { void Render(); } } ================================================ FILE: design-patterns/csharp/decorator/ItalicDecorator.cs ================================================ using System; namespace Decorator { public class ItalicDecorator : TextDecorator { public ItalicDecorator(ITextView inner) : base(inner) { } public override void Render() { Console.Write(""); inner.Render(); Console.Write(""); } } } ================================================ FILE: design-patterns/csharp/decorator/PlainTextView.cs ================================================ using System; namespace Decorator { public class PlainTextView : ITextView { private readonly string text; public PlainTextView(string text) { this.text = text; } public void Render() { Console.Write(text); } } } ================================================ FILE: design-patterns/csharp/decorator/Program.cs ================================================ using System; namespace Decorator { class Program { static void Main(string[] args) { ITextView plain = new PlainTextView("Hello, world!"); Console.Write("Plain: "); plain.Render(); Console.WriteLine(); Console.Write("Bold: "); ITextView bold = new BoldDecorator(plain); bold.Render(); Console.WriteLine(); Console.Write("Italic + Bold: "); ITextView italicBold = new ItalicDecorator(bold); italicBold.Render(); Console.WriteLine(); Console.Write("Underline + Italic + Bold: "); ITextView fullStyle = new UnderlineDecorator(italicBold); fullStyle.Render(); Console.WriteLine(); } } } ================================================ FILE: design-patterns/csharp/decorator/TextDecorator.cs ================================================ namespace Decorator { public abstract class TextDecorator : ITextView { protected readonly ITextView inner; public TextDecorator(ITextView inner) { this.inner = inner; } public abstract void Render(); } } ================================================ FILE: design-patterns/csharp/decorator/UnderlineDecorator.cs ================================================ using System; namespace Decorator { public class UnderlineDecorator : TextDecorator { public UnderlineDecorator(ITextView inner) : base(inner) { } public override void Render() { Console.Write(""); inner.Render(); Console.Write(""); } } } ================================================ FILE: design-patterns/csharp/facade/BuildSystem.cs ================================================ using System; using System.Threading; namespace Facade { public class BuildSystem { public bool CompileProject() { Console.WriteLine("BuildSystem: Compiling project..."); SimulateDelay(2000); Console.WriteLine("BuildSystem: Build successful."); return true; } public string GetArtifactPath() { string path = "target/myapplication-1.0.jar"; Console.WriteLine($"BuildSystem: Artifact located at {path}"); return path; } private void SimulateDelay(int ms) { Thread.Sleep(ms); } } } ================================================ FILE: design-patterns/csharp/facade/DeploymentFacade.cs ================================================ using System; namespace Facade { public class DeploymentFacade { private readonly VersionControlSystem vcs; private readonly BuildSystem buildSystem; private readonly TestingFramework testingFramework; private readonly DeploymentTarget deploymentTarget; public DeploymentFacade() { vcs = new VersionControlSystem(); buildSystem = new BuildSystem(); testingFramework = new TestingFramework(); deploymentTarget = new DeploymentTarget(); } public bool DeployApplication(string branch, string serverAddress) { Console.WriteLine($"\nFACADE: --- Initiating FULL DEPLOYMENT for branch: {branch} to {serverAddress} ---"); bool success = true; try { // Step 1: Pull latest code vcs.PullLatestChanges(branch); // Step 2: Build the project if (!buildSystem.CompileProject()) { Console.Error.WriteLine("FACADE: DEPLOYMENT FAILED - Build compilation failed."); return false; } string artifactPath = buildSystem.GetArtifactPath(); // Step 3: Run tests if (!testingFramework.RunUnitTests()) { Console.Error.WriteLine("FACADE: DEPLOYMENT FAILED - Unit tests failed."); return false; } if (!testingFramework.RunIntegrationTests()) { Console.Error.WriteLine("FACADE: DEPLOYMENT FAILED - Integration tests failed."); return false; } // Step 4: Deploy to production deploymentTarget.TransferArtifact(artifactPath, serverAddress); deploymentTarget.ActivateNewVersion(serverAddress); Console.WriteLine($"FACADE: APPLICATION DEPLOYED SUCCESSFULLY TO {serverAddress}!"); } catch (Exception e) { Console.Error.WriteLine($"FACADE: DEPLOYMENT FAILED - An unexpected error occurred: {e.Message}"); success = false; } return success; } public bool DeployHotfix(string branch, string serverAddress) { Console.WriteLine($"\nFACADE: --- Initiating HOTFIX DEPLOYMENT for branch: {branch} to {serverAddress} ---"); bool success = true; try { // Step 1: Pull latest code vcs.PullLatestChanges(branch); // Step 2: Build the project if (!buildSystem.CompileProject()) { Console.Error.WriteLine("FACADE: HOTFIX FAILED - Build compilation failed."); return false; } string artifactPath = buildSystem.GetArtifactPath(); // Step 3: For a hotfix, we might skip extensive tests or run a specific "smoke test" suite. Console.WriteLine("FACADE: Skipping full test suite for hotfix deployment (or running minimal smoke tests)."); // Step 4: Deploy to production deploymentTarget.TransferArtifact(artifactPath, serverAddress); deploymentTarget.ActivateNewVersion(serverAddress); Console.WriteLine($"FACADE: HOTFIX DEPLOYED SUCCESSFULLY TO {serverAddress}!"); } catch (Exception e) { Console.Error.WriteLine($"FACADE: HOTFIX FAILED - An unexpected error occurred: {e.Message}"); success = false; } return success; } } } ================================================ FILE: design-patterns/csharp/facade/DeploymentTarget.cs ================================================ using System; using System.Threading; namespace Facade { public class DeploymentTarget { public void TransferArtifact(string artifactPath, string server) { Console.WriteLine($"Deployment: Transferring {artifactPath} to {server}..."); SimulateDelay(1000); Console.WriteLine("Deployment: Transfer complete."); } public void ActivateNewVersion(string server) { Console.WriteLine($"Deployment: Activating new version on {server}..."); SimulateDelay(500); Console.WriteLine($"Deployment: Now live on {server}!"); } private void SimulateDelay(int ms) { Thread.Sleep(ms); } } } ================================================ FILE: design-patterns/csharp/facade/Program.cs ================================================ using System; namespace Facade { class Program { static void Main(string[] args) { var deploymentFacade = new DeploymentFacade(); // Demonstrate full deployment Console.WriteLine("=== Full Deployment Example ==="); deploymentFacade.DeployApplication("main", "production-server"); // Demonstrate hotfix deployment Console.WriteLine("\n=== Hotfix Deployment Example ==="); deploymentFacade.DeployHotfix("hotfix/security-patch", "production-server"); } } } ================================================ FILE: design-patterns/csharp/facade/TestingFramework.cs ================================================ using System; using System.Threading; namespace Facade { public class TestingFramework { public bool RunUnitTests() { Console.WriteLine("Testing: Running unit tests..."); SimulateDelay(1500); Console.WriteLine("Testing: Unit tests passed."); return true; } public bool RunIntegrationTests() { Console.WriteLine("Testing: Running integration tests..."); SimulateDelay(3000); Console.WriteLine("Testing: Integration tests passed."); return true; } private void SimulateDelay(int ms) { Thread.Sleep(ms); } } } ================================================ FILE: design-patterns/csharp/facade/VersionControlSystem.cs ================================================ ================================================ FILE: design-patterns/csharp/factory/EmailNotification.cs ================================================ using System; namespace Factory { public class EmailNotification : INotification { public void Send(string message) { Console.WriteLine($"Sending email: {message}"); } } } ================================================ FILE: design-patterns/csharp/factory/INotification.cs ================================================ namespace Factory { public interface INotification { void Send(string message); } } ================================================ FILE: design-patterns/csharp/factory/NotificationServiceNaive.cs ================================================ using System; namespace Factory { public class NotificationServiceNaive { public void SendNotification(string type, string message) { if (type == "EMAIL") { var email = new EmailNotification(); email.Send(message); } else if (type == "SMS") { var sms = new SMSNotification(); sms.Send(message); } else if (type == "PUSH") { var push = new PushNotification(); push.Send(message); } } } } ================================================ FILE: design-patterns/csharp/factory/Program.cs ================================================ using System; namespace Factory { class Program { static void Main(string[] args) { // Using the factory Console.WriteLine("=== Using Factory Pattern ==="); var emailNotification = SimpleNotificationFactory.CreateNotification("EMAIL"); emailNotification.Send("Hello via Email!"); var smsNotification = SimpleNotificationFactory.CreateNotification("SMS"); smsNotification.Send("Hello via SMS!"); var pushNotification = SimpleNotificationFactory.CreateNotification("PUSH"); pushNotification.Send("Hello via Push!"); // Using the naive approach Console.WriteLine("\n=== Using Naive Approach ==="); var notificationService = new NotificationServiceNaive(); notificationService.SendNotification("EMAIL", "Hello via Email!"); notificationService.SendNotification("SMS", "Hello via SMS!"); notificationService.SendNotification("PUSH", "Hello via Push!"); } } } ================================================ FILE: design-patterns/csharp/factory/PushNotification.cs ================================================ using System; namespace Factory { public class PushNotification : INotification { public void Send(string message) { Console.WriteLine($"Sending push notification: {message}"); } } } ================================================ FILE: design-patterns/csharp/factory/SMSNotification.cs ================================================ using System; namespace Factory { public class SMSNotification : INotification { public void Send(string message) { Console.WriteLine($"Sending SMS: {message}"); } } } ================================================ FILE: design-patterns/csharp/factory/SimpleNotificationFactory.cs ================================================ ================================================ FILE: design-patterns/csharp/flyweight/CharacterFlyweightFactory.cs ================================================ using System; using System.Collections.Generic; namespace Flyweight { public class CharacterFlyweightFactory { private static readonly Dictionary flyweightCache = new(); public static ICharacterFlyweight GetFlyweight(char symbol, string fontFamily, int fontSize, string color) { string key = $"{symbol}-{fontSize}-{color}"; if (!flyweightCache.ContainsKey(key)) { flyweightCache[key] = new CharacterGlyph(symbol, fontFamily, fontSize, color); } return flyweightCache[key]; } public int GetFlyweightCount() { return flyweightCache.Count; } } } ================================================ FILE: design-patterns/csharp/flyweight/CharacterGlyph.cs ================================================ using System; namespace Flyweight { public class CharacterGlyph : ICharacterFlyweight { private readonly char symbol; private readonly string fontFamily; private readonly int fontSize; private readonly string color; public CharacterGlyph(char symbol, string fontFamily, int fontSize, string color) { this.symbol = symbol; this.fontFamily = fontFamily; this.fontSize = fontSize; this.color = color; } public void Draw(int x, int y) { Console.WriteLine($"Rendering {symbol} at ({x}, {y}) with font {fontFamily}, size {fontSize}, color {color}"); } } } ================================================ FILE: design-patterns/csharp/flyweight/ICharacterFlyweight.cs ================================================ namespace Flyweight { public interface ICharacterFlyweight { void Draw(int x, int y); } } ================================================ FILE: design-patterns/csharp/flyweight/Program.cs ================================================ using System; namespace Flyweight { class Program { static void Main(string[] args) { var editor = new TextEditorClient(); // Render 'Hello' with the same style string word = "Hello"; for (int i = 0; i < word.Length; i++) { editor.AddCharacter(word[i], 10 + i * 15, 50, "Arial", 14, "#000000"); } // Render 'World' with a different font and color string word2 = "World"; for (int i = 0; i < word2.Length; i++) { editor.AddCharacter(word2[i], 10 + i * 15, 100, "Times New Roman", 14, "#3333FF"); } editor.RenderDocument(); } } } ================================================ FILE: design-patterns/csharp/flyweight/TextEditorClient.cs ================================================ using System; using System.Collections.Generic; namespace Flyweight { public class TextEditorClient { private readonly CharacterFlyweightFactory factory = new(); private readonly List document = new(); public void AddCharacter(char c, int x, int y, string font, int size, string color) { ICharacterFlyweight glyph = CharacterFlyweightFactory.GetFlyweight(c, font, size, color); document.Add(new RenderedCharacter(glyph, x, y)); } public void RenderDocument() { foreach (var rc in document) { rc.Draw(); } Console.WriteLine($"Total flyweight objects used: {factory.GetFlyweightCount()}"); } private class RenderedCharacter { private readonly ICharacterFlyweight glyph; private readonly int x, y; public RenderedCharacter(ICharacterFlyweight glyph, int x, int y) { this.glyph = glyph; this.x = x; this.y = y; } public void Draw() { glyph.Draw(x, y); } } } } ================================================ FILE: design-patterns/csharp/iterator/IIterableCollection.cs ================================================ namespace Iterator { public interface IIterableCollection { IIterator CreateIterator(); } } ================================================ FILE: design-patterns/csharp/iterator/IIterator.cs ================================================ namespace Iterator { public interface IIterator { bool HasNext(); T Next(); } } ================================================ FILE: design-patterns/csharp/iterator/Playlist.cs ================================================ ================================================ FILE: design-patterns/csharp/iterator/PlaylistIterator.cs ================================================ ================================================ FILE: design-patterns/csharp/iterator/Program.cs ================================================ ================================================ FILE: design-patterns/csharp/mediator/Button.cs ================================================ using System; namespace Mediator { public class Button : UIComponent { private bool enabled = false; public Button(IUIMediator mediator) : base(mediator) { } public void Click() { if (enabled) { Console.WriteLine("Login Button clicked!"); NotifyMediator(); // Will trigger login attempt } else { Console.WriteLine("Login Button is disabled."); } } public void SetEnabled(bool value) { this.enabled = value; Console.WriteLine($"Login Button is now {(enabled ? "ENABLED" : "DISABLED")}"); } } } ================================================ FILE: design-patterns/csharp/mediator/FormMediator.cs ================================================ namespace Mediator { public class FormMediator : IUIMediator { private TextField usernameField; private TextField passwordField; private Button loginButton; private Label statusLabel; public void SetUsernameField(TextField usernameField) { this.usernameField = usernameField; } public void SetPasswordField(TextField passwordField) { this.passwordField = passwordField; } public void SetLoginButton(Button loginButton) { this.loginButton = loginButton; } public void SetStatusLabel(Label statusLabel) { this.statusLabel = statusLabel; } public void ComponentChanged(UIComponent component) { if (component == usernameField || component == passwordField) { bool enableButton = !string.IsNullOrEmpty(usernameField.GetText()) && !string.IsNullOrEmpty(passwordField.GetText()); loginButton.SetEnabled(enableButton); } else if (component == loginButton) { string username = usernameField.GetText(); string password = passwordField.GetText(); if (username == "admin" && password == "1234") { statusLabel.SetText("✅ Login successful!"); } else { statusLabel.SetText("❌ Invalid credentials."); } } } } } ================================================ FILE: design-patterns/csharp/mediator/IUIMediator.cs ================================================ namespace Mediator { public interface IUIMediator { void ComponentChanged(UIComponent component); } } ================================================ FILE: design-patterns/csharp/mediator/Label.cs ================================================ using System; namespace Mediator { public class Label : UIComponent { private string text; public Label(IUIMediator mediator) : base(mediator) { } public void SetText(string message) { this.text = message; Console.WriteLine($"Status: {text}"); } } } ================================================ FILE: design-patterns/csharp/mediator/Program.cs ================================================ using System; namespace Mediator { class Program { static void Main(string[] args) { var mediator = new FormMediator(); var usernameField = new TextField(mediator); var passwordField = new TextField(mediator); var loginButton = new Button(mediator); var statusLabel = new Label(mediator); mediator.SetUsernameField(usernameField); mediator.SetPasswordField(passwordField); mediator.SetLoginButton(loginButton); mediator.SetStatusLabel(statusLabel); // Simulate user interaction usernameField.SetText("admin"); passwordField.SetText("1234"); loginButton.Click(); // Should succeed Console.WriteLine("\n--- New Attempt with Wrong Password ---"); passwordField.SetText("wrong"); loginButton.Click(); // Should fail } } } ================================================ FILE: design-patterns/csharp/mediator/TextField.cs ================================================ using System; namespace Mediator { public class TextField : UIComponent { private string text = ""; public TextField(IUIMediator mediator) : base(mediator) { } public void SetText(string newText) { this.text = newText; Console.WriteLine($"TextField updated: {newText}"); NotifyMediator(); } public string GetText() { return text; } } } ================================================ FILE: design-patterns/csharp/mediator/UIComponent.cs ================================================ namespace Mediator { public abstract class UIComponent { protected readonly IUIMediator mediator; public UIComponent(IUIMediator mediator) { this.mediator = mediator; } public void NotifyMediator() { mediator.ComponentChanged(this); } } } ================================================ FILE: design-patterns/csharp/memento/Program.cs ================================================ using System; namespace Memento { class Program { static void Main(string[] args) { var editor = new TextEditor(); var undoManager = new TextEditorUndoManager(); // Type some text and save state editor.Type("Hello"); undoManager.Save(editor); editor.Type(" World"); undoManager.Save(editor); editor.Type("!"); Console.WriteLine($"Current content: {editor.GetContent()}"); // Undo twice Console.WriteLine("\nUndoing last change:"); undoManager.Undo(editor); Console.WriteLine($"Content after undo: {editor.GetContent()}"); Console.WriteLine("\nUndoing another change:"); undoManager.Undo(editor); Console.WriteLine($"Content after second undo: {editor.GetContent()}"); // Try to undo when nothing is left Console.WriteLine("\nTrying to undo when nothing is left:"); undoManager.Undo(editor); } } } ================================================ FILE: design-patterns/csharp/memento/TextEditor.cs ================================================ using System; namespace Memento { public class TextEditor { private string content = ""; public void Type(string newText) { content += newText; Console.WriteLine($"Typed: {newText}"); } public string GetContent() { return content; } public TextEditorMemento Save() { Console.WriteLine($"Saving state: \"{content}\""); return new TextEditorMemento(content); } public void Restore(TextEditorMemento memento) { content = memento.GetState(); Console.WriteLine($"Restored state to: \"{content}\""); } } } ================================================ FILE: design-patterns/csharp/memento/TextEditorMemento.cs ================================================ namespace Memento { public class TextEditorMemento { private readonly string state; public TextEditorMemento(string state) { this.state = state; } public string GetState() { return state; } } } ================================================ FILE: design-patterns/csharp/memento/TextEditorUndoManager.cs ================================================ using System; using System.Collections.Generic; namespace Memento { public class TextEditorUndoManager { private readonly Stack history = new Stack(); public void Save(TextEditor editor) { history.Push(editor.Save()); } public void Undo(TextEditor editor) { if (history.Count > 0) { editor.Restore(history.Pop()); } else { Console.WriteLine("Nothing to undo."); } } } } ================================================ FILE: design-patterns/csharp/observer/FitnessData.cs ================================================ using System; using System.Collections.Generic; namespace Observer { public class FitnessData : IFitnessDataSubject { private int steps; private int activeMinutes; private int calories; private readonly List observers = new List(); public void RegisterObserver(IFitnessDataObserver observer) { observers.Add(observer); } public void RemoveObserver(IFitnessDataObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (var observer in observers) { observer.Update(this); } } public void NewFitnessDataPushed(int steps, int activeMinutes, int calories) { this.steps = steps; this.activeMinutes = activeMinutes; this.calories = calories; Console.WriteLine($"\nFitnessData: New data received — Steps: {steps}, " + $"Active Minutes: {activeMinutes}, Calories: {calories}"); NotifyObservers(); } public void DailyReset() { this.steps = 0; this.activeMinutes = 0; this.calories = 0; Console.WriteLine("\nFitnessData: Daily reset performed."); NotifyObservers(); } // Properties public int Steps => steps; public int ActiveMinutes => activeMinutes; public int Calories => calories; } } ================================================ FILE: design-patterns/csharp/observer/GoalNotifier.cs ================================================ using System; namespace Observer { public class GoalNotifier : IFitnessDataObserver { private const int STEPS_GOAL = 10000; private const int ACTIVE_MINUTES_GOAL = 30; private const int CALORIES_GOAL = 500; public void Update(FitnessData data) { if (data.Steps >= STEPS_GOAL) { Console.WriteLine($"GoalNotifier: Congratulations! You've reached your daily steps goal of {STEPS_GOAL} steps!"); } if (data.ActiveMinutes >= ACTIVE_MINUTES_GOAL) { Console.WriteLine($"GoalNotifier: Great job! You've achieved your active minutes goal of {ACTIVE_MINUTES_GOAL} minutes!"); } if (data.Calories >= CALORIES_GOAL) { Console.WriteLine($"GoalNotifier: Amazing! You've burned {CALORIES_GOAL} calories today!"); } } } } ================================================ FILE: design-patterns/csharp/observer/IFitnessDataObserver.cs ================================================ namespace Observer { public interface IFitnessDataObserver { void Update(FitnessData data); } } ================================================ FILE: design-patterns/csharp/observer/IFitnessDataSubject.cs ================================================ namespace Observer { public interface IFitnessDataSubject { void RegisterObserver(IFitnessDataObserver observer); void RemoveObserver(IFitnessDataObserver observer); void NotifyObservers(); } } ================================================ FILE: design-patterns/csharp/observer/LiveActivityDisplay.cs ================================================ using System; namespace Observer { public class LiveActivityDisplay : IFitnessDataObserver { public void Update(FitnessData data) { Console.WriteLine($"LiveActivityDisplay: Steps: {data.Steps}, " + $"Active Minutes: {data.ActiveMinutes}, " + $"Calories: {data.Calories}"); } } } ================================================ FILE: design-patterns/csharp/observer/Program.cs ================================================ ================================================ FILE: design-patterns/csharp/observer/ProgressLogger.cs ================================================ using System; namespace Observer { public class ProgressLogger : IFitnessDataObserver { public void Update(FitnessData data) { Console.WriteLine($"ProgressLogger: Logging progress — " + $"Steps: {data.Steps}, " + $"Active Minutes: {data.ActiveMinutes}, " + $"Calories: {data.Calories}"); } } } ================================================ FILE: design-patterns/csharp/prototype/Enemy.cs ================================================ using System; namespace Prototype { public class Enemy : IEnemyPrototype { private string type; private int health; private double speed; private bool armored; private string weapon; public Enemy(string type, int health, double speed, bool armored, string weapon) { this.type = type; this.health = health; this.speed = speed; this.armored = armored; this.weapon = weapon; } public IEnemyPrototype Clone() { return new Enemy(type, health, speed, armored, weapon); } public void SetHealth(int health) { this.health = health; } public void PrintStats() { Console.WriteLine($"{type} [Health: {health}, Speed: {speed}, Armored: {armored}, Weapon: {weapon}]"); } } } ================================================ FILE: design-patterns/csharp/prototype/EnemyRegistry.cs ================================================ using System; using System.Collections.Generic; namespace Prototype { public class EnemyRegistry { private readonly Dictionary prototypes = new Dictionary(); public void Register(string key, Enemy prototype) { prototypes[key] = prototype; } public Enemy Get(string key) { if (prototypes.TryGetValue(key, out var prototype)) { return (Enemy)prototype.Clone(); } throw new ArgumentException($"No prototype registered for: {key}"); } } } ================================================ FILE: design-patterns/csharp/prototype/Game.cs ================================================ using System; namespace Prototype { class Game { static void Main(string[] args) { var registry = new EnemyRegistry(); // Register prototype enemies registry.Register("flying", new Enemy("FlyingEnemy", 100, 12.0, false, "Laser")); registry.Register("armored", new Enemy("ArmoredEnemy", 300, 6.0, true, "Cannon")); // Clone from registry Enemy e1 = registry.Get("flying"); Enemy e2 = registry.Get("flying"); e2.SetHealth(80); // this one is damaged Enemy e3 = registry.Get("armored"); // Print enemy stats e1.PrintStats(); e2.PrintStats(); e3.PrintStats(); } } } ================================================ FILE: design-patterns/csharp/prototype/IEnemyPrototype.cs ================================================ namespace Prototype { public interface IEnemyPrototype { IEnemyPrototype Clone(); } } ================================================ FILE: design-patterns/csharp/proxy/HighResolutionImage.cs ================================================ using System; using System.Threading; namespace Proxy { public class HighResolutionImage : IImage { private string fileName; private byte[] imageData; // Simulate large data public HighResolutionImage(string fileName) { this.fileName = fileName; LoadImageFromDisk(); // Expensive operation! } private void LoadImageFromDisk() { Console.WriteLine($"Loading image: {fileName} from disk (Expensive Operation)..."); // Simulate disk read and memory allocation Thread.Sleep(2000); // Simulate delay this.imageData = new byte[10 * 1024 * 1024]; // 10MB Console.WriteLine($"Image {fileName} loaded successfully."); } public void Display() { Console.WriteLine($"Displaying image: {fileName}"); // Actual rendering logic would go here } public string GetFileName() { return fileName; } } } ================================================ FILE: design-patterns/csharp/proxy/IImage.cs ================================================ namespace Proxy { public interface IImage { void Display(); string GetFileName(); } } ================================================ FILE: design-patterns/csharp/proxy/ImageGalleryApp.cs ================================================ using System; namespace Proxy { class ImageGalleryApp { static void Main(string[] args) { Console.WriteLine("Application Started. Initializing image proxies for gallery..."); // Create lightweight proxies instead of full image objects IImage image1 = new ImageProxy("photo1.jpg"); IImage image2 = new ImageProxy("photo2.png"); // Never displayed IImage image3 = new ImageProxy("photo3.gif"); Console.WriteLine("\nGallery initialized. No images actually loaded yet."); Console.WriteLine($"Image 1 Filename: {image1.GetFileName()}"); // Does not trigger image load // User clicks on image1 Console.WriteLine($"\nUser requests to display {image1.GetFileName()}"); image1.Display(); // Lazy loading happens here // User clicks on image1 again Console.WriteLine($"\nUser requests to display {image1.GetFileName()} again."); image1.Display(); // Already loaded; no loading delay // User clicks on image3 Console.WriteLine($"\nUser requests to display {image3.GetFileName()}"); image3.Display(); // Triggers loading for image3 Console.WriteLine("\nApplication finished. Note: photo2.png was never loaded."); } } } ================================================ FILE: design-patterns/csharp/proxy/ImageProxy.cs ================================================ using System; namespace Proxy { public class ImageProxy : IImage { private string fileName; private HighResolutionImage realImage; // RealSubject public ImageProxy(string fileName) { this.fileName = fileName; Console.WriteLine($"ImageProxy: Created for {fileName}. Real image not loaded yet."); } public string GetFileName() { // Can safely return without loading the image return fileName; } public void Display() { // Lazy initialization: Load only when Display() is called if (realImage == null) { Console.WriteLine($"ImageProxy: Display() requested for {fileName}. Loading high-resolution image..."); realImage = new HighResolutionImage(fileName); } else { Console.WriteLine($"ImageProxy: Using cached high-resolution image for {fileName}"); } // Delegate the display call to the real image realImage.Display(); } } } ================================================ FILE: design-patterns/csharp/singleton/BillPughSingleton.cs ================================================ namespace Singleton { public class BillPughSingleton { private BillPughSingleton() { } public static BillPughSingleton GetInstance() { return Nested.instance; } private class Nested { internal static readonly BillPughSingleton instance = new BillPughSingleton(); static Nested() { } } } } ================================================ FILE: design-patterns/csharp/singleton/DoubleCheckedLockingSingleton.cs ================================================ namespace Singleton { public class DoubleCheckedLockingSingleton { private static volatile DoubleCheckedLockingSingleton instance; private static readonly object lockObj = new object(); private DoubleCheckedLockingSingleton() { } public static DoubleCheckedLockingSingleton GetInstance() { if (instance == null) { lock (lockObj) { if (instance == null) { instance = new DoubleCheckedLockingSingleton(); } } } return instance; } } } ================================================ FILE: design-patterns/csharp/singleton/EagerSingleton.cs ================================================ namespace Singleton { public class EagerSingleton { private static readonly EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { } public static EagerSingleton GetInstance() { return instance; } } } ================================================ FILE: design-patterns/csharp/singleton/LazySingleton.cs ================================================ namespace Singleton { public class LazySingleton { private static LazySingleton instance; private LazySingleton() { } public static LazySingleton GetInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } } } ================================================ FILE: design-patterns/csharp/singleton/SingletonDemo.cs ================================================ using System; namespace Singleton { class SingletonDemo { static void Main(string[] args) { Console.WriteLine("LazySingleton: " + (LazySingleton.GetInstance() == LazySingleton.GetInstance())); Console.WriteLine("ThreadSafeSingleton: " + (ThreadSafeSingleton.GetInstance() == ThreadSafeSingleton.GetInstance())); Console.WriteLine("DoubleCheckedLockingSingleton: " + (DoubleCheckedLockingSingleton.GetInstance() == DoubleCheckedLockingSingleton.GetInstance())); Console.WriteLine("EagerSingleton: " + (EagerSingleton.GetInstance() == EagerSingleton.GetInstance())); Console.WriteLine("StaticBlockSingleton: " + (StaticBlockSingleton.GetInstance() == StaticBlockSingleton.GetInstance())); Console.WriteLine("BillPughSingleton: " + (BillPughSingleton.GetInstance() == BillPughSingleton.GetInstance())); } } } ================================================ FILE: design-patterns/csharp/singleton/StaticBlockSingleton.cs ================================================ using System; namespace Singleton { public class StaticBlockSingleton { private static readonly StaticBlockSingleton instance; static StaticBlockSingleton() { try { instance = new StaticBlockSingleton(); } catch (Exception ex) { throw new Exception("Exception occurred in creating singleton instance", ex); } } private StaticBlockSingleton() { } public static StaticBlockSingleton GetInstance() { return instance; } } } ================================================ FILE: design-patterns/csharp/singleton/ThreadSafeSingleton.cs ================================================ namespace Singleton { public class ThreadSafeSingleton { private static ThreadSafeSingleton instance; private static readonly object lockObj = new object(); private ThreadSafeSingleton() { } public static ThreadSafeSingleton GetInstance() { lock (lockObj) { if (instance == null) { instance = new ThreadSafeSingleton(); } return instance; } } } } ================================================ FILE: design-patterns/csharp/state/DispensingState.cs ================================================ using System; namespace State { public class DispensingState : IMachineState { public void SelectItem(VendingMachine context, string itemCode) { Console.WriteLine("Please wait, dispensing in progress."); } public void InsertCoin(VendingMachine context, double amount) { Console.WriteLine("Please wait, dispensing in progress."); } public void DispenseItem(VendingMachine context) { Console.WriteLine("Already dispensing. Please wait."); } } } ================================================ FILE: design-patterns/csharp/state/HasMoneyState.cs ================================================ using System; using System.Threading; namespace State { public class HasMoneyState : IMachineState { public void SelectItem(VendingMachine context, string itemCode) { Console.WriteLine("Cannot change item after inserting money."); } public void InsertCoin(VendingMachine context, double amount) { Console.WriteLine("Money already inserted."); } public void DispenseItem(VendingMachine context) { Console.WriteLine($"Dispensing item: {context.GetSelectedItem()}"); context.SetState(new DispensingState()); // Simulate dispensing Thread.Sleep(1000); Console.WriteLine("Item dispensed successfully."); context.Reset(); } } } ================================================ FILE: design-patterns/csharp/state/IMachineState.cs ================================================ namespace State { public interface IMachineState { void SelectItem(VendingMachine context, string itemCode); void InsertCoin(VendingMachine context, double amount); void DispenseItem(VendingMachine context); } } ================================================ FILE: design-patterns/csharp/state/IdleState.cs ================================================ using System; namespace State { public class IdleState : IMachineState { public void SelectItem(VendingMachine context, string itemCode) { Console.WriteLine($"Item selected: {itemCode}"); context.SetSelectedItem(itemCode); context.SetState(new ItemSelectedState()); } public void InsertCoin(VendingMachine context, double amount) { Console.WriteLine("Please select an item before inserting coins."); } public void DispenseItem(VendingMachine context) { Console.WriteLine("No item selected. Nothing to dispense."); } } } ================================================ FILE: design-patterns/csharp/state/ItemSelectedState.cs ================================================ using System; namespace State { public class ItemSelectedState : IMachineState { public void SelectItem(VendingMachine context, string itemCode) { Console.WriteLine($"Item already selected: {context.GetSelectedItem()}"); } public void InsertCoin(VendingMachine context, double amount) { Console.WriteLine($"Inserted ${amount} for item: {context.GetSelectedItem()}"); context.SetInsertedAmount(amount); context.SetState(new HasMoneyState()); } public void DispenseItem(VendingMachine context) { Console.WriteLine("Insert coin before dispensing."); } } } ================================================ FILE: design-patterns/csharp/state/Program.cs ================================================ using System; namespace State { class Program { static void Main(string[] args) { var vm = new VendingMachine(); vm.InsertCoin(1.0); // Invalid in IdleState vm.SelectItem("A1"); vm.InsertCoin(1.5); vm.DispenseItem(); Console.WriteLine("\n--- Second Transaction ---"); vm.SelectItem("B2"); vm.InsertCoin(2.0); vm.DispenseItem(); } } } ================================================ FILE: design-patterns/csharp/state/VendingMachine.cs ================================================ namespace State { public class VendingMachine { private IMachineState currentState; private string selectedItem; private double insertedAmount; public VendingMachine() { this.currentState = new IdleState(); // Initial state } public void SetState(IMachineState newState) { this.currentState = newState; } public void SetSelectedItem(string itemCode) { this.selectedItem = itemCode; } public void SetInsertedAmount(double amount) { this.insertedAmount = amount; } public string GetSelectedItem() { return selectedItem; } public double GetInsertedAmount() { return insertedAmount; } public void SelectItem(string itemCode) { currentState.SelectItem(this, itemCode); } public void InsertCoin(double amount) { currentState.InsertCoin(this, amount); } public void DispenseItem() { currentState.DispenseItem(this); } public void Reset() { this.selectedItem = ""; this.insertedAmount = 0.0; this.currentState = new IdleState(); } } } ================================================ FILE: design-patterns/csharp/strategy/DistanceBasedShipping.cs ================================================ namespace Strategy { public class DistanceBasedShipping : IShippingStrategy { private const double BASE_RATE = 5.0; private const double ZONE_A_MULTIPLIER = 1.0; private const double ZONE_B_MULTIPLIER = 1.5; private const double ZONE_C_MULTIPLIER = 2.0; public double CalculateCost(Order order) { double multiplier = order.GetDestinationZone() switch { "ZoneA" => ZONE_A_MULTIPLIER, "ZoneB" => ZONE_B_MULTIPLIER, "ZoneC" => ZONE_C_MULTIPLIER, _ => ZONE_A_MULTIPLIER }; return BASE_RATE * multiplier; } } } ================================================ FILE: design-patterns/csharp/strategy/FlatRateShipping.cs ================================================ namespace Strategy { public class FlatRateShipping : IShippingStrategy { private const double FLAT_RATE = 10.0; public double CalculateCost(Order order) { return FLAT_RATE; } } } ================================================ FILE: design-patterns/csharp/strategy/IShippingStrategy.cs ================================================ namespace Strategy { public interface IShippingStrategy { double CalculateCost(Order order); } } ================================================ FILE: design-patterns/csharp/strategy/Order.cs ================================================ namespace Strategy { public class Order { public double GetTotalWeight() => 5.0; // kg public string GetDestinationZone() => "ZoneA"; public double GetOrderValue() => 150.0; // ... other order details } } ================================================ FILE: design-patterns/csharp/strategy/Program.cs ================================================ using System; namespace Strategy { class Program { static void Main(string[] args) { var order = new Order(); // Using different shipping strategies var flatRateService = new ShippingCostService(new FlatRateShipping()); var weightBasedService = new ShippingCostService(new WeightBasedShipping()); var distanceBasedService = new ShippingCostService(new DistanceBasedShipping()); var thirdPartyService = new ShippingCostService(new ThirdPartyApiShipping()); Console.WriteLine("Shipping costs using different strategies:"); Console.WriteLine($"Flat Rate Shipping: ${flatRateService.CalculateShippingCost(order):F2}"); Console.WriteLine($"Weight Based Shipping: ${weightBasedService.CalculateShippingCost(order):F2}"); Console.WriteLine($"Distance Based Shipping: ${distanceBasedService.CalculateShippingCost(order):F2}"); Console.WriteLine($"Third Party API Shipping: ${thirdPartyService.CalculateShippingCost(order):F2}"); } } } ================================================ FILE: design-patterns/csharp/strategy/ShippingCostService.cs ================================================ namespace Strategy { public class ShippingCostService { private readonly IShippingStrategy shippingStrategy; public ShippingCostService(IShippingStrategy shippingStrategy) { this.shippingStrategy = shippingStrategy; } public double CalculateShippingCost(Order order) { return shippingStrategy.CalculateCost(order); } } } ================================================ FILE: design-patterns/csharp/strategy/ThirdPartyApiShipping.cs ================================================ namespace Strategy { public class ThirdPartyApiShipping : IShippingStrategy { public double CalculateCost(Order order) { // Simulate API call to third-party shipping service double baseRate = 15.0; double weightFactor = order.GetTotalWeight() * 1.5; double distanceFactor = order.GetDestinationZone() == "ZoneC" ? 2.0 : 1.0; return baseRate + weightFactor * distanceFactor; } } } ================================================ FILE: design-patterns/csharp/strategy/WeightBasedShipping.cs ================================================ namespace Strategy { public class WeightBasedShipping : IShippingStrategy { private const double RATE_PER_KG = 2.0; public double CalculateCost(Order order) { return order.GetTotalWeight() * RATE_PER_KG; } } } ================================================ FILE: design-patterns/csharp/templatemethod/AbstractReportExporter.cs ================================================ using System; namespace TemplateMethod { public abstract class AbstractReportExporter { public void ExportReport(ReportData data, string filePath) { PrepareData(data); OpenFile(filePath); WriteHeader(data); WriteDataRows(data); WriteFooter(data); CloseFile(filePath); Console.WriteLine($"Report exported to {filePath}"); } // Hook method – optional for subclasses to override protected virtual void PrepareData(ReportData data) { Console.WriteLine("Preparing report data..."); } // Hook method – optional for subclasses to override protected virtual void OpenFile(string filePath) { Console.WriteLine($"Opening file: {filePath}"); } protected abstract void WriteHeader(ReportData data); protected abstract void WriteDataRows(ReportData data); // Hook method – optional for subclasses to override protected virtual void WriteFooter(ReportData data) { Console.WriteLine("Writing footer..."); } // Hook method – optional for subclasses to override protected virtual void CloseFile(string filePath) { Console.WriteLine($"Closing file: {filePath}"); } } } ================================================ FILE: design-patterns/csharp/templatemethod/CsvReportExporter.cs ================================================ using System; using System.Linq; namespace TemplateMethod { public class CsvReportExporter : AbstractReportExporter { protected override void WriteHeader(ReportData data) { var headers = data.GetHeaders(); Console.WriteLine(string.Join(",", headers)); } protected override void WriteDataRows(ReportData data) { foreach (var row in data.GetRows()) { var values = data.GetHeaders() .Select(header => row[header].ToString()) .ToList(); Console.WriteLine(string.Join(",", values)); } } } } ================================================ FILE: design-patterns/csharp/templatemethod/ExcelReportExporter.cs ================================================ using System; namespace TemplateMethod { public class ExcelReportExporter : AbstractReportExporter { protected override void WriteHeader(ReportData data) { Console.WriteLine("Excel Header:"); foreach (var header in data.GetHeaders()) { Console.WriteLine($"\t{header}"); } } protected override void WriteDataRows(ReportData data) { Console.WriteLine("Excel Data:"); foreach (var row in data.GetRows()) { Console.WriteLine("\tRow:"); foreach (var header in data.GetHeaders()) { Console.WriteLine($"\t\t{header}: {row[header]}"); } } } } } ================================================ FILE: design-patterns/csharp/templatemethod/PdfReportExporter.cs ================================================ using System; namespace TemplateMethod { public class PdfReportExporter : AbstractReportExporter { protected override void WriteHeader(ReportData data) { Console.WriteLine("PDF Header:"); Console.WriteLine("----------------------------------------"); foreach (var header in data.GetHeaders()) { Console.Write($"{header,-15}"); } Console.WriteLine("\n----------------------------------------"); } protected override void WriteDataRows(ReportData data) { Console.WriteLine("PDF Data:"); foreach (var row in data.GetRows()) { foreach (var header in data.GetHeaders()) { Console.Write($"{row[header],-15}"); } Console.WriteLine(); } Console.WriteLine("----------------------------------------"); } } } ================================================ FILE: design-patterns/csharp/templatemethod/Program.cs ================================================ using System; namespace TemplateMethod { class Program { static void Main(string[] args) { var data = new ReportData(); // Export to different formats var csvExporter = new CsvReportExporter(); var excelExporter = new ExcelReportExporter(); var pdfExporter = new PdfReportExporter(); Console.WriteLine("Exporting to CSV:"); csvExporter.ExportReport(data, "report.csv"); Console.WriteLine("\nExporting to Excel:"); excelExporter.ExportReport(data, "report.xlsx"); Console.WriteLine("\nExporting to PDF:"); pdfExporter.ExportReport(data, "report.pdf"); } } } ================================================ FILE: design-patterns/csharp/templatemethod/ReportData.cs ================================================ using System.Collections.Generic; namespace TemplateMethod { public class ReportData { public List GetHeaders() { return new List { "ID", "Name", "Value" }; } public List> GetRows() { return new List> { new Dictionary { { "ID", 1 }, { "Name", "Item A" }, { "Value", 100.0 } }, new Dictionary { { "ID", 2 }, { "Name", "Item B" }, { "Value", 150.5 } }, new Dictionary { { "ID", 3 }, { "Name", "Item C" }, { "Value", 75.25 } } }; } } } ================================================ FILE: design-patterns/golang/adapter/checkout_service.go ================================================ package adapter import "fmt" // CheckoutService handles the checkout process type CheckoutService struct { paymentProcessor PaymentProcessor } // NewCheckoutService creates a new CheckoutService func NewCheckoutService(paymentProcessor PaymentProcessor) *CheckoutService { return &CheckoutService{ paymentProcessor: paymentProcessor, } } // ProcessCheckout processes a checkout with the given amount and currency func (cs *CheckoutService) ProcessCheckout(amount float64, currency string) { cs.paymentProcessor.ProcessPayment(amount, currency) if cs.paymentProcessor.IsPaymentSuccessful() { fmt.Printf("Checkout successful! Transaction ID: %s\n", cs.paymentProcessor.GetTransactionID()) } else { fmt.Println("Checkout failed!") } } ================================================ FILE: design-patterns/golang/adapter/go.mod ================================================ module design-patterns/golang/adapter go 1.21 ================================================ FILE: design-patterns/golang/adapter/in_house_payment_processor.go ================================================ package adapter import ( "fmt" "time" ) // InHousePaymentProcessor represents our in-house payment processing system type InHousePaymentProcessor struct { transactionID string isSuccessful bool } // ProcessPayment implements the PaymentProcessor interface func (p *InHousePaymentProcessor) ProcessPayment(amount float64, currency string) { fmt.Printf("InHousePaymentProcessor: Processing payment of %s %.2f\n", currency, amount) p.transactionID = fmt.Sprintf("INH-%d", time.Now().UnixNano()) p.isSuccessful = true fmt.Printf("InHousePaymentProcessor: Payment processed successfully. Txn ID: %s\n", p.transactionID) } // IsPaymentSuccessful implements the PaymentProcessor interface func (p *InHousePaymentProcessor) IsPaymentSuccessful() bool { return p.isSuccessful } // GetTransactionID implements the PaymentProcessor interface func (p *InHousePaymentProcessor) GetTransactionID() string { return p.transactionID } ================================================ FILE: design-patterns/golang/adapter/legacy_gateway.go ================================================ package adapter import ( "fmt" "time" ) // LegacyGateway represents the legacy payment gateway type LegacyGateway struct { transactionReference int64 isPaymentSuccessful bool } // ExecuteTransaction processes a payment using the legacy gateway func (lg *LegacyGateway) ExecuteTransaction(totalAmount float64, currency string) { fmt.Printf("LegacyGateway: Executing transaction for %s %.2f\n", currency, totalAmount) lg.transactionReference = time.Now().UnixNano() lg.isPaymentSuccessful = true fmt.Printf("LegacyGateway: Transaction executed successfully. Txn ID: %d\n", lg.transactionReference) } // CheckStatus checks the status of a transaction func (lg *LegacyGateway) CheckStatus(transactionReference int64) bool { fmt.Printf("LegacyGateway: Checking status for ref: %d\n", transactionReference) return lg.isPaymentSuccessful } // GetReferenceNumber returns the transaction reference number func (lg *LegacyGateway) GetReferenceNumber() int64 { return lg.transactionReference } ================================================ FILE: design-patterns/golang/adapter/legacy_gateway_adapter.go ================================================ package adapter import "fmt" // LegacyGatewayAdapter adapts the LegacyGateway to the PaymentProcessor interface type LegacyGatewayAdapter struct { legacyGateway *LegacyGateway } // NewLegacyGatewayAdapter creates a new LegacyGatewayAdapter func NewLegacyGatewayAdapter(legacyGateway *LegacyGateway) *LegacyGatewayAdapter { return &LegacyGatewayAdapter{ legacyGateway: legacyGateway, } } // ProcessPayment implements the PaymentProcessor interface func (adapter *LegacyGatewayAdapter) ProcessPayment(amount float64, currency string) { adapter.legacyGateway.ExecuteTransaction(amount, currency) } // IsPaymentSuccessful implements the PaymentProcessor interface func (adapter *LegacyGatewayAdapter) IsPaymentSuccessful() bool { return adapter.legacyGateway.CheckStatus(adapter.legacyGateway.GetReferenceNumber()) } // GetTransactionID implements the PaymentProcessor interface func (adapter *LegacyGatewayAdapter) GetTransactionID() string { return fmt.Sprintf("LEG-%d", adapter.legacyGateway.GetReferenceNumber()) } ================================================ FILE: design-patterns/golang/adapter/main.go ================================================ package main import ( "design-patterns/golang/adapter" "fmt" ) func main() { // Using the in-house payment processor fmt.Println("Using In-House Payment Processor:") inHouseProcessor := &adapter.InHousePaymentProcessor{} checkoutService := adapter.NewCheckoutService(inHouseProcessor) checkoutService.ProcessCheckout(100.0, "USD") fmt.Println("\nUsing Legacy Gateway (via Adapter):") // Using the legacy gateway through the adapter legacyGateway := &adapter.LegacyGateway{} legacyAdapter := adapter.NewLegacyGatewayAdapter(legacyGateway) checkoutService = adapter.NewCheckoutService(legacyAdapter) checkoutService.ProcessCheckout(150.0, "EUR") } ================================================ FILE: design-patterns/golang/adapter/payment_processor.go ================================================ package adapter // PaymentProcessor defines the interface for processing payments type PaymentProcessor interface { ProcessPayment(amount float64, currency string) IsPaymentSuccessful() bool GetTransactionID() string } ================================================ FILE: design-patterns/golang/bridge/circle.go ================================================ package bridge // Circle represents a circle shape type Circle struct { *BaseShape radius float64 } // NewCircle creates a new Circle func NewCircle(renderer Renderer, radius float64) *Circle { return &Circle{ BaseShape: NewBaseShape(renderer), radius: radius, } } // Draw implements the Shape interface func (c *Circle) Draw() { c.renderer.RenderCircle(c.radius) } ================================================ FILE: design-patterns/golang/bridge/go.mod ================================================ module design-patterns/golang/bridge go 1.21 ================================================ FILE: design-patterns/golang/bridge/main.go ================================================ package main import ( "design-patterns/golang/bridge" "fmt" ) func main() { // Create renderers vectorRenderer := bridge.NewVectorRenderer() rasterRenderer := bridge.NewRasterRenderer() // Create shapes with vector renderer circle := bridge.NewCircle(vectorRenderer, 5.0) rectangle := bridge.NewRectangle(vectorRenderer, 10.0, 5.0) fmt.Println("Drawing shapes with vector renderer:") circle.Draw() rectangle.Draw() // Create shapes with raster renderer circle = bridge.NewCircle(rasterRenderer, 5.0) rectangle = bridge.NewRectangle(rasterRenderer, 10.0, 5.0) fmt.Println("\nDrawing shapes with raster renderer:") circle.Draw() rectangle.Draw() } ================================================ FILE: design-patterns/golang/bridge/raster_renderer.go ================================================ package bridge import "fmt" // RasterRenderer renders shapes as raster graphics type RasterRenderer struct{} // NewRasterRenderer creates a new RasterRenderer func NewRasterRenderer() *RasterRenderer { return &RasterRenderer{} } // RenderCircle implements the Renderer interface func (r *RasterRenderer) RenderCircle(radius float64) { fmt.Printf("Drawing a circle of radius %.2f using raster graphics\n", radius) } // RenderRectangle implements the Renderer interface func (r *RasterRenderer) RenderRectangle(width, height float64) { fmt.Printf("Drawing a rectangle of width %.2f and height %.2f using raster graphics\n", width, height) } ================================================ FILE: design-patterns/golang/bridge/rectangle.go ================================================ package bridge // Rectangle represents a rectangle shape type Rectangle struct { *BaseShape width float64 height float64 } // NewRectangle creates a new Rectangle func NewRectangle(renderer Renderer, width, height float64) *Rectangle { return &Rectangle{ BaseShape: NewBaseShape(renderer), width: width, height: height, } } // Draw implements the Shape interface func (r *Rectangle) Draw() { r.renderer.RenderRectangle(r.width, r.height) } ================================================ FILE: design-patterns/golang/bridge/renderer.go ================================================ package bridge // Renderer defines the interface for rendering shapes type Renderer interface { RenderCircle(radius float64) RenderRectangle(width, height float64) } ================================================ FILE: design-patterns/golang/bridge/shape.go ================================================ package bridge // Shape defines the interface for shapes type Shape interface { Draw() } // BaseShape provides common functionality for shapes type BaseShape struct { renderer Renderer } // NewBaseShape creates a new BaseShape func NewBaseShape(renderer Renderer) *BaseShape { return &BaseShape{ renderer: renderer, } } ================================================ FILE: design-patterns/golang/bridge/vector_renderer.go ================================================ package bridge import "fmt" // VectorRenderer renders shapes as vector graphics type VectorRenderer struct{} // NewVectorRenderer creates a new VectorRenderer func NewVectorRenderer() *VectorRenderer { return &VectorRenderer{} } // RenderCircle implements the Renderer interface func (v *VectorRenderer) RenderCircle(radius float64) { fmt.Printf("Drawing a circle of radius %.2f using vector graphics\n", radius) } // RenderRectangle implements the Renderer interface func (v *VectorRenderer) RenderRectangle(width, height float64) { fmt.Printf("Drawing a rectangle of width %.2f and height %.2f using vector graphics\n", width, height) } ================================================ FILE: design-patterns/golang/builder/go.mod ================================================ module design-patterns/golang/builder go 1.21 ================================================ FILE: design-patterns/golang/builder/http_request.go ================================================ package builder import ( "fmt" ) // HttpRequest represents an HTTP request with all its components type HttpRequest struct { url string // Required method string // Optional, default GET headers map[string]string // Optional queryParams map[string]string // Optional body string // Optional timeout int // Optional, default 30s } // NewHttpRequest creates a new HttpRequest using the builder pattern func NewHttpRequest(builder *HttpRequestBuilder) *HttpRequest { return &HttpRequest{ url: builder.url, method: builder.method, headers: builder.headers, queryParams: builder.queryParams, body: builder.body, timeout: builder.timeout, } } // GetURL returns the request URL func (r *HttpRequest) GetURL() string { return r.url } // GetMethod returns the request method func (r *HttpRequest) GetMethod() string { return r.method } // GetHeaders returns the request headers func (r *HttpRequest) GetHeaders() map[string]string { return r.headers } // GetQueryParams returns the request query parameters func (r *HttpRequest) GetQueryParams() map[string]string { return r.queryParams } // GetBody returns the request body func (r *HttpRequest) GetBody() string { return r.body } // GetTimeout returns the request timeout func (r *HttpRequest) GetTimeout() int { return r.timeout } // String returns a string representation of the HttpRequest func (r *HttpRequest) String() string { bodyPreview := r.body if len(bodyPreview) > 10 { bodyPreview = bodyPreview[:10] + "..." } return fmt.Sprintf("HttpRequest{url='%s', method='%s', headers=%v, queryParams=%v, body='%s', timeout=%d}", r.url, r.method, r.headers, r.queryParams, bodyPreview, r.timeout) } ================================================ FILE: design-patterns/golang/builder/http_request_builder.go ================================================ package builder import ( "fmt" "strings" ) // HttpRequestBuilder is responsible for building HttpRequest objects type HttpRequestBuilder struct { url string // Required method string // Optional, default GET headers map[string]string // Optional queryParams map[string]string // Optional body string // Optional timeout int // Optional, default 30s } // NewHttpRequestBuilder creates a new HttpRequestBuilder with the required URL func NewHttpRequestBuilder(url string) (*HttpRequestBuilder, error) { if strings.TrimSpace(url) == "" { return nil, fmt.Errorf("URL cannot be null or empty") } return &HttpRequestBuilder{ url: url, method: "GET", headers: make(map[string]string), queryParams: make(map[string]string), timeout: 30000, // 30 seconds default }, nil } // Method sets the HTTP method func (b *HttpRequestBuilder) Method(method string) *HttpRequestBuilder { if strings.TrimSpace(method) == "" { b.method = "GET" } else { b.method = strings.ToUpper(method) } return b } // Header adds a header to the request func (b *HttpRequestBuilder) Header(key, value string) *HttpRequestBuilder { if key != "" && value != "" { b.headers[key] = value } return b } // QueryParam adds a query parameter to the request func (b *HttpRequestBuilder) QueryParam(key, value string) *HttpRequestBuilder { if key != "" && value != "" { b.queryParams[key] = value } return b } // Body sets the request body func (b *HttpRequestBuilder) Body(body string) *HttpRequestBuilder { b.body = body return b } // Timeout sets the request timeout in milliseconds func (b *HttpRequestBuilder) Timeout(timeoutMillis int) *HttpRequestBuilder { if timeoutMillis > 0 { b.timeout = timeoutMillis } return b } // Build creates and returns a new HttpRequest func (b *HttpRequestBuilder) Build() *HttpRequest { // Validate the request if (b.method == "POST" || b.method == "PUT") && b.body == "" { fmt.Printf("Warning: Building %s request without a body for URL: %s\n", b.method, b.url) } return NewHttpRequest(b) } ================================================ FILE: design-patterns/golang/builder/main.go ================================================ package main import ( "design-patterns/golang/builder" "fmt" ) func main() { // Create a GET request getRequest, err := builder.NewHttpRequestBuilder("https://api.example.com/users") if err != nil { fmt.Printf("Error creating request: %v\n", err) return } getRequest. Method("GET"). Header("Accept", "application/json"). QueryParam("page", "1"). QueryParam("limit", "10"). Timeout(5000) request := getRequest.Build() fmt.Println("GET Request:", request) // Create a POST request postRequest, err := builder.NewHttpRequestBuilder("https://api.example.com/users") if err != nil { fmt.Printf("Error creating request: %v\n", err) return } postRequest. Method("POST"). Header("Content-Type", "application/json"). Header("Authorization", "Bearer token123"). Body(`{"name": "John Doe", "email": "john@example.com"}`). Timeout(10000) request = postRequest.Build() fmt.Println("\nPOST Request:", request) } ================================================ FILE: design-patterns/golang/chainofresponsibility/authentication_handler.go ================================================ package chainofresponsibility import "fmt" // AuthenticationHandler handles authentication requests type AuthenticationHandler struct { BaseHandler } // Handle processes authentication requests func (h *AuthenticationHandler) Handle(request *Request) { if request.Type == "auth" { fmt.Printf("AuthenticationHandler: Processing authentication request for user %s\n", request.Data) // Simulate authentication logic if request.Data == "valid_user" { fmt.Println("AuthenticationHandler: Authentication successful") } else { fmt.Println("AuthenticationHandler: Authentication failed") } } else { h.HandleNext(request) } } ================================================ FILE: design-patterns/golang/chainofresponsibility/authorization_handler.go ================================================ ================================================ FILE: design-patterns/golang/chainofresponsibility/base_handler.go ================================================ package chainofresponsibility // BaseHandler provides common functionality for request handlers type BaseHandler struct { next RequestHandler } // SetNext sets the next handler in the chain func (h *BaseHandler) SetNext(handler RequestHandler) { h.next = handler } // HandleNext passes the request to the next handler if one exists func (h *BaseHandler) HandleNext(request *Request) { if h.next != nil { h.next.Handle(request) } } ================================================ FILE: design-patterns/golang/chainofresponsibility/go.mod ================================================ module chainofresponsibility go 1.21 ================================================ FILE: design-patterns/golang/chainofresponsibility/main.go ================================================ package chainofresponsibility import ( "fmt" ) func main() { // Create handlers auth := &AuthenticationHandler{} authz := &AuthorizationHandler{} validate := &ValidationHandler{} // Set up the chain auth.SetNext(authz) authz.SetNext(validate) // Create requests authRequest := &Request{ Type: "auth", Data: "valid_user", } authzRequest := &Request{ Type: "authz", Data: "admin_resource", } validateRequest := &Request{ Type: "validate", Data: "test_data", } invalidRequest := &Request{ Type: "unknown", Data: "invalid_data", } // Process requests fmt.Println("Processing authentication request:") auth.Handle(authRequest) fmt.Println("\nProcessing authorization request:") auth.Handle(authzRequest) fmt.Println("\nProcessing validation request:") auth.Handle(validateRequest) fmt.Println("\nProcessing invalid request:") auth.Handle(invalidRequest) } ================================================ FILE: design-patterns/golang/chainofresponsibility/request.go ================================================ package chainofresponsibility // Request represents a request in the chain type Request struct { Type string Data string } // NewRequest creates a new Request func NewRequest(user, role string, requestCount int, payload string) *Request { return &Request{ User: user, UserRole: role, RequestCount: requestCount, Payload: payload, } } ================================================ FILE: design-patterns/golang/chainofresponsibility/request_handler.go ================================================ package chainofresponsibility // RequestHandler defines the interface for request handlers in the chain type RequestHandler interface { SetNext(handler RequestHandler) Handle(request *Request) } ================================================ FILE: design-patterns/golang/chainofresponsibility/validation_handler.go ================================================ package chainofresponsibility import "fmt" // ValidationHandler handles validation requests type ValidationHandler struct { BaseHandler } // Handle processes validation requests func (h *ValidationHandler) Handle(request *Request) { if request.Type == "validate" { fmt.Printf("ValidationHandler: Processing validation request for data %s\n", request.Data) // Simulate validation logic if len(request.Data) > 0 { fmt.Println("ValidationHandler: Validation successful") } else { fmt.Println("ValidationHandler: Validation failed") } } else { h.HandleNext(request) } } ================================================ FILE: design-patterns/golang/composite/file.go ================================================ package composite import "fmt" // File represents a file in the file system type File struct { name string size int64 } // NewFile creates a new File instance func NewFile(name string, size int64) *File { return &File{ name: name, size: size, } } // GetName returns the name of the file func (f *File) GetName() string { return f.name } // GetSize returns the size of the file func (f *File) GetSize() int64 { return f.size } // Print prints the file information with the given indentation func (f *File) Print(indent string) { fmt.Printf("%sFile: %s (%d bytes)\n", indent, f.name, f.size) } // Delete deletes the file func (f *File) Delete() { fmt.Printf("Deleting file: %s\n", f.name) } ================================================ FILE: design-patterns/golang/composite/file_system_item.go ================================================ package composite // FileSystemItem defines the interface for both files and folders type FileSystemItem interface { GetName() string GetSize() int64 Print(indent string) Delete() } ================================================ FILE: design-patterns/golang/composite/folder.go ================================================ package composite import "fmt" // Folder represents a folder in the file system type Folder struct { name string children []FileSystemItem } // NewFolder creates a new Folder instance func NewFolder(name string) *Folder { return &Folder{ name: name, children: make([]FileSystemItem, 0), } } // GetName returns the name of the folder func (f *Folder) GetName() string { return f.name } // GetSize returns the total size of the folder and its contents func (f *Folder) GetSize() int64 { var totalSize int64 for _, item := range f.children { totalSize += item.GetSize() } return totalSize } // Add adds a new item to the folder func (f *Folder) Add(item FileSystemItem) { f.children = append(f.children, item) } // Remove removes an item from the folder func (f *Folder) Remove(item FileSystemItem) { for i, child := range f.children { if child.GetName() == item.GetName() { f.children = append(f.children[:i], f.children[i+1:]...) break } } } // Print prints the folder structure with the given indentation func (f *Folder) Print(indent string) { fmt.Printf("%sFolder: %s\n", indent, f.name) for _, item := range f.children { item.Print(indent + " ") } } // Delete deletes the folder and its contents func (f *Folder) Delete() { fmt.Printf("Deleting folder: %s\n", f.name) for _, item := range f.children { item.Delete() } } ================================================ FILE: design-patterns/golang/composite/go.mod ================================================ module composite go 1.21 ================================================ FILE: design-patterns/golang/composite/main.go ================================================ package composite import "fmt" func main() { // Create root folder root := NewFolder("Root") // Create subfolders documents := NewFolder("Documents") downloads := NewFolder("Downloads") pictures := NewFolder("Pictures") // Create files report := NewFile("report.txt", 1024) image := NewFile("image.jpg", 2048) video := NewFile("video.mp4", 4096) // Build the structure root.Add(documents) root.Add(downloads) root.Add(pictures) documents.Add(report) downloads.Add(video) pictures.Add(image) // Print the structure fmt.Println("File System Structure:") root.Print("") // Print total size fmt.Printf("\nTotal size: %d bytes\n", root.GetSize()) // Delete a folder fmt.Println("\nDeleting Documents folder:") root.Remove(documents) documents.Delete() // Print the structure again fmt.Println("\nUpdated File System Structure:") root.Print("") } ================================================ FILE: design-patterns/golang/decorator/beverage.go ================================================ package decorator // Beverage defines the interface for all beverages type Beverage interface { GetDescription() string Cost() float64 } ================================================ FILE: design-patterns/golang/decorator/beverage_decorator.go ================================================ package decorator // BeverageDecorator is the base decorator that wraps a Beverage type BeverageDecorator struct { beverage Beverage } // NewBeverageDecorator creates a new BeverageDecorator func NewBeverageDecorator(beverage Beverage) *BeverageDecorator { return &BeverageDecorator{ beverage: beverage, } } // GetDescription returns the description of the decorated beverage func (d *BeverageDecorator) GetDescription() string { return d.beverage.GetDescription() } // Cost returns the cost of the decorated beverage func (d *BeverageDecorator) Cost() float64 { return d.beverage.Cost() } ================================================ FILE: design-patterns/golang/decorator/go.mod ================================================ ================================================ FILE: design-patterns/golang/decorator/main.go ================================================ ================================================ FILE: design-patterns/golang/decorator/milk_decorator.go ================================================ package decorator // MilkDecorator adds milk to a beverage type MilkDecorator struct { *BeverageDecorator } // NewMilkDecorator creates a new MilkDecorator func NewMilkDecorator(beverage Beverage) *MilkDecorator { return &MilkDecorator{ BeverageDecorator: NewBeverageDecorator(beverage), } } // GetDescription returns the description of the beverage with milk func (d *MilkDecorator) GetDescription() string { return d.beverage.GetDescription() + " with Milk" } // Cost returns the cost of the beverage with milk func (d *MilkDecorator) Cost() float64 { return d.beverage.Cost() + 0.5 } ================================================ FILE: design-patterns/golang/decorator/simple_coffee.go ================================================ package decorator // SimpleCoffee represents a basic coffee without any additions type SimpleCoffee struct{} // NewSimpleCoffee creates a new SimpleCoffee instance func NewSimpleCoffee() *SimpleCoffee { return &SimpleCoffee{} } // GetDescription returns the description of the coffee func (c *SimpleCoffee) GetDescription() string { return "Simple Coffee" } // Cost returns the cost of the coffee func (c *SimpleCoffee) Cost() float64 { return 1.0 } ================================================ FILE: design-patterns/golang/decorator/sugar_decorator.go ================================================ ================================================ FILE: design-patterns/golang/facade/build_system.go ================================================ package facade import ( "fmt" ) // BuildSystem handles project compilation type BuildSystem struct{} // NewBuildSystem creates a new BuildSystem instance func NewBuildSystem() *BuildSystem { return &BuildSystem{} } // CompileProject compiles the project func (b *BuildSystem) CompileProject() bool { fmt.Println("Build: Compiling project...") simulateDelay() fmt.Println("Build: Compilation complete.") return true } // GetArtifactPath returns the path to the compiled artifact func (b *BuildSystem) GetArtifactPath() string { return "/path/to/artifact" } ================================================ FILE: design-patterns/golang/facade/deployment_facade.go ================================================ package facade import "fmt" // DeploymentFacade provides a simplified interface to the deployment system type DeploymentFacade struct { vcs *VersionControlSystem buildSystem *BuildSystem testingFramework *TestingFramework deploymentTarget *DeploymentTarget } // NewDeploymentFacade creates a new DeploymentFacade instance func NewDeploymentFacade() *DeploymentFacade { return &DeploymentFacade{ vcs: NewVersionControlSystem(), buildSystem: NewBuildSystem(), testingFramework: NewTestingFramework(), deploymentTarget: NewDeploymentTarget(), } } // DeployApplication performs a full standard deployment func (f *DeploymentFacade) DeployApplication(branch, serverAddress string) bool { fmt.Printf("\nFACADE: --- Initiating FULL DEPLOYMENT for branch: %s to %s ---\n", branch, serverAddress) success := true // Step 1: Pull latest code f.vcs.PullLatestChanges(branch) // Step 2: Build the project if !f.buildSystem.CompileProject() { fmt.Println("FACADE: DEPLOYMENT FAILED - Build compilation failed.") return false } artifactPath := f.buildSystem.GetArtifactPath() // Step 3: Run tests if !f.testingFramework.RunUnitTests() { fmt.Println("FACADE: DEPLOYMENT FAILED - Unit tests failed.") return false } if !f.testingFramework.RunIntegrationTests() { fmt.Println("FACADE: DEPLOYMENT FAILED - Integration tests failed.") return false } // Step 4: Deploy to production f.deploymentTarget.TransferArtifact(artifactPath, serverAddress) f.deploymentTarget.ActivateNewVersion(serverAddress) fmt.Printf("FACADE: APPLICATION DEPLOYED SUCCESSFULLY TO %s!\n", serverAddress) return success } // DeployHotfix performs a hotfix deployment func (f *DeploymentFacade) DeployHotfix(branch, serverAddress string) bool { fmt.Printf("\nFACADE: --- Initiating HOTFIX DEPLOYMENT for branch: %s to %s ---\n", branch, serverAddress) success := true // Step 1: Pull latest code f.vcs.PullLatestChanges(branch) // Step 2: Build the project if !f.buildSystem.CompileProject() { fmt.Println("FACADE: HOTFIX FAILED - Build compilation failed.") return false } artifactPath := f.buildSystem.GetArtifactPath() // Step 3: Skip extensive tests for hotfix fmt.Println("FACADE: Skipping full test suite for hotfix deployment (or running minimal smoke tests).") // Step 4: Deploy to production f.deploymentTarget.TransferArtifact(artifactPath, serverAddress) f.deploymentTarget.ActivateNewVersion(serverAddress) fmt.Printf("FACADE: HOTFIX DEPLOYED SUCCESSFULLY TO %s!\n", serverAddress) return success } ================================================ FILE: design-patterns/golang/facade/deployment_target.go ================================================ package facade import ( "fmt" ) // DeploymentTarget handles artifact deployment type DeploymentTarget struct{} // NewDeploymentTarget creates a new DeploymentTarget instance func NewDeploymentTarget() *DeploymentTarget { return &DeploymentTarget{} } // TransferArtifact transfers the artifact to the target server func (d *DeploymentTarget) TransferArtifact(artifactPath, serverAddress string) { fmt.Printf("Deployment: Transferring artifact from %s to %s...\n", artifactPath, serverAddress) simulateDelay() fmt.Println("Deployment: Transfer complete.") } // ActivateNewVersion activates the new version on the target server func (d *DeploymentTarget) ActivateNewVersion(serverAddress string) { fmt.Printf("Deployment: Activating new version on %s...\n", serverAddress) simulateDelay() fmt.Println("Deployment: Activation complete.") } ================================================ FILE: design-patterns/golang/facade/go.mod ================================================ module facade go 1.21 ================================================ FILE: design-patterns/golang/facade/main.go ================================================ package facade import "fmt" func main() { // Create the deployment facade deploymentFacade := NewDeploymentFacade() // Perform a full deployment fmt.Println("=== Performing Full Deployment ===") success := deploymentFacade.DeployApplication("main", "production-server") if !success { fmt.Println("Full deployment failed!") } // Perform a hotfix deployment fmt.Println("\n=== Performing Hotfix Deployment ===") success = deploymentFacade.DeployHotfix("hotfix-123", "production-server") if !success { fmt.Println("Hotfix deployment failed!") } } ================================================ FILE: design-patterns/golang/facade/testing_framework.go ================================================ ================================================ FILE: design-patterns/golang/facade/version_control_system.go ================================================ ================================================ FILE: design-patterns/golang/factory/email_notification.go ================================================ package factory import "fmt" // EmailNotification represents an email notification type EmailNotification struct{} // NewEmailNotification creates a new EmailNotification instance func NewEmailNotification() *EmailNotification { return &EmailNotification{} } // Send sends an email notification func (e *EmailNotification) Send(message string) { fmt.Printf("Sending email: %s\n", message) } ================================================ FILE: design-patterns/golang/factory/go.mod ================================================ module factory go 1.21 ================================================ FILE: design-patterns/golang/factory/main.go ================================================ package factory import "fmt" func main() { // Create the factory factory := NewSimpleNotificationFactory() // Create and send different types of notifications notifications := []string{"EMAIL", "SMS", "PUSH"} messages := []string{ "Welcome to our platform!", "Your OTP is 123456", "You have a new follower!", } for i, notificationType := range notifications { notification, err := factory.CreateNotification(notificationType) if err != nil { fmt.Printf("Error creating notification: %v\n", err) continue } notification.Send(messages[i]) } } ================================================ FILE: design-patterns/golang/factory/notification.go ================================================ package factory // Notification defines the interface for all notification types type Notification interface { Send(message string) } ================================================ FILE: design-patterns/golang/factory/push_notification.go ================================================ ================================================ FILE: design-patterns/golang/factory/simple_notification_factory.go ================================================ package factory // SimpleNotificationFactory creates different types of notifications type SimpleNotificationFactory struct{} // NewSimpleNotificationFactory creates a new SimpleNotificationFactory instance func NewSimpleNotificationFactory() *SimpleNotificationFactory { return &SimpleNotificationFactory{} } // CreateNotification creates a notification based on the type func (f *SimpleNotificationFactory) CreateNotification(notificationType string) (Notification, error) { switch notificationType { case "EMAIL": return NewEmailNotification(), nil case "SMS": return NewSMSNotification(), nil case "PUSH": return NewPushNotification(), nil default: return nil, fmt.Errorf("unknown notification type: %s", notificationType) } } ================================================ FILE: design-patterns/golang/factory/sms_notification.go ================================================ package factory import "fmt" // SMSNotification represents an SMS notification type SMSNotification struct{} // NewSMSNotification creates a new SMSNotification instance func NewSMSNotification() *SMSNotification { return &SMSNotification{} } // Send sends an SMS notification func (s *SMSNotification) Send(message string) { fmt.Printf("Sending SMS: %s\n", message) } ================================================ FILE: design-patterns/golang/flyweight/character_flyweight.go ================================================ package flyweight // CharacterFlyweight defines the interface for character glyphs type CharacterFlyweight interface { Draw(x, y int) } ================================================ FILE: design-patterns/golang/flyweight/character_flyweight_factory.go ================================================ package flyweight import "fmt" // CharacterFlyweightFactory manages the flyweight objects type CharacterFlyweightFactory struct { flyweightCache map[string]CharacterFlyweight } // NewCharacterFlyweightFactory creates a new CharacterFlyweightFactory instance func NewCharacterFlyweightFactory() *CharacterFlyweightFactory { return &CharacterFlyweightFactory{ flyweightCache: make(map[string]CharacterFlyweight), } } // GetFlyweight returns a flyweight object for the given character properties func (f *CharacterFlyweightFactory) GetFlyweight(symbol rune, fontFamily string, fontSize int, color string) CharacterFlyweight { key := fmt.Sprintf("%c-%d-%s", symbol, fontSize, color) if _, exists := f.flyweightCache[key]; !exists { f.flyweightCache[key] = NewCharacterGlyph(symbol, fontFamily, fontSize, color) } return f.flyweightCache[key] } // GetFlyweightCount returns the number of unique flyweight objects func (f *CharacterFlyweightFactory) GetFlyweightCount() int { return len(f.flyweightCache) } ================================================ FILE: design-patterns/golang/flyweight/character_glyph.go ================================================ package flyweight import "fmt" // CharacterGlyph represents a character with its intrinsic properties type CharacterGlyph struct { symbol rune fontFamily string fontSize int color string } // NewCharacterGlyph creates a new CharacterGlyph instance func NewCharacterGlyph(symbol rune, fontFamily string, fontSize int, color string) *CharacterGlyph { return &CharacterGlyph{ symbol: symbol, fontFamily: fontFamily, fontSize: fontSize, color: color, } } // Draw renders the character at the specified position func (g *CharacterGlyph) Draw(x, y int) { fmt.Printf("Rendering %c at (%d, %d) with font %s, size %d, color %s\n", g.symbol, x, y, g.fontFamily, g.fontSize, g.color) } ================================================ FILE: design-patterns/golang/flyweight/go.mod ================================================ module flyweight go 1.21 ================================================ FILE: design-patterns/golang/flyweight/main.go ================================================ package flyweight import "fmt" func main() { // Create a text editor client editor := NewTextEditorClient() // Render some text with the same properties fmt.Println("Rendering text with same properties:") editor.RenderText("Hello", 0, 0, "Arial", 12, "black") fmt.Printf("Number of unique characters: %d\n\n", editor.GetUniqueCharacterCount()) // Render the same text with different properties fmt.Println("Rendering text with different properties:") editor.RenderText("Hello", 0, 20, "Times New Roman", 14, "blue") fmt.Printf("Number of unique characters: %d\n\n", editor.GetUniqueCharacterCount()) // Render text with mixed properties fmt.Println("Rendering text with mixed properties:") editor.RenderText("World", 0, 40, "Arial", 12, "red") fmt.Printf("Number of unique characters: %d\n", editor.GetUniqueCharacterCount()) } ================================================ FILE: design-patterns/golang/flyweight/text_editor_client.go ================================================ package flyweight // TextEditorClient represents a client that uses the flyweight objects type TextEditorClient struct { factory *CharacterFlyweightFactory } // NewTextEditorClient creates a new TextEditorClient instance func NewTextEditorClient() *TextEditorClient { return &TextEditorClient{ factory: NewCharacterFlyweightFactory(), } } // RenderText renders a text string using flyweight objects func (c *TextEditorClient) RenderText(text string, x, y int, fontFamily string, fontSize int, color string) { for i, char := range text { flyweight := c.factory.GetFlyweight(char, fontFamily, fontSize, color) flyweight.Draw(x+i*fontSize, y) } } // GetUniqueCharacterCount returns the number of unique character flyweights func (c *TextEditorClient) GetUniqueCharacterCount() int { return c.factory.GetFlyweightCount() } ================================================ FILE: design-patterns/golang/iterator/book.go ================================================ package iterator // Book represents a book with title and author type Book struct { Title string Author string } // NewBook creates a new Book instance func NewBook(title, author string) *Book { return &Book{ Title: title, Author: author, } } ================================================ FILE: design-patterns/golang/iterator/book_collection.go ================================================ package iterator // BookCollection represents a collection of books type BookCollection struct { books []*Book } // NewBookCollection creates a new BookCollection instance func NewBookCollection() *BookCollection { return &BookCollection{ books: make([]*Book, 0), } } // AddBook adds a book to the collection func (bc *BookCollection) AddBook(book *Book) { bc.books = append(bc.books, book) } // CreateIterator creates a new iterator for the book collection func (bc *BookCollection) CreateIterator() Iterator { return NewBookIterator(bc) } // BookIterator represents an iterator for the book collection type BookIterator struct { collection *BookCollection index int } // NewBookIterator creates a new BookIterator instance func NewBookIterator(collection *BookCollection) *BookIterator { return &BookIterator{ collection: collection, index: 0, } } // HasNext checks if there are more books to iterate func (bi *BookIterator) HasNext() bool { return bi.index < len(bi.collection.books) } // Next returns the next book in the collection func (bi *BookIterator) Next() interface{} { if bi.HasNext() { book := bi.collection.books[bi.index] bi.index++ return book } return nil } ================================================ FILE: design-patterns/golang/iterator/collection.go ================================================ package iterator // Collection defines the interface for creating an iterator type Collection interface { CreateIterator() Iterator } ================================================ FILE: design-patterns/golang/iterator/go.mod ================================================ module iterator go 1.21 ================================================ FILE: design-patterns/golang/iterator/iterator.go ================================================ package iterator // Iterator defines the interface for traversing a collection type Iterator interface { HasNext() bool Next() interface{} } ================================================ FILE: design-patterns/golang/iterator/main.go ================================================ package iterator import "fmt" func main() { // Create a book collection collection := NewBookCollection() // Add some books to the collection collection.AddBook(NewBook("The Great Gatsby", "F. Scott Fitzgerald")) collection.AddBook(NewBook("To Kill a Mockingbird", "Harper Lee")) collection.AddBook(NewBook("1984", "George Orwell")) // Create an iterator for the collection iterator := collection.CreateIterator() // Iterate through the books fmt.Println("Iterating through the book collection:") for iterator.HasNext() { book := iterator.Next().(*Book) fmt.Printf("Book: %s by %s\n", book.Title, book.Author) } } ================================================ FILE: design-patterns/golang/mediator/chat_mediator.go ================================================ package mediator // ChatMediator is a concrete mediator that manages users type ChatMediator struct { users []Colleague } // NewChatMediator creates a new ChatMediator func NewChatMediator() *ChatMediator { return &ChatMediator{users: make([]Colleague, 0)} } // AddUser adds a user to the chat func (m *ChatMediator) AddUser(user Colleague) { m.users = append(m.users, user) user.SetMediator(m) } // SendMessage sends a message from one user to all others func (m *ChatMediator) SendMessage(message string, sender Colleague) { for _, user := range m.users { if user != sender { user.ReceiveMessage(sender.GetName() + ": " + message) } } } ================================================ FILE: design-patterns/golang/mediator/colleague.go ================================================ package mediator // Colleague defines the interface for participants in the communication type Colleague interface { SetMediator(mediator Mediator) GetName() string ReceiveMessage(message string) } ================================================ FILE: design-patterns/golang/mediator/main.go ================================================ package mediator func main() { mediator := NewChatMediator() alice := NewUser("Alice") bob := NewUser("Bob") carol := NewUser("Carol") mediator.AddUser(alice) mediator.AddUser(bob) mediator.AddUser(carol) alice.SendMessage("Hello, everyone!") bob.SendMessage("Hi Alice!") carol.SendMessage("Hey folks!") } ================================================ FILE: design-patterns/golang/mediator/mediator.go ================================================ package mediator // Mediator defines the interface for communication between colleagues type Mediator interface { SendMessage(message string, colleague Colleague) } ================================================ FILE: design-patterns/golang/mediator/user.go ================================================ package mediator import "fmt" // User represents a concrete colleague type User struct { name string mediator Mediator } // NewUser creates a new User func NewUser(name string) *User { return &User{name: name} } func (u *User) SetMediator(mediator Mediator) { u.mediator = mediator } func (u *User) GetName() string { return u.name } func (u *User) ReceiveMessage(message string) { fmt.Printf("%s received: %s\n", u.name, message) } // SendMessage allows the user to send a message via the mediator func (u *User) SendMessage(message string) { if u.mediator != nil { u.mediator.SendMessage(message, u) } } ================================================ FILE: design-patterns/golang/memento/go.mod ================================================ module memento go 1.21 ================================================ FILE: design-patterns/golang/memento/main.go ================================================ package memento import "fmt" func main() { editor := NewTextEditor() undoManager := NewTextEditorUndoManager() editor.Type("Hello, ") undoManager.Save(editor) editor.Type("world!") undoManager.Save(editor) editor.Type(" This is a test.") fmt.Println("Current content:", editor.GetContent()) undoManager.Undo(editor) fmt.Println("After undo:", editor.GetContent()) undoManager.Undo(editor) fmt.Println("After second undo:", editor.GetContent()) undoManager.Undo(editor) } ================================================ FILE: design-patterns/golang/memento/text_editor.go ================================================ package memento import "fmt" // TextEditor is the originator that can save and restore its state type TextEditor struct { content string } // NewTextEditor creates a new TextEditor func NewTextEditor() *TextEditor { return &TextEditor{} } // Type appends text to the editor func (e *TextEditor) Type(words string) { e.content += words fmt.Printf("Typed: %s\n", words) } // GetContent returns the current content func (e *TextEditor) GetContent() string { return e.content } // Save creates a memento of the current state func (e *TextEditor) Save() *TextEditorMemento { fmt.Printf("Saved state: %s\n", e.content) return NewTextEditorMemento(e.content) } // Restore restores the state from a memento func (e *TextEditor) Restore(memento *TextEditorMemento) { e.content = memento.State fmt.Printf("Restored state: %s\n", e.content) } ================================================ FILE: design-patterns/golang/memento/text_editor_memento.go ================================================ package memento // TextEditorMemento stores the state of the TextEditor type TextEditorMemento struct { State string } // NewTextEditorMemento creates a new memento with the given state func NewTextEditorMemento(state string) *TextEditorMemento { return &TextEditorMemento{State: state} } ================================================ FILE: design-patterns/golang/memento/text_editor_undo_manager.go ================================================ package memento import "fmt" // TextEditorUndoManager manages the undo stack for the TextEditor type TextEditorUndoManager struct { history []*TextEditorMemento } // NewTextEditorUndoManager creates a new undo manager func NewTextEditorUndoManager() *TextEditorUndoManager { return &TextEditorUndoManager{history: make([]*TextEditorMemento, 0)} } // Save saves the current state of the editor func (m *TextEditorUndoManager) Save(editor *TextEditor) { m.history = append(m.history, editor.Save()) } // Undo restores the last saved state func (m *TextEditorUndoManager) Undo(editor *TextEditor) { n := len(m.history) if n == 0 { fmt.Println("Nothing to undo.") return } last := m.history[n-1] m.history = m.history[:n-1] editor.Restore(last) } ================================================ FILE: design-patterns/golang/observer/fitness_data.go ================================================ package observer // FitnessData is the concrete subject that manages observers and fitness data type FitnessData struct { observers []FitnessDataObserver steps int calories int distance float64 } // NewFitnessData creates a new FitnessData instance func NewFitnessData() *FitnessData { return &FitnessData{ observers: make([]FitnessDataObserver, 0), } } func (f *FitnessData) RegisterObserver(observer FitnessDataObserver) { f.observers = append(f.observers, observer) } func (f *FitnessData) RemoveObserver(observer FitnessDataObserver) { for i, obs := range f.observers { if obs == observer { f.observers = append(f.observers[:i], f.observers[i+1:]...) break } } } func (f *FitnessData) NotifyObservers() { for _, observer := range f.observers { observer.Update(f.steps, f.calories, f.distance) } } // SetMeasurements updates the fitness data and notifies observers func (f *FitnessData) SetMeasurements(steps int, calories int, distance float64) { f.steps = steps f.calories = calories f.distance = distance f.NotifyObservers() } ================================================ FILE: design-patterns/golang/observer/fitness_data_observer.go ================================================ package observer // FitnessDataObserver defines the interface for observers type FitnessDataObserver interface { Update(steps int, calories int, distance float64) } ================================================ FILE: design-patterns/golang/observer/fitness_data_subject.go ================================================ package observer // FitnessDataSubject defines the interface for the subject type FitnessDataSubject interface { RegisterObserver(observer FitnessDataObserver) RemoveObserver(observer FitnessDataObserver) NotifyObservers() } ================================================ FILE: design-patterns/golang/observer/go.mod ================================================ module observer go 1.21 ================================================ FILE: design-patterns/golang/observer/goal_notifier.go ================================================ package observer import "fmt" // GoalNotifier notifies when a goal is reached type GoalNotifier struct { goalSteps int } func NewGoalNotifier(goalSteps int) *GoalNotifier { return &GoalNotifier{goalSteps: goalSteps} } func (g *GoalNotifier) Update(steps int, calories int, distance float64) { if steps >= g.goalSteps { fmt.Printf("[GoalNotifier] Congratulations! Goal of %d steps reached!\n", g.goalSteps) } else { fmt.Printf("[GoalNotifier] %d steps to go to reach your goal of %d steps.\n", g.goalSteps-steps, g.goalSteps) } } ================================================ FILE: design-patterns/golang/observer/live_activity_display.go ================================================ package observer import "fmt" // LiveActivityDisplay displays live activity updates type LiveActivityDisplay struct{} func NewLiveActivityDisplay() *LiveActivityDisplay { return &LiveActivityDisplay{} } func (l *LiveActivityDisplay) Update(steps int, calories int, distance float64) { fmt.Printf("[LiveActivityDisplay] Steps: %d, Calories: %d, Distance: %.2f km\n", steps, calories, distance) } ================================================ FILE: design-patterns/golang/observer/main.go ================================================ package observer func main() { fitnessData := NewFitnessData() liveDisplay := NewLiveActivityDisplay() logger := NewProgressLogger() goalNotifier := NewGoalNotifier(10000) fitnessData.RegisterObserver(liveDisplay) fitnessData.RegisterObserver(logger) fitnessData.RegisterObserver(goalNotifier) fitnessData.SetMeasurements(3000, 120, 2.5) fitnessData.SetMeasurements(7000, 250, 5.0) fitnessData.SetMeasurements(10000, 400, 8.0) fitnessData.RemoveObserver(logger) fitnessData.SetMeasurements(12000, 500, 10.0) } ================================================ FILE: design-patterns/golang/observer/progress_logger.go ================================================ package observer import "fmt" // ProgressLogger logs progress updates type ProgressLogger struct{} func NewProgressLogger() *ProgressLogger { return &ProgressLogger{} } func (p *ProgressLogger) Update(steps int, calories int, distance float64) { fmt.Printf("[ProgressLogger] Progress logged: %d steps, %d calories, %.2f km\n", steps, calories, distance) } ================================================ FILE: design-patterns/golang/prototype/enemy.go ================================================ package prototype import "fmt" // Enemy represents a game enemy type Enemy struct { Type string Health int Speed float64 Armored bool Weapon string } // NewEnemy creates a new Enemy instance func NewEnemy(type_ string, health int, speed float64, armored bool, weapon string) *Enemy { return &Enemy{ Type: type_, Health: health, Speed: speed, Armored: armored, Weapon: weapon, } } // Clone creates a copy of the enemy func (e *Enemy) Clone() EnemyPrototype { return NewEnemy(e.Type, e.Health, e.Speed, e.Armored, e.Weapon) } // SetHealth updates the enemy's health func (e *Enemy) SetHealth(health int) { e.Health = health } // PrintStats displays the enemy's statistics func (e *Enemy) PrintStats() { fmt.Printf("%s [Health: %d, Speed: %.1f, Armored: %v, Weapon: %s]\n", e.Type, e.Health, e.Speed, e.Armored, e.Weapon) } ================================================ FILE: design-patterns/golang/prototype/enemy_prototype.go ================================================ package prototype // EnemyPrototype defines the interface for cloneable enemies type EnemyPrototype interface { Clone() EnemyPrototype } ================================================ FILE: design-patterns/golang/prototype/enemy_registry.go ================================================ package prototype // EnemyRegistry manages enemy prototypes type EnemyRegistry struct { prototypes map[string]*Enemy } // NewEnemyRegistry creates a new EnemyRegistry func NewEnemyRegistry() *EnemyRegistry { return &EnemyRegistry{ prototypes: make(map[string]*Enemy), } } // Register adds a prototype to the registry func (r *EnemyRegistry) Register(key string, prototype *Enemy) { r.prototypes[key] = prototype } // Get retrieves and clones a prototype from the registry func (r *EnemyRegistry) Get(key string) *Enemy { if prototype, exists := r.prototypes[key]; exists { return prototype.Clone().(*Enemy) } panic("No prototype registered for: " + key) } ================================================ FILE: design-patterns/golang/prototype/go.mod ================================================ module prototype go 1.21 ================================================ FILE: design-patterns/golang/prototype/main.go ================================================ package prototype func main() { registry := NewEnemyRegistry() // Register prototype enemies registry.Register("flying", NewEnemy("FlyingEnemy", 100, 12.0, false, "Laser")) registry.Register("armored", NewEnemy("ArmoredEnemy", 300, 6.0, true, "Cannon")) // Clone from registry e1 := registry.Get("flying") e2 := registry.Get("flying") e2.SetHealth(80) // this one is damaged e3 := registry.Get("armored") // Print enemy stats e1.PrintStats() e2.PrintStats() e3.PrintStats() } ================================================ FILE: design-patterns/golang/proxy/go.mod ================================================ module proxy go 1.21 ================================================ FILE: design-patterns/golang/proxy/high_resolution_image.go ================================================ package proxy import ( "fmt" "time" ) // HighResolutionImage represents a high-resolution image type HighResolutionImage struct { fileName string imageData []byte // Simulate large data } // NewHighResolutionImage creates a new HighResolutionImage func NewHighResolutionImage(fileName string) *HighResolutionImage { image := &HighResolutionImage{fileName: fileName} image.loadImageFromDisk() // Expensive operation! return image } func (i *HighResolutionImage) loadImageFromDisk() { fmt.Printf("Loading image: %s from disk (Expensive Operation)...\n", i.fileName) // Simulate disk read and memory allocation time.Sleep(2 * time.Second) // Simulate delay i.imageData = make([]byte, 10*1024*1024) // 10MB fmt.Printf("Image %s loaded successfully.\n", i.fileName) } func (i *HighResolutionImage) Display() { fmt.Printf("Displaying image: %s\n", i.fileName) // Actual rendering logic would go here } func (i *HighResolutionImage) GetFileName() string { return i.fileName } ================================================ FILE: design-patterns/golang/proxy/image.go ================================================ package proxy // Image defines the interface for image operations type Image interface { Display() GetFileName() string } ================================================ FILE: design-patterns/golang/proxy/image_proxy.go ================================================ package proxy import "fmt" // ImageProxy represents a proxy for high-resolution images type ImageProxy struct { fileName string realImage *HighResolutionImage // RealSubject } // NewImageProxy creates a new ImageProxy func NewImageProxy(fileName string) *ImageProxy { fmt.Printf("ImageProxy: Created for %s. Real image not loaded yet.\n", fileName) return &ImageProxy{fileName: fileName} } func (p *ImageProxy) GetFileName() string { // Can safely return without loading the image return p.fileName } func (p *ImageProxy) Display() { // Lazy initialization: Load only when Display() is called if p.realImage == nil { fmt.Printf("ImageProxy: Display() requested for %s. Loading high-resolution image...\n", p.fileName) p.realImage = NewHighResolutionImage(p.fileName) } else { fmt.Printf("ImageProxy: Using cached high-resolution image for %s\n", p.fileName) } // Delegate the display call to the real image p.realImage.Display() } ================================================ FILE: design-patterns/golang/proxy/main.go ================================================ package proxy import "fmt" func main() { fmt.Println("Application Started. Initializing image proxies for gallery...") // Create lightweight proxies instead of full image objects image1 := NewImageProxy("photo1.jpg") image2 := NewImageProxy("photo2.png") // Never displayed image3 := NewImageProxy("photo3.gif") fmt.Println("\nGallery initialized. No images actually loaded yet.") fmt.Printf("Image 1 Filename: %s\n", image1.GetFileName()) // Does not trigger image load // User clicks on image1 fmt.Printf("\nUser requests to display %s\n", image1.GetFileName()) image1.Display() // Lazy loading happens here // User clicks on image1 again fmt.Printf("\nUser requests to display %s again.\n", image1.GetFileName()) image1.Display() // Already loaded; no loading delay // User clicks on image3 fmt.Printf("\nUser requests to display %s\n", image3.GetFileName()) image3.Display() // Triggers loading for image3 fmt.Println("\nApplication finished. Note: photo2.png was never loaded.") } ================================================ FILE: design-patterns/golang/singleton/double_checked_singleton.go ================================================ package singleton import "sync" // DoubleCheckedSingleton implements double-checked locking singleton pattern type DoubleCheckedSingleton struct{} var ( doubleCheckedInstance *DoubleCheckedSingleton dcMu sync.Mutex ) // GetDoubleCheckedInstance returns the singleton instance func GetDoubleCheckedInstance() *DoubleCheckedSingleton { if doubleCheckedInstance == nil { dcMu.Lock() defer dcMu.Unlock() if doubleCheckedInstance == nil { doubleCheckedInstance = &DoubleCheckedSingleton{} } } return doubleCheckedInstance } ================================================ FILE: design-patterns/golang/singleton/eager_singleton.go ================================================ package singleton // EagerSingleton implements eager initialization singleton pattern type EagerSingleton struct{} // The single instance, created immediately var instance = &EagerSingleton{} // GetInstance returns the singleton instance func GetInstance() *EagerSingleton { return instance } ================================================ FILE: design-patterns/golang/singleton/go.mod ================================================ module singleton go 1.21 ================================================ FILE: design-patterns/golang/singleton/lazy_singleton.go ================================================ package singleton import "sync" // LazySingleton implements lazy initialization singleton pattern type LazySingleton struct{} var ( instance *LazySingleton once sync.Once ) // GetInstance returns the singleton instance func GetInstance() *LazySingleton { once.Do(func() { instance = &LazySingleton{} }) return instance } ================================================ FILE: design-patterns/golang/singleton/main.go ================================================ ================================================ FILE: design-patterns/golang/singleton/thread_safe_singleton.go ================================================ package singleton import "sync" // ThreadSafeSingleton implements thread-safe singleton pattern type ThreadSafeSingleton struct{} var ( threadSafeInstance *ThreadSafeSingleton mu sync.Mutex ) // GetThreadSafeInstance returns the singleton instance func GetThreadSafeInstance() *ThreadSafeSingleton { mu.Lock() defer mu.Unlock() if threadSafeInstance == nil { threadSafeInstance = &ThreadSafeSingleton{} } return threadSafeInstance } ================================================ FILE: design-patterns/golang/state/go.mod ================================================ module state go 1.21 ================================================ FILE: design-patterns/golang/state/has_money_state.go ================================================ package state import "fmt" // HasMoneyState represents the state after money is inserted type HasMoneyState struct{} func (s *HasMoneyState) SelectItem(context *VendingMachine, item string) { fmt.Println("Transaction in progress. Please wait.") } func (s *HasMoneyState) InsertCoin(context *VendingMachine, amount float64) { fmt.Println("Already received money. Dispensing item...") } func (s *HasMoneyState) DispenseItem(context *VendingMachine) { item := context.GetSelectedItem() amt := context.GetInsertedAmount() fmt.Printf("Dispensing '%s' for $%.2f. Thank you!\n", item, amt) context.Reset() } ================================================ FILE: design-patterns/golang/state/idle_state.go ================================================ package state import "fmt" // IdleState represents the state when the machine is waiting for item selection type IdleState struct{} func (s *IdleState) SelectItem(context *VendingMachine, item string) { fmt.Printf("Item '%s' selected. Please insert coins.\n", item) context.SetSelectedItem(item) context.SetState(&ItemSelectedState{}) } func (s *IdleState) InsertCoin(context *VendingMachine, amount float64) { fmt.Println("Please select an item first.") } func (s *IdleState) DispenseItem(context *VendingMachine) { fmt.Println("Please select an item and insert coins first.") } ================================================ FILE: design-patterns/golang/state/item_selected_state.go ================================================ package state import "fmt" // ItemSelectedState represents the state after an item is selected type ItemSelectedState struct{} func (s *ItemSelectedState) SelectItem(context *VendingMachine, item string) { fmt.Println("Item already selected. Please insert coins.") } func (s *ItemSelectedState) InsertCoin(context *VendingMachine, amount float64) { fmt.Printf("Inserted $%.2f.\n", amount) context.SetInsertedAmount(amount) context.SetState(&HasMoneyState{}) } func (s *ItemSelectedState) DispenseItem(context *VendingMachine) { fmt.Println("Please insert coins before dispensing the item.") } ================================================ FILE: design-patterns/golang/state/machine_state.go ================================================ package state // MachineState defines the interface for vending machine states type MachineState interface { SelectItem(context *VendingMachine, item string) InsertCoin(context *VendingMachine, amount float64) DispenseItem(context *VendingMachine) } ================================================ FILE: design-patterns/golang/state/main.go ================================================ package state func main() { vm := NewVendingMachine() // Try to insert coin before selecting item vm.InsertCoin(1.0) // Select an item vm.SelectItem("Soda") // Insert coin vm.InsertCoin(1.5) // Dispense item vm.DispenseItem() // Try another transaction vm.SelectItem("Chips") vm.InsertCoin(2.0) vm.DispenseItem() } ================================================ FILE: design-patterns/golang/state/vending_machine.go ================================================ package state import "fmt" // VendingMachine is the context that maintains the current state type VendingMachine struct { state MachineState selectedItem string insertedAmt float64 } func NewVendingMachine() *VendingMachine { return &VendingMachine{ state: &IdleState{}, } } func (vm *VendingMachine) SetState(state MachineState) { vm.state = state } func (vm *VendingMachine) SetSelectedItem(item string) { vm.selectedItem = item } func (vm *VendingMachine) SetInsertedAmount(amount float64) { vm.insertedAmt = amount } func (vm *VendingMachine) GetSelectedItem() string { return vm.selectedItem } func (vm *VendingMachine) GetInsertedAmount() float64 { return vm.insertedAmt } func (vm *VendingMachine) SelectItem(item string) { vm.state.SelectItem(vm, item) } func (vm *VendingMachine) InsertCoin(amount float64) { vm.state.InsertCoin(vm, amount) } func (vm *VendingMachine) DispenseItem() { vm.state.DispenseItem(vm) } func (vm *VendingMachine) Reset() { fmt.Println("Resetting vending machine...") vm.selectedItem = "" vm.insertedAmt = 0 vm.state = &IdleState{} } ================================================ FILE: design-patterns/golang/strategy/credit_card_payment.go ================================================ package strategy import "fmt" // CreditCardPayment represents the credit card payment strategy type CreditCardPayment struct { cardNumber string name string cvv string dateOfExp string } // NewCreditCardPayment creates a new credit card payment strategy func NewCreditCardPayment(cardNumber, name, cvv, dateOfExp string) *CreditCardPayment { return &CreditCardPayment{ cardNumber: cardNumber, name: name, cvv: cvv, dateOfExp: dateOfExp, } } // Pay implements the payment strategy for credit card func (c *CreditCardPayment) Pay(amount float64) string { return fmt.Sprintf("%.2f paid with credit/debit card", amount) } ================================================ FILE: design-patterns/golang/strategy/main.go ================================================ package strategy func main() { cart := NewShoppingCart(100.0) // Use credit card payment creditCard := NewCreditCardPayment("1234-5678-9012-3456", "John Doe", "123", "12/25") cart.SetPaymentStrategy(creditCard) cart.Checkout() // Use PayPal payment paypal := NewPayPalPayment("john@example.com") cart.SetPaymentStrategy(paypal) cart.Checkout() } ================================================ FILE: design-patterns/golang/strategy/payment_strategy.go ================================================ package strategy // PaymentStrategy defines the interface for payment strategies type PaymentStrategy interface { Pay(amount float64) string } ================================================ FILE: design-patterns/golang/strategy/paypal_payment.go ================================================ package strategy import "fmt" // PayPalPayment represents the PayPal payment strategy type PayPalPayment struct { email string } // NewPayPalPayment creates a new PayPal payment strategy func NewPayPalPayment(email string) *PayPalPayment { return &PayPalPayment{email: email} } // Pay implements the payment strategy for PayPal func (p *PayPalPayment) Pay(amount float64) string { return fmt.Sprintf("%.2f paid using PayPal", amount) } ================================================ FILE: design-patterns/golang/strategy/shopping_cart.go ================================================ package strategy import "fmt" // ShoppingCart is the context that uses a payment strategy type ShoppingCart struct { amount float64 strategy PaymentStrategy } func NewShoppingCart(amount float64) *ShoppingCart { return &ShoppingCart{amount: amount} } func (c *ShoppingCart) SetPaymentStrategy(strategy PaymentStrategy) { c.strategy = strategy } func (c *ShoppingCart) Checkout() { if c.strategy == nil { fmt.Println("No payment strategy selected.") return } result := c.strategy.Pay(c.amount) fmt.Println(result) } ================================================ FILE: design-patterns/golang/templatemethod/csv_data_processor.go ================================================ package templatemethod import "fmt" type CSVDataProcessor struct{} func (c *CSVDataProcessor) ReadData() { fmt.Println("Reading data from CSV file...") } func (c *CSVDataProcessor) ProcessData() { fmt.Println("Processing CSV data...") } func (c *CSVDataProcessor) SaveData() { fmt.Println("Saving processed data to CSV file...") } ================================================ FILE: design-patterns/golang/templatemethod/data_processor.go ================================================ package templatemethod import "fmt" // DataProcessor defines the interface for steps // and provides the template method Process // (Go doesn't have abstract classes, so we use interface + embedding) type DataProcessor interface { ReadData() ProcessData() SaveData() } type BaseDataProcessor struct { Processor DataProcessor } func (b *BaseDataProcessor) Process() { b.Processor.ReadData() b.Processor.ProcessData() b.Processor.SaveData() fmt.Println("Data processing completed.") } ================================================ FILE: design-patterns/golang/templatemethod/main.go ================================================ package templatemethod func main() { csvProcessor := &CSVDataProcessor{} baseCSV := &BaseDataProcessor{Processor: csvProcessor} baseCSV.Process() xmlProcessor := &XMLDataProcessor{} baseXML := &BaseDataProcessor{Processor: xmlProcessor} baseXML.Process() } ================================================ FILE: design-patterns/golang/templatemethod/xml_data_processor.go ================================================ package templatemethod import "fmt" type XMLDataProcessor struct{} func (x *XMLDataProcessor) ReadData() { fmt.Println("Reading data from XML file...") } func (x *XMLDataProcessor) ProcessData() { fmt.Println("Processing XML data...") } func (x *XMLDataProcessor) SaveData() { fmt.Println("Saving processed data to XML file...") } ================================================ FILE: design-patterns/java/abstractfactory/AppLauncher.java ================================================ public class AppLauncher { public static void main(String[] args) { // Simulate platform detection String os = System.getProperty("os.name").toLowerCase(); GUIFactory factory; if (os.contains("mac")) { factory = new MacOSFactory(); } else { factory = new WindowsFactory(); } Application app = new Application(factory); app.renderUI(); } } ================================================ FILE: design-patterns/java/abstractfactory/Application.java ================================================ public class Application { private final Button button; private final Checkbox checkbox; public Application(GUIFactory factory) { this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); } public void renderUI() { button.paint(); checkbox.paint(); } } ================================================ FILE: design-patterns/java/abstractfactory/Button.java ================================================ public interface Button { void paint(); void onClick(); } ================================================ FILE: design-patterns/java/abstractfactory/Checkbox.java ================================================ public interface Checkbox { void paint(); void onSelect(); } ================================================ FILE: design-patterns/java/abstractfactory/GUIFactory.java ================================================ public interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } ================================================ FILE: design-patterns/java/abstractfactory/MacOSButton.java ================================================ public class MacOSButton implements Button { @Override public void paint() { System.out.println("Painting a macOS-style button."); } @Override public void onClick() { System.out.println("MacOS button clicked."); } } ================================================ FILE: design-patterns/java/abstractfactory/MacOSCheckbox.java ================================================ public class MacOSCheckbox implements Checkbox { @Override public void paint() { System.out.println("Painting a macOS-style checkbox."); } @Override public void onSelect() { System.out.println("MacOS checkbox selected."); } } ================================================ FILE: design-patterns/java/abstractfactory/MacOSFactory.java ================================================ public class MacOSFactory implements GUIFactory { @Override public Button createButton() { return new MacOSButton(); } @Override public Checkbox createCheckbox() { return new MacOSCheckbox(); } } ================================================ FILE: design-patterns/java/abstractfactory/WindowsButton.java ================================================ public class WindowsButton implements Button { @Override public void paint() { System.out.println("Painting a Windows-style button."); } @Override public void onClick() { System.out.println("Windows button clicked."); } } ================================================ FILE: design-patterns/java/abstractfactory/WindowsCheckbox.java ================================================ public class WindowsCheckbox implements Checkbox { @Override public void paint() { System.out.println("Painting a Windows-style checkbox."); } @Override public void onSelect() { System.out.println("Windows checkbox selected."); } } ================================================ FILE: design-patterns/java/abstractfactory/WindowsFactory.java ================================================ public class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public Checkbox createCheckbox() { return new WindowsCheckbox(); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/BumpySole.java ================================================ public class BumpySole implements Sole { @Override public String soleBuild() { return "Bummpy"; } @Override public String soleMaterial() { return "Plastic Rubber"; } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/CasualShoeFactory.java ================================================ public class CasualShoeFactory implements ShoeFactory { @Override public Sole createShoeSole() { return new ThinSole(); } @Override public ShoeLace createShoeLace() { return new TapeShoeLace(); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/FlatSole.java ================================================ public class FlatSole implements Sole { @Override public String soleBuild() { return "Flat"; } @Override public String soleMaterial() { return "Synthetic Rubber"; } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/FormalShoeFactory.java ================================================ public class FormalShoeFactory implements ShoeFactory { @Override public Sole createShoeSole() { return new FlatSole(); } @Override public ShoeLace createShoeLace() { return new RoundShoeLace(); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/RoundShoeLace.java ================================================ public class RoundShoeLace implements ShoeLace { @Override public String shoeLaceBuild() { return "Round"; } @Override public String shoeLaceMaterial() { return "Synthetic Polyster"; } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/Shoe.java ================================================ public class Shoe { private Sole sole; private ShoeLace shoeLace; public Shoe(Sole sole, ShoeLace shoeLace){ this.sole = sole; this.shoeLace = shoeLace; } public void displayBuildShoe() { System.out.println("Sole Type is: "+ this.sole.soleBuild()); System.out.println("Sole Material is: "+ this.sole.soleMaterial()); System.out.println("ShoeLace Type is: "+ this.shoeLace.shoeLaceBuild()); System.out.println("ShoeLace Material is: "+ this.shoeLace.shoeLaceMaterial()); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/ShoeFactory.java ================================================ public interface ShoeFactory { public Sole createShoeSole(); public ShoeLace createShoeLace(); } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/ShoeLace.java ================================================ public interface ShoeLace { public String shoeLaceBuild(); public String shoeLaceMaterial(); } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/ShoeManufacture.java ================================================ public class ShoeManufacture { static ShoeFactory shoeFactory; public static Shoe produceShoe(String shoeType) { if(shoeType == "Formal") { shoeFactory = new FormalShoeFactory(); } if(shoeType == "Sports") { shoeFactory = new SportsShoeFactory(); } if(shoeType == "Casual") { shoeFactory = new CasualShoeFactory(); } return new Shoe(shoeFactory.createShoeSole(), shoeFactory.createShoeLace()); } public static void main(String[] args) { Shoe formalShoe = produceShoe("Formal"); Shoe sportaShoe = produceShoe("Sports"); Shoe casualShoe = produceShoe("Casual"); formalShoe.displayBuildShoe(); sportaShoe.displayBuildShoe(); casualShoe.displayBuildShoe(); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/Sole.java ================================================ public interface Sole { public String soleBuild(); public String soleMaterial(); } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/SportsShoeFactory.java ================================================ public class SportsShoeFactory implements ShoeFactory { @Override public Sole createShoeSole() { return new BumpySole(); } @Override public ShoeLace createShoeLace() { return new RoundShoeLace(); } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/TapeShoeLace.java ================================================ public class TapeShoeLace implements ShoeLace{ @Override public String shoeLaceBuild() { return "Tape Flat"; } @Override public String shoeLaceMaterial() { return "Synthetic Cotton"; } } ================================================ FILE: design-patterns/java/abstractfactory/shoefactory/ThinSole.java ================================================ public class ThinSole implements Sole { @Override public String soleBuild() { return "Thin Plated"; } @Override public String soleMaterial() { return "Rubber"; } } ================================================ FILE: design-patterns/java/adapter/CheckoutService.java ================================================ public class CheckoutService { private PaymentProcessor paymentProcessor; public CheckoutService(PaymentProcessor paymentProcessor) { this.paymentProcessor = paymentProcessor; } public void checkout(double amount, String currency) { System.out.println("CheckoutService: Attempting to process order for $" + amount + " " + currency); paymentProcessor.processPayment(amount, currency); if (paymentProcessor.isPaymentSuccessful()) { System.out.println("CheckoutService: Order successful! Transaction ID: " + paymentProcessor.getTransactionId()); } else { System.out.println("CheckoutService: Order failed. Payment was not successful."); } } } ================================================ FILE: design-patterns/java/adapter/ECommerceAppV1.java ================================================ public class ECommerceAppV1 { public static void main(String[] args) { PaymentProcessor processor = new InHousePaymentProcessor(); CheckoutService checkout = new CheckoutService(processor); checkout.checkout(199.99, "USD"); } } ================================================ FILE: design-patterns/java/adapter/ECommerceAppV2.java ================================================ public class ECommerceAppV2 { public static void main(String[] args) { PaymentProcessor inHouseProcessor = new InHousePaymentProcessor(); PaymentProcessor legacyProcessor = new LegacyGatewayAdapter(new LegacyGateway()); CheckoutService checkoutService = new CheckoutService(inHouseProcessor); checkoutService.checkout(100, "USD"); System.out.println("--------------------------------"); checkoutService = new CheckoutService(legacyProcessor); checkoutService.checkout(100, "USD"); } } ================================================ FILE: design-patterns/java/adapter/InHousePaymentProcessor.java ================================================ public class InHousePaymentProcessor implements PaymentProcessor { private String transactionId; private boolean isPaymentSuccessful; @Override public void processPayment(double amount, String currency) { System.out.println("InHousePaymentProcessor: Processing payment of " + amount + " " + currency); // Process payment logic transactionId = "TXN_" + System.currentTimeMillis(); isPaymentSuccessful = true; System.out.println("InHousePaymentProcessor: Payment successful. Txn ID: " + this.transactionId); } @Override public boolean isPaymentSuccessful() { return isPaymentSuccessful; } @Override public String getTransactionId() { return transactionId; } } ================================================ FILE: design-patterns/java/adapter/LegacyGateway.java ================================================ public class LegacyGateway { private long transactionReference; private boolean isPaymentSuccessful; public void executeTransaction(double totalAmount, String currency) { System.out.println("LegacyGateway: Executing transaction for " + currency + " " + totalAmount); transactionReference = System.nanoTime(); isPaymentSuccessful = true; System.out.println("LegacyGateway: Transaction executed successfully. Txn ID: " + transactionReference); } public boolean checkStatus(long transactionReference) { System.out.println("LegacyGateway: Checking status for ref: " + transactionReference); return isPaymentSuccessful; } public long getReferenceNumber() { return transactionReference; } } ================================================ FILE: design-patterns/java/adapter/LegacyGatewayAdapter.java ================================================ public class LegacyGatewayAdapter implements PaymentProcessor { private LegacyGateway legacyGateway; public LegacyGatewayAdapter(LegacyGateway legacyGateway) { this.legacyGateway = legacyGateway; } @Override public void processPayment(double amount, String currency) { System.out.println("LegacyGatewayAdapter: Processing payment of " + amount + " " + currency); legacyGateway.executeTransaction(amount, currency); System.out.println("LegacyGatewayAdapter: Payment processed successfully. Txn ID: " + legacyGateway.getReferenceNumber()); } @Override public boolean isPaymentSuccessful() { return legacyGateway.checkStatus(legacyGateway.getReferenceNumber()); } @Override public String getTransactionId() { return String.valueOf(legacyGateway.getReferenceNumber()); } } ================================================ FILE: design-patterns/java/adapter/PaymentProcessor.java ================================================ public interface PaymentProcessor { void processPayment(double amount, String currency); boolean isPaymentSuccessful(); String getTransactionId(); } ================================================ FILE: design-patterns/java/bridge/BridgeDemo.java ================================================ public class BridgeDemo { public static void main(String[] args) { Renderer vector = new VectorRenderer(); Renderer raster = new RasterRenderer(); Shape circle1 = new Circle(vector, 5); Shape circle2 = new Circle(raster, 5); Shape rectangle1 = new Rectangle(vector, 10, 4); Shape rectangle2 = new Rectangle(raster, 10, 4); circle1.draw(); // Vector circle2.draw(); // Raster rectangle1.draw(); // Vector rectangle2.draw(); // Raster } } ================================================ FILE: design-patterns/java/bridge/Circle.java ================================================ public class Circle extends Shape { private final float radius; public Circle(Renderer renderer, float radius) { super(renderer); this.radius = radius; } @Override public void draw() { renderer.renderCircle(radius); } } ================================================ FILE: design-patterns/java/bridge/RasterRenderer.java ================================================ public class RasterRenderer implements Renderer { @Override public void renderCircle(float radius) { System.out.println("Drawing pixels for a circle of radius " + radius + " (RASTER)."); } @Override public void renderRectangle(float width, float height) { System.out.println("Drawing pixels for a rectangle " + width + "x" + height + " (RASTER)."); } } ================================================ FILE: design-patterns/java/bridge/Rectangle.java ================================================ public class Rectangle extends Shape { private final float width; private final float height; public Rectangle(Renderer renderer, float width, float height) { super(renderer); this.width = width; this.height = height; } @Override public void draw() { renderer.renderRectangle(width, height); } } ================================================ FILE: design-patterns/java/bridge/Renderer.java ================================================ public interface Renderer { void renderCircle(float radius); void renderRectangle(float width, float height); } ================================================ FILE: design-patterns/java/bridge/Shape.java ================================================ public abstract class Shape { protected Renderer renderer; public Shape(Renderer renderer) { this.renderer = renderer; } public abstract void draw(); } ================================================ FILE: design-patterns/java/bridge/VectorRenderer.java ================================================ public class VectorRenderer implements Renderer { @Override public void renderCircle(float radius) { System.out.println("Drawing a circle of radius " + radius + " using VECTOR rendering."); } @Override public void renderRectangle(float width, float height) { System.out.println("Drawing a rectangle " + width + "x" + height + " using VECTOR rendering."); } } ================================================ FILE: design-patterns/java/builder/HttpAppBuilder.java ================================================ public class HttpAppBuilder { public static void main(String[] args) { // Example 1: Simple GET request HttpRequest getRequest = new HttpRequest.Builder("https://api.example.com/users") .method("GET") .header("Accept", "application/json") .timeout(5000) .build(); System.out.println("GET Request: " + getRequest); // Example 2: POST request with body and custom headers HttpRequest postRequest = new HttpRequest.Builder("https://api.example.com/posts") .method("POST") .header("Content-Type", "application/json") .header("X-Auth-Token", "some_secret_token") .body("{\"title\":\"New Post\",\"content\":\"Hello Builder!\"}") .queryParam("userId", "123") .build(); System.out.println("POST Request: " + postRequest); // Example 3: Request with only required URL (defaults for others) HttpRequest defaultRequest = new HttpRequest.Builder("https://api.example.com/status").build(); System.out.println("Default Request: " + defaultRequest); // Example 4: Illustrating potential warning from builder HttpRequest putNoBodyRequest = new HttpRequest.Builder("https://api.example.com/resource/1") .method("PUT") // .body("updated data") // Body intentionally omitted .build(); System.out.println("PUT Request (no body): " + putNoBodyRequest); // Example of trying to build with invalid required parameter try { HttpRequest invalidRequest = new HttpRequest.Builder(null).build(); } catch (IllegalArgumentException e) { System.err.println("Error creating request: " + e.getMessage()); } } } ================================================ FILE: design-patterns/java/builder/HttpAppTelescoping.java ================================================ public class HttpAppTelescoping { public static void main(String[] args) { HttpRequestTelescoping req1 = new HttpRequestTelescoping("https://api.example.com/data"); // GET, defaults HttpRequestTelescoping req2 = new HttpRequestTelescoping("https://api.example.com/submit", "POST", null, null, "{\"key\":\"value\"}"); // POST with body HttpRequestTelescoping req3 = new HttpRequestTelescoping("https://api.example.com/config", "PUT", Map.of("X-API-Key", "secret"), null, "config_data", 5000); } } ================================================ FILE: design-patterns/java/builder/HttpRequest.java ================================================ import java.util.HashMap; import java.util.Map; import java.util.Collections; public class HttpRequest { private final String url; // Required private final String method; // Optional, default GET private final Map headers; // Optional private final Map queryParams; // Optional private final String body; // Optional private final int timeout; // Optional, default 30s // Private constructor, only accessible by the Builder private HttpRequest(Builder builder) { this.url = builder.url; this.method = builder.method; this.headers = Collections.unmodifiableMap(new HashMap<>(builder.headers)); // Defensive copy this.queryParams = Collections.unmodifiableMap(new HashMap<>(builder.queryParams)); // Defensive copy this.body = builder.body; this.timeout = builder.timeout; } // Getters (no setters to ensure immutability) public String getUrl() { return url; } public String getMethod() { return method; } public Map getHeaders() { return headers; } public Map getQueryParams() { return queryParams; } public String getBody() { return body; } public int getTimeout() { return timeout; } @Override public String toString() { return "HttpRequest{" + "url='" + url + '\'' + ", method='" + method + '\'' + ", headers=" + headers + ", queryParams=" + queryParams + ", body='" + (body != null ? body.substring(0, Math.min(10, body.length()))+"..." : "null") + '\'' + ", timeout=" + timeout + '}'; } // --- Static Nested Builder Class --- public static class Builder { // Required parameter private final String url; // Optional parameters - initialized to default values private String method = "GET"; private Map headers = new HashMap<>(); private Map queryParams = new HashMap<>(); private String body = null; private int timeout = 30000; // 30 seconds default // Builder constructor for required fields public Builder(String url) { if (url == null || url.trim().isEmpty()) { throw new IllegalArgumentException("URL cannot be null or empty."); } this.url = url; } // Setter-like methods for optional fields, returning the Builder for fluency public Builder method(String method) { this.method = (method == null || method.trim().isEmpty()) ? "GET" : method.toUpperCase(); return this; } public Builder header(String key, String value) { if (key != null && value != null) { this.headers.put(key, value); } return this; } public Builder queryParam(String key, String value) { if (key != null && value != null) { this.queryParams.put(key, value); } return this; } public Builder body(String body) { this.body = body; return this; } public Builder timeout(int timeoutMillis) { if (timeoutMillis > 0) { this.timeout = timeoutMillis; } return this; } // The final build method that creates the HttpRequest object public HttpRequest build() { // Optionally, add validation logic here before creating the object // For example, ensure body is present for POST/PUT if required by your design if (("POST".equals(method) || "PUT".equals(method)) && (body == null || body.isEmpty())) { System.out.println("Warning: Building " + method + " request without a body for URL: " + url); } return new HttpRequest(this); } } } ================================================ FILE: design-patterns/java/builder/HttpRequestTelescoping.java ================================================ import java.util.HashMap; import java.util.Map; public class HttpRequestTelescoping { private String url; // Required private String method; // Optional, default GET private Map headers; // Optional private Map queryParams; // Optional private String body; // Optional private int timeout; // Optional, default 30s public HttpRequestTelescoping(String url) { this(url, "GET"); } public HttpRequestTelescoping(String url, String method) { this(url, method, null); } public HttpRequestTelescoping(String url, String method, Map headers) { this(url, method, headers, null); } public HttpRequestTelescoping(String url, String method, Map headers, Map queryParams) { this(url, method, headers, queryParams, null); } public HttpRequestTelescoping(String url, String method, Map headers, Map queryParams, String body) { this(url, method, headers, queryParams, body, 30000); } public HttpRequestTelescoping(String url, String method, Map headers, Map queryParams, String body, int timeout) { this.url = url; this.method = method; this.headers = headers == null ? new HashMap<>() : headers; this.queryParams = queryParams == null ? new HashMap<>() : queryParams; this.body = body; this.timeout = timeout; System.out.println("HttpRequest Created: URL=" + url + ", Method=" + method + ", Headers=" + this.headers.size() + ", Params=" + this.queryParams.size() + ", Body=" + (body != null) + ", Timeout=" + timeout); } // ... getters ... } ================================================ FILE: design-patterns/java/chainofresponsibility/AuthHandler.java ================================================ public class AuthHandler extends BaseHandler { @Override public void handle(Request request) { if (request.user == null) { System.out.println("AuthHandler: ❌ User not authenticated."); return; // Stop the chain } System.out.println("AuthHandler: ✅ Authenticated."); forward(request); } } ================================================ FILE: design-patterns/java/chainofresponsibility/AuthorizationHandler.java ================================================ public class AuthorizationHandler extends BaseHandler { @Override public void handle(Request request) { if (!"ADMIN".equals(request.userRole)) { System.out.println("AuthorizationHandler: ❌ Access denied."); return; } System.out.println("AuthorizationHandler: ✅ Authorized."); forward(request); } } ================================================ FILE: design-patterns/java/chainofresponsibility/BaseHandler.java ================================================ public abstract class BaseHandler implements RequestHandler { protected RequestHandler next; @Override public void setNext(RequestHandler next) { this.next = next; } protected void forward(Request request) { if (next != null) { next.handle(request); } } } ================================================ FILE: design-patterns/java/chainofresponsibility/BusinessLogicHandler.java ================================================ public class BusinessLogicHandler extends BaseHandler { @Override public void handle(Request request) { System.out.println("BusinessLogicHandler: 🚀 Processing request..."); // Core application logic goes here } } ================================================ FILE: design-patterns/java/chainofresponsibility/RateLimitHandler.java ================================================ public class RateLimitHandler extends BaseHandler { @Override public void handle(Request request) { if (request.requestCount >= 100) { System.out.println("RateLimitHandler: ❌ Rate limit exceeded."); return; } System.out.println("RateLimitHandler: ✅ Within rate limit."); forward(request); } } ================================================ FILE: design-patterns/java/chainofresponsibility/Request.java ================================================ public class Request { public String user; public String userRole; public int requestCount; public String payload; public Request(String user, String role, int requestCount, String payload) { this.user = user; this.userRole = role; this.requestCount = requestCount; this.payload = payload; } } ================================================ FILE: design-patterns/java/chainofresponsibility/RequestHandler.java ================================================ public interface RequestHandler { void setNext(RequestHandler next); void handle(Request request); } ================================================ FILE: design-patterns/java/chainofresponsibility/RequestHandlerV1.java ================================================ public class RequestHandlerV1 { public void handle(Request request) { if (!authenticate(request)) { System.out.println("Request Rejected: Authentication failed."); return; } if (!authorize(request)) { System.out.println("Request Rejected: Authorization failed."); return; } if (!rateLimit(request)) { System.out.println("Request Rejected: Rate limit exceeded."); return; } if (!validate(request)) { System.out.println("Request Rejected: Invalid payload."); return; } System.out.println("Request passed all checks. Executing business logic..."); // Proceed to business logic } private boolean authenticate(Request req) { return req.user != null; } private boolean authorize(Request req) { return "ADMIN".equals(req.userRole); } private boolean rateLimit(Request req) { return req.requestCount < 100; } private boolean validate(Request req) { return req.payload != null && !req.payload.isEmpty(); } } ================================================ FILE: design-patterns/java/chainofresponsibility/RequestHandlerV2.java ================================================ public class RequestHandlerV2 { public static void main(String[] args) { // Create handlers RequestHandler auth = new AuthHandler(); RequestHandler authorization = new AuthorizationHandler(); RequestHandler rateLimit = new RateLimitHandler(); RequestHandler validation = new ValidationHandler(); RequestHandler businessLogic = new BusinessLogicHandler(); // Build the chain auth.setNext(authorization); authorization.setNext(rateLimit); rateLimit.setNext(validation); validation.setNext(businessLogic); // Send a request through the chain Request request = new Request("john", "ADMIN", 10, "{ \"data\": \"valid\" }"); auth.handle(request); System.out.println("\n--- Trying an invalid request ---"); Request badRequest = new Request(null, "USER", 150, ""); auth.handle(badRequest); } } ================================================ FILE: design-patterns/java/chainofresponsibility/ValidationHandler.java ================================================ public class ValidationHandler extends BaseHandler { @Override public void handle(Request request) { if (request.payload == null || request.payload.trim().isEmpty()) { System.out.println("ValidationHandler: ❌ Invalid payload."); return; } System.out.println("ValidationHandler: ✅ Payload valid."); forward(request); } } ================================================ FILE: design-patterns/java/command/Command.java ================================================ interface Command { void execute(); void undo(); } ================================================ FILE: design-patterns/java/command/CommandPatternDemo.java ================================================ public class CommandPatternDemo { public static void main(String[] args) { // Receivers Light light = new Light(); Thermostat thermostat = new Thermostat(); // Commands Command lightOn = new LightOnCommand(light); Command lightOff = new LightOffCommand(light); Command setTemp22 = new SetTemperatureCommand(thermostat, 22); // Invoker SmartButton button = new SmartButton(); // Simulate usage System.out.println("→ Pressing Light ON"); button.setCommand(lightOn); button.press(); System.out.println("→ Pressing Set Temp to 22°C"); button.setCommand(setTemp22); button.press(); System.out.println("→ Pressing Light OFF"); button.setCommand(lightOff); button.press(); System.out.println("\n🔁 Undo Last Action"); button.undoLast(); // Undo Light OFF System.out.println("🔁 Undo Previous Action"); button.undoLast(); // Undo Set Temp System.out.println("🔁 Undo Again"); button.undoLast(); // Undo Light ON System.out.println("🔁 Undo Once More"); button.undoLast(); // No more actions } } ================================================ FILE: design-patterns/java/command/Light.java ================================================ public class Light { public void on() { System.out.println("Light turned ON"); } public void off() { System.out.println("Light turned OFF"); } } ================================================ FILE: design-patterns/java/command/LightOffCommand.java ================================================ public class LightOffCommand implements Command { private final Light light; public LightOffCommand(Light light) { this.light = light; } @Override public void execute() { light.off(); } @Override public void undo() { light.on(); } } ================================================ FILE: design-patterns/java/command/LightOnCommand.java ================================================ public class LightOnCommand implements Command { private final Light light; public LightOnCommand(Light light) { this.light = light; } @Override public void execute() { light.on(); } @Override public void undo() { light.off(); } } ================================================ FILE: design-patterns/java/command/SetTemperatureCommand.java ================================================ public class SetTemperatureCommand implements Command { private final Thermostat thermostat; private final int newTemperature; private int previousTemperature; public SetTemperatureCommand(Thermostat thermostat, int temperature) { this.thermostat = thermostat; this.newTemperature = temperature; } @Override public void execute() { previousTemperature = thermostat.getCurrentTemperature(); thermostat.setTemperature(newTemperature); } @Override public void undo() { thermostat.setTemperature(previousTemperature); } } ================================================ FILE: design-patterns/java/command/SmartButton.java ================================================ import java.util.Stack; public class SmartButton { private Command currentCommand; private final Stack history = new Stack<>(); public void setCommand(Command command) { this.currentCommand = command; } public void press() { if (currentCommand != null) { currentCommand.execute(); history.push(currentCommand); } else { System.out.println("No command assigned."); } } public void undoLast() { if (!history.isEmpty()) { Command lastCommand = history.pop(); lastCommand.undo(); } else { System.out.println("Nothing to undo."); } } } ================================================ FILE: design-patterns/java/command/Thermostat.java ================================================ public class Thermostat { private int currentTemperature = 20; // default public void setTemperature(int temp) { System.out.println("Thermostat set to " + temp + "°C"); currentTemperature = temp; } public int getCurrentTemperature() { return currentTemperature; } } ================================================ FILE: design-patterns/java/composite/filesystem/File.java ================================================ public class File implements FileSystemItem { private final String name; private final int size; public File(String name, int size) { this.name = name; this.size = size; } @Override public int getSize() { return size; } @Override public void printStructure(String indent) { System.out.println(indent + "- " + name + " (" + size + " KB)"); } @Override public void delete() { System.out.println("Deleting file: " + name); } } ================================================ FILE: design-patterns/java/composite/filesystem/FileExplorerApp.java ================================================ public class FileExplorerApp { public static void main(String[] args) { FileSystemItem file1 = new File("readme.txt", 5); FileSystemItem file2 = new File("photo.jpg", 1500); FileSystemItem file3 = new File("data.csv", 300); Folder documents = new Folder("Documents"); documents.addItem(file1); documents.addItem(file3); Folder pictures = new Folder("Pictures"); pictures.addItem(file2); Folder home = new Folder("Home"); home.addItem(documents); home.addItem(pictures); System.out.println("---- File Structure ----"); home.printStructure(""); System.out.println("\nTotal Size: " + home.getSize() + " KB"); System.out.println("\n---- Deleting All ----"); home.delete(); } } ================================================ FILE: design-patterns/java/composite/filesystem/FileSystemItem.java ================================================ public interface FileSystemItem { int getSize(); void printStructure(String indent); void delete(); } ================================================ FILE: design-patterns/java/composite/filesystem/Folder.java ================================================ import java.util.ArrayList; import java.util.List; public class Folder implements FileSystemItem { private final String name; private final List children = new ArrayList<>(); public Folder(String name) { this.name = name; } public void addItem(FileSystemItem item) { children.add(item); } @Override public int getSize() { int total = 0; for (FileSystemItem item : children) { total += item.getSize(); } return total; } @Override public void printStructure(String indent) { System.out.println(indent + "+ " + name + "/"); for (FileSystemItem item : children) { item.printStructure(indent + " "); } } @Override public void delete() { for (FileSystemItem item : children) { item.delete(); } System.out.println("Deleting folder: " + name); } } ================================================ FILE: design-patterns/java/composite/organization/CompositeDemo.java ================================================ public class CompositeDemo { public static void main(String[] args) { Developer dev1 = new Developer("John Doe", 100000); Developer dev2 = new Developer("Jane Smith", 120000); Designer designer = new Designer("Mike Johnson", 90000); Manager engManager = new Manager("Emily Brown", 200000); engManager.addEmployee(dev1); engManager.addEmployee(dev2); engManager.addEmployee(designer); Manager generalManager = new Manager("David Wilson", 300000); generalManager.addEmployee(engManager); System.out.println("Company Structure:"); generalManager.showDetails(); System.out.println("\nTotal Salary Budget: $" + generalManager.getSalary()); } } ================================================ FILE: design-patterns/java/composite/organization/Designer.java ================================================ class Designer implements Employee { private String name; private double salary; public Designer(String name, double salary) { this.name = name; this.salary = salary; } @Override public void showDetails() { System.out.println("Designer: " + name + ", Salary: $" + salary); } @Override public double getSalary() { return salary; } } ================================================ FILE: design-patterns/java/composite/organization/Developer.java ================================================ class Developer implements Employee { private String name; private double salary; public Developer(String name, double salary) { this.name = name; this.salary = salary; } @Override public void showDetails() { System.out.println("Developer: " + name + ", Salary: $" + salary); } @Override public double getSalary() { return salary; } } ================================================ FILE: design-patterns/java/composite/organization/Employee.java ================================================ interface Employee { void showDetails(); double getSalary(); } ================================================ FILE: design-patterns/java/composite/organization/Manager.java ================================================ import java.util.ArrayList; import java.util.List; class Manager implements Employee { private String name; private double salary; private List subordinates = new ArrayList<>(); public Manager(String name, double salary) { this.name = name; this.salary = salary; } public void addEmployee(Employee employee) { subordinates.add(employee); } public void removeEmployee(Employee employee) { subordinates.remove(employee); } @Override public void showDetails() { System.out.println("Manager: " + name + ", Salary: $" + salary); System.out.println("Subordinates:"); for (Employee employee : subordinates) { employee.showDetails(); } } @Override public double getSalary() { double totalSalary = salary; for (Employee employee : subordinates) { totalSalary += employee.getSalary(); } return totalSalary; } } ================================================ FILE: design-patterns/java/decorator/BoldDecorator.java ================================================ public class BoldDecorator extends TextDecorator { public BoldDecorator(TextView inner) { super(inner); } @Override public void render() { System.out.print(""); inner.render(); System.out.print(""); } } ================================================ FILE: design-patterns/java/decorator/DecoratorDemo.java ================================================ public class DecoratorDemo { public static void main(String[] args) { TextView plain = new PlainTextView("Hello, world!"); System.out.print("Plain: "); plain.render(); System.out.println(); System.out.print("Bold: "); TextView bold = new BoldDecorator(plain); bold.render(); System.out.println(); System.out.print("Italic + Bold: "); TextView italicBold = new ItalicDecorator(bold); italicBold.render(); System.out.println(); System.out.print("Underline + Italic + Bold: "); TextView fullStyle = new UnderlineDecorator(italicBold); fullStyle.render(); System.out.println(); } } ================================================ FILE: design-patterns/java/decorator/ItalicDecorator.java ================================================ public class ItalicDecorator extends TextDecorator { public ItalicDecorator(TextView inner) { super(inner); } @Override public void render() { System.out.print(""); inner.render(); System.out.print(""); } } ================================================ FILE: design-patterns/java/decorator/PlainTextView.java ================================================ public class PlainTextView implements TextView { private final String text; public PlainTextView(String text) { this.text = text; } @Override public void render() { System.out.print(text); } } ================================================ FILE: design-patterns/java/decorator/TextDecorator.java ================================================ public abstract class TextDecorator implements TextView { protected final TextView inner; public TextDecorator(TextView inner) { this.inner = inner; } } ================================================ FILE: design-patterns/java/decorator/TextView.java ================================================ public interface TextView { void render(); } ================================================ FILE: design-patterns/java/decorator/UnderlineDecorator.java ================================================ public class UnderlineDecorator extends TextDecorator { public UnderlineDecorator(TextView inner) { super(inner); } @Override public void render() { System.out.print(""); inner.render(); System.out.print(""); } } ================================================ FILE: design-patterns/java/decorator/coffee/Coffee.java ================================================ interface Coffee { double getCost(); String getDescription(); } ================================================ FILE: design-patterns/java/decorator/coffee/CoffeeDecorator.java ================================================ abstract class CoffeeDecorator implements Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; } public double getCost() { return decoratedCoffee.getCost(); } public String getDescription() { return decoratedCoffee.getDescription(); } } ================================================ FILE: design-patterns/java/decorator/coffee/DecoratorDemo.java ================================================ public class DecoratorDemo { public static void main(String[] args) { // Order a simple coffee Coffee coffee = new SimpleCoffee(); System.out.println("Cost: $" + coffee.getCost() + "; Description: " + coffee.getDescription()); // Decorate it with milk coffee = new Milk(coffee); System.out.println("Cost: $" + coffee.getCost() + "; Description: " + coffee.getDescription()); // Decorate it with sugar coffee = new Sugar(coffee); System.out.println("Cost: $" + coffee.getCost() + "; Description: " + coffee.getDescription()); } } ================================================ FILE: design-patterns/java/decorator/coffee/Milk.java ================================================ class Milk extends CoffeeDecorator { public Milk(Coffee coffee) { super(coffee); } @Override public double getCost() { return super.getCost() + 0.5; } @Override public String getDescription() { return super.getDescription() + ", milk"; } } ================================================ FILE: design-patterns/java/decorator/coffee/SimpleCoffee.java ================================================ class SimpleCoffee implements Coffee { @Override public double getCost() { return 1.0; } @Override public String getDescription() { return "Simple coffee"; } } ================================================ FILE: design-patterns/java/decorator/coffee/Sugar.java ================================================ class Sugar extends CoffeeDecorator { public Sugar(Coffee coffee) { super(coffee); } @Override public double getCost() { return super.getCost() + 0.2; } @Override public String getDescription() { return super.getDescription() + ", sugar"; } } ================================================ FILE: design-patterns/java/facade/BuildSystem.java ================================================ public class BuildSystem { public boolean compileProject() { System.out.println("BuildSystem: Compiling project..."); simulateDelay(2000); System.out.println("BuildSystem: Build successful."); return true; } public String getArtifactPath() { String path = "target/myapplication-1.0.jar"; System.out.println("BuildSystem: Artifact located at " + path); return path; } private void simulateDelay(int ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: design-patterns/java/facade/DeploymentAppDirect.java ================================================ public class DeploymentAppDirect { public static void main(String[] args) { DeploymentOrchestrator orchestrator = new DeploymentOrchestrator(); orchestrator.deployApplication("main", "prod.server.example.com"); System.out.println("\n--- Attempting another deployment ---"); orchestrator.deployApplication("feature/new-ui", "staging.server.example.com"); } } ================================================ FILE: design-patterns/java/facade/DeploymentAppFacade.java ================================================ public class DeploymentAppFacade { public static void main(String[] args) { DeploymentFacade deploymentFacade = new DeploymentFacade(); // Deploy to production deploymentFacade.deployApplication("main", "prod.server.example.com"); // Deploy a feature branch to staging System.out.println("\n--- Deploying feature branch to staging ---"); deploymentFacade.deployApplication("feature/new-ui", "staging.server.example.com"); } } ================================================ FILE: design-patterns/java/facade/DeploymentFacade.java ================================================ public class DeploymentFacade { // Instances of all the subsystem components // or they can be injected (e.g., via constructor for better testability). private VersionControlSystem vcs = new VersionControlSystem(); private BuildSystem buildSystem = new BuildSystem(); private TestingFramework testingFramework = new TestingFramework(); private DeploymentTarget deploymentTarget = new DeploymentTarget(); // Perform a full standard deployment: pull, build, test, deploy. public boolean deployApplication(String branch, String serverAddress) { System.out.println("\nFACADE: --- Initiating FULL DEPLOYMENT for branch: " + branch + " to " + serverAddress + " ---"); boolean success = true; try { // Step 1: Pull latest code vcs.pullLatestChanges(branch); // Step 2: Build the project if (!buildSystem.compileProject()) { System.err.println("FACADE: DEPLOYMENT FAILED - Build compilation failed."); return false; // Exit early on critical failure } String artifactPath = buildSystem.getArtifactPath(); // Step 3: Run tests if (!testingFramework.runUnitTests()) { System.err.println("FACADE: DEPLOYMENT FAILED - Unit tests failed."); return false; } if (!testingFramework.runIntegrationTests()) { System.err.println("FACADE: DEPLOYMENT FAILED - Integration tests failed."); return false; } // Step 4: Deploy to production deploymentTarget.transferArtifact(artifactPath, serverAddress); deploymentTarget.activateNewVersion(serverAddress); System.out.println("FACADE: APPLICATION DEPLOYED SUCCESSFULLY TO " + serverAddress + "!"); } catch (Exception e) { System.err.println("FACADE: DEPLOYMENT FAILED - An unexpected error occurred: " + e.getMessage()); e.printStackTrace(); // Log the full stack trace success = false; } return success; } public boolean deployHotfix(String branch, String serverAddress) { System.out.println("\nFACADE: --- Initiating HOTFIX DEPLOYMENT for branch: " + branch + " to " + serverAddress + " ---"); boolean success = true; try { // Step 1: Pull latest code vcs.pullLatestChanges(branch); // Step 2: Build the project if (!buildSystem.compileProject()) { System.err.println("FACADE: HOTFIX FAILED - Build compilation failed."); return false; } String artifactPath = buildSystem.getArtifactPath(); // Step 3: For a hotfix, we might skip extensive tests or run a specific "smoke test" suite. System.out.println("FACADE: Skipping full test suite for hotfix deployment (or running minimal smoke tests)."); // if (!testingFramework.runSmokeTests()) { return false; } // Example // Step 4: Deploy to production deploymentTarget.transferArtifact(artifactPath, serverAddress); deploymentTarget.activateNewVersion(serverAddress); System.out.println("FACADE: HOTFIX DEPLOYED SUCCESSFULLY TO " + serverAddress + "!"); } catch (Exception e) { System.err.println("FACADE: HOTFIX FAILED - An unexpected error occurred: " + e.getMessage()); success = false; } return success; } // We could add other simplified methods: rollbackLastDeployment(), checkDeploymentStatus(), etc. } ================================================ FILE: design-patterns/java/facade/DeploymentOrchestrator.java ================================================ public class DeploymentOrchestrator { private VersionControlSystem vcs = new VersionControlSystem(); private BuildSystem buildSystem = new BuildSystem(); private TestingFramework testFramework = new TestingFramework(); private DeploymentTarget deployTarget = new DeploymentTarget(); public boolean deployApplication(String branch, String prodServer) { System.out.println("\n[Orchestrator] Starting deployment for branch: " + branch); vcs.pullLatestChanges(branch); if (!buildSystem.compileProject()) { System.err.println("Build failed. Deployment aborted."); return false; } String artifact = buildSystem.getArtifactPath(); if (!testFramework.runUnitTests() || !testFramework.runIntegrationTests()) { System.err.println("Tests failed. Deployment aborted."); return false; } deployTarget.transferArtifact(artifact, prodServer); deployTarget.activateNewVersion(prodServer); System.out.println("[Orchestrator] Deployment successful!"); return true; } } ================================================ FILE: design-patterns/java/facade/DeploymentTarget.java ================================================ public class DeploymentTarget { public void transferArtifact(String artifactPath, String server) { System.out.println("Deployment: Transferring " + artifactPath + " to " + server + "..."); simulateDelay(1000); System.out.println("Deployment: Transfer complete."); } public void activateNewVersion(String server) { System.out.println("Deployment: Activating new version on " + server + "..."); simulateDelay(500); System.out.println("Deployment: Now live on " + server + "!"); } private void simulateDelay(int ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: design-patterns/java/facade/TestingFramework.java ================================================ public class TestingFramework { public boolean runUnitTests() { System.out.println("Testing: Running unit tests..."); simulateDelay(1500); System.out.println("Testing: Unit tests passed."); return true; } public boolean runIntegrationTests() { System.out.println("Testing: Running integration tests..."); simulateDelay(3000); System.out.println("Testing: Integration tests passed."); return true; } private void simulateDelay(int ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: design-patterns/java/facade/VersionControlSystem.java ================================================ public class VersionControlSystem { public void pullLatestChanges(String branch) { System.out.println("VCS: Pulling latest changes from '" + branch + "'..."); simulateDelay(); System.out.println("VCS: Pull complete."); } private void simulateDelay() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: design-patterns/java/factory/notification/EmailNotification.java ================================================ public class EmailNotification implements Notification { @Override public void send(String message) { System.out.println("Sending email: " + message); } } ================================================ FILE: design-patterns/java/factory/notification/EmailNotificationCreator.java ================================================ public class EmailNotificationCreator extends NotificationCreator { @Override public Notification createNotification() { return new EmailNotification(); } } ================================================ FILE: design-patterns/java/factory/notification/FactoryMethodDemo.java ================================================ public class FactoryMethodDemo { public static void main(String[] args) { NotificationCreator creator; // Send Email creator = new EmailNotificationCreator(); creator.send("Welcome to our platform!"); // Send SMS creator = new SMSNotificationCreator(); creator.send("Your OTP is 123456"); // Send Push Notification creator = new PushNotificationCreator(); creator.send("You have a new follower!"); } } ================================================ FILE: design-patterns/java/factory/notification/Notification.java ================================================ public interface Notification { public void send(String message); } ================================================ FILE: design-patterns/java/factory/notification/NotificationCreator.java ================================================ public abstract class NotificationCreator { // Factory Method public abstract Notification createNotification(); // Common logic using the factory method public void send(String message) { Notification notification = createNotification(); notification.send(message); } } ================================================ FILE: design-patterns/java/factory/notification/NotificationServiceNaive.java ================================================ public class NotificationServiceNaive { public void sendNotification(String type, String message) { if (type.equals("EMAIL")) { EmailNotification email = new EmailNotification(); email.send(message); } else if (type.equals("SMS")) { SMSNotification sms = new SMSNotification(); sms.send(message); } else if (type.equals("Push")) { PushNotification push = new PushNotification(); push.send(message); } } } ================================================ FILE: design-patterns/java/factory/notification/PushNotification.java ================================================ public class PushNotification implements Notification { @Override public void send(String message) { System.out.println("Sending push notification: " + message); } } ================================================ FILE: design-patterns/java/factory/notification/PushNotificationCreator.java ================================================ public class PushNotificationCreator extends NotificationCreator { @Override public Notification createNotification() { return new PushNotification(); } } ================================================ FILE: design-patterns/java/factory/notification/SMSNotification.java ================================================ public class SMSNotification implements Notification { @Override public void send(String message) { System.out.println("Sending SMS: " + message); } } ================================================ FILE: design-patterns/java/factory/notification/SMSNotificationCreator.java ================================================ public class SMSNotificationCreator extends NotificationCreator { @Override public Notification createNotification() { return new SMSNotification(); } } ================================================ FILE: design-patterns/java/factory/notification/SimpleNotificationFactory.java ================================================ public class SimpleNotificationFactory { public static Notification createNotification(String type) { return switch (type) { case "EMAIL" -> new EmailNotification(); case "SMS" -> new SMSNotification(); case "PUSH" -> new PushNotification(); default -> throw new IllegalArgumentException("Unknown type"); }; } } ================================================ FILE: design-patterns/java/factory/subscription/Customer.java ================================================ public class Customer { public String customerId; public Subscription subscription = null; public Customer(String customerId) { this.customerId = customerId; } public void SubscribePlan(Subscription subscription) { this.subscription = subscription; this.subscription.addSubscription(this); } public void unSubscribePlan() { subscription.removeSubscription(this); } public void updateSubcribePlan(Subscription newSubscription) { subscription.removeSubscription(this); this.subscription = newSubscription; this.subscription.addSubscription(this); } } ================================================ FILE: design-patterns/java/factory/subscription/DataBase.java ================================================ import java.util.HashMap; public class DataBase { private HashMap customerList; public DataBase() { customerList = new HashMap<>(); } public void addToDataBase(String customerId, String subscriptionType) { if(!customerList.containsKey(customerId)) customerList.put(customerId, subscriptionType); System.out.println("Successfull Added to the DB"); } public void removeFromDataBase(String customerId) { if(customerList.containsKey(customerId)) customerList.remove(customerId); System.out.println("Successfully removed from the DB"); } public void updateDataBase(String customerId, String subscriptionType) { if(!customerList.containsKey(customerId)) System.out.println("Record not found"); else { customerList.put(customerId, subscriptionType); System.out.println("Sucessfully update the DB"); } } } ================================================ FILE: design-patterns/java/factory/subscription/FactoryApplication.java ================================================ public class FactoryApplication { static public DataBase dataBase; public static void main(String[] arg) { dataBase = new DataBase(); SubscriptionFactory factory = new SubscriptionFactory(dataBase); Customer customer1 = new Customer("1"); Customer customer2 = new Customer("2"); Customer customer3 = new Customer("3"); customer1.SubscribePlan(factory.getSubscription("gold")); customer2.SubscribePlan(factory.getSubscription("silver")); customer1.updateSubcribePlan(factory.getSubscription("royalGold")); customer2.unSubscribePlan(); customer3.SubscribePlan(factory.getSubscription("platinum")); } } ================================================ FILE: design-patterns/java/factory/subscription/Gold.java ================================================ public class Gold implements Subscription { DataBase dataBase; public Gold(DataBase dataBase) { this.dataBase = dataBase; } @Override public String subscriptionType() { return this.getClass().getName(); } @Override public boolean addSubscription(Customer customer) { System.out.println("Customer"+ customer.customerId+ "Added to the Gold List" ); dataBase.addToDataBase(customer.customerId, "Gold"); return true; } @Override public boolean removeSubscription(Customer customer) { dataBase.removeFromDataBase(customer.customerId); System.out.println("Customer "+ customer.customerId +" removed to the Gold List" ); return true; } @Override public boolean updateSubscription(Customer customer) { dataBase.updateDataBase(customer.customerId, "Gold"); System.out.println("Customer "+ customer.customerId+" Updated to the Gold List" ); return true; } } ================================================ FILE: design-patterns/java/factory/subscription/Platinum.java ================================================ public class Platinum implements Subscription { DataBase dataBase; public Platinum(DataBase dataBase) { this.dataBase = dataBase; } @Override public String subscriptionType() { return this.getClass().getName(); } @Override public boolean addSubscription(Customer customer) { System.out.println("Customer Added to the Platinum List" ); dataBase.addToDataBase(customer.customerId, "Platinum"); return true; } @Override public boolean removeSubscription(Customer customer) { dataBase.removeFromDataBase(customer.customerId); System.out.println("Customer removed to the Platinum List" ); return true; } @Override public boolean updateSubscription(Customer customer) { dataBase.updateDataBase(customer.customerId, "Platinum"); System.out.println("Customer Updated to the Platinum List" ); return true; } } ================================================ FILE: design-patterns/java/factory/subscription/RoyalGold.java ================================================ public class RoyalGold implements Subscription { DataBase dataBase; public RoyalGold(DataBase dataBase) { this.dataBase = dataBase; } @Override public String subscriptionType() { return this.getClass().getName(); } @Override public boolean addSubscription(Customer customer) { System.out.println("Customer Added to the RoyalGold List" ); dataBase.addToDataBase(customer.customerId, "RoyalGold"); return true; } @Override public boolean removeSubscription(Customer customer) { dataBase.removeFromDataBase(customer.customerId); System.out.println("Customer removed to the RoyalGold List" ); return true; } @Override public boolean updateSubscription(Customer customer) { dataBase.updateDataBase(customer.customerId, "RoyalGold"); System.out.println("Customer Updated to the RoyalGold List" ); return true; } } ================================================ FILE: design-patterns/java/factory/subscription/Silver.java ================================================ public class Silver implements Subscription { DataBase dataBase; public Silver(DataBase dataBase) { this.dataBase = dataBase; } @Override public String subscriptionType() { return this.getClass().getName(); } @Override public boolean addSubscription(Customer customer) { System.out.println("Customer Added to the Silver List" ); dataBase.addToDataBase(customer.customerId, "Silver"); return true; } @Override public boolean removeSubscription(Customer customer) { dataBase.removeFromDataBase(customer.customerId); System.out.println("Customer removed to the Silver List" ); return true; } @Override public boolean updateSubscription(Customer customer) { dataBase.updateDataBase(customer.customerId, "Silver"); System.out.println("Customer Updated to the Silver List" ); return true; } } ================================================ FILE: design-patterns/java/factory/subscription/Subscription.java ================================================ public interface Subscription { public String subscriptionType(); public boolean addSubscription(Customer customer); public boolean removeSubscription(Customer customer); public boolean updateSubscription(Customer customer); } ================================================ FILE: design-patterns/java/factory/subscription/SubscriptionFactory.java ================================================ public class SubscriptionFactory { private final DataBase dataBase; public SubscriptionFactory(DataBase dataBase){ this.dataBase = dataBase; } public Subscription getSubscription(String subscriptionType){ return switch (subscriptionType) { case "gold" -> new Gold(dataBase); case "silver" -> new Silver(dataBase); case "platinum" -> new Platinum(dataBase); case "royalGold" -> new RoyalGold(dataBase); default -> throw new IllegalArgumentException("Unknown subcription type"); }; } } ================================================ FILE: design-patterns/java/flyweight/CharacterFlyweight.java ================================================ public interface CharacterFlyweight { void draw(int x, int y); } ================================================ FILE: design-patterns/java/flyweight/CharacterFlyweightFactory.java ================================================ import java.util.Map; import java.util.HashMap; public class CharacterFlyweightFactory { private static final Map flyweightCache = new HashMap<>(); public static CharacterFlyweight getFlyweight(char symbol, String fontFamily, int fontSize, String color) { String key = String.format("%s-%d-%s", symbol, fontSize, color); if (!flyweightCache.containsKey(key)) { flyweightCache.put(key, new CharacterGlyph(symbol, fontFamily, fontSize, color)); } return flyweightCache.get(key); } public int getFlyweightCount() { return flyweightCache.size(); } } ================================================ FILE: design-patterns/java/flyweight/CharacterGlyph.java ================================================ public class CharacterGlyph implements CharacterFlyweight { private final char symbol; private final String fontFamily; private final int fontSize; private final String color; public CharacterGlyph(char symbol, String fontFamily, int fontSize, String color) { this.symbol = symbol; this.fontFamily = fontFamily; this.fontSize = fontSize; this.color = color; } @Override public void draw(int x, int y) { System.out.println(String.format("Rendering %s at (%d, %d) with font %s, size %d, color %s", symbol, x, y, fontFamily, fontSize, color)); } } ================================================ FILE: design-patterns/java/flyweight/FlyweightDemo.java ================================================ public class FlyweightDemo { public static void main(String[] args) { TextEditorClient editor = new TextEditorClient(); // Render 'Hello' with the same style String word = "Hello"; for (int i = 0; i < word.length(); i++) { editor.addCharacter(word.charAt(i), 10 + i * 15, 50, "Arial", 14, "#000000"); } // Render 'World' with a different font and color String word2 = "World"; for (int i = 0; i < word2.length(); i++) { editor.addCharacter(word2.charAt(i), 10 + i * 15, 100, "Times New Roman", 14, "#3333FF"); } editor.renderDocument(); } } ================================================ FILE: design-patterns/java/flyweight/TextEditorClient.java ================================================ import java.util.List; import java.util.ArrayList; public class TextEditorClient { private final CharacterFlyweightFactory factory = new CharacterFlyweightFactory(); private final List document = new ArrayList<>(); public void addCharacter(char c, int x, int y, String font, int size, String color) { CharacterFlyweight glyph = factory.getFlyweight(c, font, size, color); document.add(new RenderedCharacter(glyph, x, y)); } public void renderDocument() { for (RenderedCharacter rc : document) { rc.draw(); } System.out.println("Total flyweight objects used: " + factory.getFlyweightCount()); } private static class RenderedCharacter { private final CharacterFlyweight glyph; private final int x, y; public RenderedCharacter(CharacterFlyweight glyph, int x, int y) { this.glyph = glyph; this.x = x; this.y = y; } public void draw() { glyph.draw(x, y); } } } ================================================ FILE: design-patterns/java/iterator/IterableCollection.java ================================================ public interface IterableCollection { Iterator createIterator(); } ================================================ FILE: design-patterns/java/iterator/Iterator.java ================================================ public interface Iterator { boolean hasNext(); T next(); } ================================================ FILE: design-patterns/java/iterator/MusicPlayer.java ================================================ public class MusicPlayer { public static void main(String[] args) { Playlist playlist = new Playlist(); playlist.addSong("Shape of You"); playlist.addSong("Bohemian Rhapsody"); playlist.addSong("Blinding Lights"); Iterator iterator = playlist.createIterator(); System.out.println("Now Playing:"); while (iterator.hasNext()) { System.out.println("🎵 " + iterator.next()); } } } ================================================ FILE: design-patterns/java/iterator/Playlist.java ================================================ import java.util.List; import java.util.ArrayList; public class Playlist implements IterableCollection { private final List songs = new ArrayList<>(); public void addSong(String song) { songs.add(song); } public String getSongAt(int index) { return songs.get(index); } public int getSize() { return songs.size(); } @Override public Iterator createIterator() { return new PlaylistIterator(this); } } ================================================ FILE: design-patterns/java/iterator/PlaylistIterator.java ================================================ public class PlaylistIterator implements Iterator { private final Playlist playlist; private int index = 0; public PlaylistIterator(Playlist playlist) { this.playlist = playlist; } @Override public boolean hasNext() { return index < playlist.getSize(); } @Override public String next() { return playlist.getSongAt(index++); } } ================================================ FILE: design-patterns/java/iterator/books/Book.java ================================================ class Book { private String title; public Book(String title) { this.title = title; } public String getTitle() { return title; } } ================================================ FILE: design-patterns/java/iterator/books/BookShelf.java ================================================ import java.util.List; import java.util.ArrayList; import java.util.Iterator; class BookShelf implements Container { private List books; public BookShelf() { books = new ArrayList<>(); } public void addBook(Book book) { books.add(book); } @Override public Iterator getIterator() { return new BookShelfIterator(); } // ConcreteIterator private class BookShelfIterator implements Iterator { private int index; @Override public boolean hasNext() { return index < books.size(); } @Override public Book next() { if (this.hasNext()) { return books.get(index++); } return null; } } } ================================================ FILE: design-patterns/java/iterator/books/Container.java ================================================ interface Container { Iterator getIterator(); } ================================================ FILE: design-patterns/java/iterator/books/Iterator.java ================================================ interface Iterator { boolean hasNext(); T next(); } ================================================ FILE: design-patterns/java/iterator/books/IteratorDemo.java ================================================ public class IteratorDemo { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(); bookShelf.addBook(new Book("Design Patterns")); bookShelf.addBook(new Book("Clean Code")); bookShelf.addBook(new Book("Refactoring")); Iterator iterator = bookShelf.getIterator(); System.out.println("Books in the shelf:"); while (iterator.hasNext()) { Book book = iterator.next(); System.out.println("- " + book.getTitle()); } } } ================================================ FILE: design-patterns/java/mediator/Button.java ================================================ public class Button extends UIComponent { private boolean enabled = false; public Button(UIMediator mediator) { super(mediator); } public void click() { if (enabled) { System.out.println("Login Button clicked!"); notifyMediator(); // Will trigger login attempt } else { System.out.println("Login Button is disabled."); } } public void setEnabled(boolean value) { this.enabled = value; System.out.println("Login Button is now " + (enabled ? "ENABLED" : "DISABLED")); } } ================================================ FILE: design-patterns/java/mediator/FormMediator.java ================================================ public class FormMediator implements UIMediator { private TextField usernameField; private TextField passwordField; private Button loginButton; private Label statusLabel; public void setUsernameField(TextField usernameField) { this.usernameField = usernameField; } public void setPasswordField(TextField passwordField) { this.passwordField = passwordField; } public void setLoginButton(Button loginButton) { this.loginButton = loginButton; } public void setStatusLabel(Label statusLabel) { this.statusLabel = statusLabel; } @Override public void componentChanged(UIComponent component) { if (component == usernameField || component == passwordField) { boolean enableButton = !usernameField.getText().isEmpty() && !passwordField.getText().isEmpty(); loginButton.setEnabled(enableButton); } else if (component == loginButton) { String username = usernameField.getText(); String password = passwordField.getText(); if ("admin".equals(username) && "1234".equals(password)) { statusLabel.setText("✅ Login successful!"); } else { statusLabel.setText("❌ Invalid credentials."); } } } } ================================================ FILE: design-patterns/java/mediator/Label.java ================================================ public class Label extends UIComponent { private String text; public Label(UIMediator mediator) { super(mediator); } public void setText(String message) { this.text = message; System.out.println("Status: " + text); } } ================================================ FILE: design-patterns/java/mediator/MediatorApp.java ================================================ public class MediatorApp { public static void main(String[] args) { FormMediator mediator = new FormMediator(); TextField usernameField = new TextField(mediator); TextField passwordField = new TextField(mediator); Button loginButton = new Button(mediator); Label statusLabel = new Label(mediator); mediator.setUsernameField(usernameField); mediator.setPasswordField(passwordField); mediator.setLoginButton(loginButton); mediator.setStatusLabel(statusLabel); // Simulate user interaction usernameField.setText("admin"); passwordField.setText("1234"); loginButton.click(); // Should succeed System.out.println("\n--- New Attempt with Wrong Password ---"); passwordField.setText("wrong"); loginButton.click(); // Should fail } } ================================================ FILE: design-patterns/java/mediator/TextField.java ================================================ public class TextField extends UIComponent { private String text = ""; public TextField(UIMediator mediator) { super(mediator); } public void setText(String newText) { this.text = newText; System.out.println("TextField updated: " + newText); notifyMediator(); } public String getText() { return text; } } ================================================ FILE: design-patterns/java/mediator/UIComponent.java ================================================ public abstract class UIComponent { protected UIMediator mediator; public UIComponent(UIMediator mediator) { this.mediator = mediator; } public void notifyMediator() { mediator.componentChanged(this); } } ================================================ FILE: design-patterns/java/mediator/UIMediator.java ================================================ public interface UIMediator { void componentChanged(UIComponent component); } ================================================ FILE: design-patterns/java/memento/TextEditor.java ================================================ public class TextEditor { private String content = ""; public void type(String newText) { content += newText; System.out.println("Typed: " + newText); } public String getContent() { return content; } public TextEditorMemento save() { System.out.println("Saving state: \"" + content + "\""); return new TextEditorMemento(content); } public void restore(TextEditorMemento memento) { content = memento.getState(); System.out.println("Restored state to: \"" + content + "\""); } } ================================================ FILE: design-patterns/java/memento/TextEditorMemento.java ================================================ public class TextEditorMemento { private final String state; public TextEditorMemento(String state) { this.state = state; } public String getState() { return state; } } ================================================ FILE: design-patterns/java/memento/TextEditorNaive.java ================================================ public class TextEditorNaive { private String content = ""; public void type(String newText) { content += newText; } public void undo(String previousContent) { content = previousContent; } public String getContent() { return content; } } ================================================ FILE: design-patterns/java/memento/TextEditorUndoManager.java ================================================ import java.util.Stack; public class TextEditorUndoManager { private final Stack history = new Stack<>(); public void save(TextEditor editor) { history.push(editor.save()); } public void undo(TextEditor editor) { if (!history.isEmpty()) { editor.restore(history.pop()); } else { System.out.println("Nothing to undo."); } } } ================================================ FILE: design-patterns/java/memento/TextEditorUndoV1.java ================================================ public class TextEditorUndoV1 { public static void main(String[] args) { TextEditorNaive editor = new TextEditorNaive(); editor.type("Hello"); String snapshot1 = editor.getContent(); // manual snapshot editor.type(" World"); String snapshot2 = editor.getContent(); System.out.println("Current Content: " + editor.getContent()); // Hello World // Undo 1 step editor.undo(snapshot1); System.out.println("After Undo: " + editor.getContent()); // Hello } } ================================================ FILE: design-patterns/java/memento/TextEditorUndoV2.java ================================================ public class TextEditorUndoV2 { public static void main(String[] args) { TextEditor editor = new TextEditor(); TextEditorUndoManager undoManager = new TextEditorUndoManager(); editor.type("Hello"); undoManager.save(editor); // save state: Hello editor.type(" World"); undoManager.save(editor); // save state: Hello World editor.type("!"); System.out.println("Current Content: " + editor.getContent()); // Hello World! System.out.println("\n--- Undo 1 ---"); undoManager.undo(editor); // Back to: Hello World System.out.println("\n--- Undo 2 ---"); undoManager.undo(editor); // Back to: Hello System.out.println("\n--- Undo 3 ---"); undoManager.undo(editor); // Nothing left to undo } } ================================================ FILE: design-patterns/java/observer/FitnessAppNaiveClient.java ================================================ public class FitnessAppNaiveClient { public static void main(String[] args) { LiveActivityDisplayNaive display = new LiveActivityDisplayNaive(); ProgressLoggerNaive logger = new ProgressLoggerNaive(); NotificationServiceNaive notifier = new NotificationServiceNaive(); FitnessDataNaive fitnessData = new FitnessDataNaive(display, logger, notifier); fitnessData.newFitnessDataPushed(500, 5, 20); fitnessData.newFitnessDataPushed(9800, 85, 350); fitnessData.newFitnessDataPushed(10100, 90, 380); // Goal should be hit fitnessData.dailyReset(); } } ================================================ FILE: design-patterns/java/observer/FitnessAppObserverDemo.java ================================================ public class FitnessAppObserverDemo { public static void main(String[] args) { FitnessData fitnessData = new FitnessData(); LiveActivityDisplay display = new LiveActivityDisplay(); ProgressLogger logger = new ProgressLogger(); GoalNotifier notifier = new GoalNotifier(); // Register observers fitnessData.registerObserver(display); fitnessData.registerObserver(logger); fitnessData.registerObserver(notifier); // Simulate updates fitnessData.newFitnessDataPushed(500, 5, 20); fitnessData.newFitnessDataPushed(9800, 85, 350); fitnessData.newFitnessDataPushed(10100, 90, 380); // Goal should trigger // Daily reset notifier.reset(); fitnessData.dailyReset(); } } ================================================ FILE: design-patterns/java/observer/FitnessData.java ================================================ import java.util.*; public class FitnessData implements FitnessDataSubject { private int steps; private int activeMinutes; private int calories; private final List observers = new ArrayList<>(); @Override public void registerObserver(FitnessDataObserver observer) { observers.add(observer); } @Override public void removeObserver(FitnessDataObserver observer) { observers.remove(observer); } @Override public void notifyObservers() { for (FitnessDataObserver observer : observers) { observer.update(this); } } public void newFitnessDataPushed(int steps, int activeMinutes, int calories) { this.steps = steps; this.activeMinutes = activeMinutes; this.calories = calories; System.out.println("\nFitnessData: New data received — Steps: " + steps + ", Active Minutes: " + activeMinutes + ", Calories: " + calories); notifyObservers(); } public void dailyReset() { this.steps = 0; this.activeMinutes = 0; this.calories = 0; System.out.println("\nFitnessData: Daily reset performed."); notifyObservers(); } // Getters public int getSteps() { return steps; } public int getActiveMinutes() { return activeMinutes; } public int getCalories() { return calories; } } ================================================ FILE: design-patterns/java/observer/FitnessDataNaive.java ================================================ public class FitnessDataNaive { private int steps; private int activeMinutes; private int calories; // Direct, hardcoded references to all dependent modules! private LiveActivityDisplayNaive liveDisplay; private ProgressLoggerNaive progressLogger; private NotificationServiceNaive notificationService; public FitnessDataNaive(LiveActivityDisplayNaive ld, ProgressLoggerNaive pl, NotificationServiceNaive ns) { this.liveDisplay = ld; this.progressLogger = pl; this.notificationService = ns; } // This method gets called when new data arrives from the wearable public void newFitnessDataPushed(int newSteps, int newActiveMinutes, int newCalories) { this.steps = newSteps; this.activeMinutes = newActiveMinutes; this.calories = newCalories; System.out.println("\nFitnessDataNaive: New data received - Steps:" + steps + ", ActiveMins:" + activeMinutes + ", Calories:" + calories); // Manually notify each dependent module liveDisplay.showStats(steps, activeMinutes, calories); progressLogger.logDataPoint(steps, activeMinutes, calories); notificationService.checkAndNotify(steps); } public void dailyReset() { // ... reset steps, etc. ... notificationService.resetDailyNotifications(); System.out.println("FitnessDataNaive: Daily data reset."); newFitnessDataPushed(0,0,0); // Notify of reset state } } ================================================ FILE: design-patterns/java/observer/FitnessDataObserver.java ================================================ public interface FitnessDataObserver { void update(FitnessData data); } ================================================ FILE: design-patterns/java/observer/FitnessDataSubject.java ================================================ public interface FitnessDataSubject { void registerObserver(FitnessDataObserver o); void removeObserver(FitnessDataObserver o); void notifyObservers(); } ================================================ FILE: design-patterns/java/observer/GoalNotifier.java ================================================ public class GoalNotifier implements FitnessDataObserver { private final int stepGoal = 10000; private boolean goalReached = false; @Override public void update(FitnessData data) { if (data.getSteps() >= stepGoal && !goalReached) { System.out.println("Notifier → 🎉 Goal Reached! You've hit " + stepGoal + " steps!"); goalReached = true; } } public void reset() { goalReached = false; } } ================================================ FILE: design-patterns/java/observer/LiveActivityDisplay.java ================================================ public class LiveActivityDisplay implements FitnessDataObserver { @Override public void update(FitnessData data) { System.out.println("Live Display → Steps: " + data.getSteps() + " | Active Minutes: " + data.getActiveMinutes() + " | Calories: " + data.getCalories()); } } ================================================ FILE: design-patterns/java/observer/LiveActivityDisplayNaive.java ================================================ public class LiveActivityDisplayNaive { public void showStats(int steps, int activeMinutes, int calories) { System.out.println("NAIVE Live Display: Steps: " + steps + " | Active Mins: " + activeMinutes + " | Calories: " + calories); } } ================================================ FILE: design-patterns/java/observer/NotificationServiceNaive.java ================================================ public class NotificationServiceNaive { private int stepGoal = 10000; private boolean dailyStepGoalNotified = false; public void checkAndNotify(int currentSteps) { if (currentSteps >= stepGoal && !dailyStepGoalNotified) { System.out.println("NAIVE Notifier: ALERT! You've reached your " + stepGoal + " step goal!"); dailyStepGoalNotified = true; } // ... other notification logic, e.g., inactivity alerts ... } public void resetDailyNotifications() { dailyStepGoalNotified = false; } } ================================================ FILE: design-patterns/java/observer/ProgressLogger.java ================================================ public class ProgressLogger implements FitnessDataObserver { @Override public void update(FitnessData data) { System.out.println("Logger → Saving to DB: Steps=" + data.getSteps() + ", ActiveMinutes=" + data.getActiveMinutes() + ", Calories=" + data.getCalories()); // Simulated DB/file write... } } ================================================ FILE: design-patterns/java/observer/ProgressLoggerNaive.java ================================================ public class ProgressLoggerNaive { public void logDataPoint(int steps, int activeMinutes, int calories) { System.out.println("NAIVE Logger: Saving data - Steps: " + steps + ", Active Mins: " + activeMinutes + ", Calories: " + calories); // ... actual database/file logging logic ... } } ================================================ FILE: design-patterns/java/prototype/Enemy.java ================================================ public class Enemy implements EnemyPrototype { private String type; private int health; private double speed; private boolean armored; private String weapon; public Enemy(String type, int health, double speed, boolean armored, String weapon) { this.type = type; this.health = health; this.speed = speed; this.armored = armored; this.weapon = weapon; } @Override public Enemy clone() { return new Enemy(type, health, speed, armored, weapon); } public void setHealth(int health) { this.health = health; } public void printStats() { System.out.println(type + " [Health: " + health + ", Speed: " + speed + ", Armored: " + armored + ", Weapon: " + weapon + "]"); } } ================================================ FILE: design-patterns/java/prototype/EnemyPrototype.java ================================================ public interface EnemyPrototype { EnemyPrototype clone(); } ================================================ FILE: design-patterns/java/prototype/EnemyRegistry.java ================================================ import java.util.HashMap; import java.util.Map; public class EnemyRegistry { private Map prototypes = new HashMap<>(); public void register(String key, Enemy prototype) { prototypes.put(key, prototype); } public Enemy get(String key) { Enemy prototype = prototypes.get(key); if (prototype != null) { return prototype.clone(); } throw new IllegalArgumentException("No prototype registered for: " + key); } } ================================================ FILE: design-patterns/java/prototype/Game.java ================================================ public class Game { public static void main(String[] args) { EnemyRegistry registry = new EnemyRegistry(); // Register prototype enemies registry.register("flying", new Enemy("FlyingEnemy", 100, 12.0, false, "Laser")); registry.register("armored", new Enemy("ArmoredEnemy", 300, 6.0, true, "Cannon")); // Clone from registry Enemy e1 = registry.get("flying"); Enemy e2 = registry.get("flying"); e2.setHealth(80); // this one is damaged Enemy e3 = registry.get("armored"); // Print enemy stats e1.printStats(); e2.printStats(); e3.printStats(); } } ================================================ FILE: design-patterns/java/proxy/HighResolutionImage.java ================================================ public class HighResolutionImage implements Image { private String fileName; private byte[] imageData; // Simulate large data public HighResolutionImage(String fileName) { this.fileName = fileName; loadImageFromDisk(); // Expensive operation! } private void loadImageFromDisk() { System.out.println("Loading image: " + fileName + " from disk (Expensive Operation)..."); // Simulate disk read and memory allocation try { Thread.sleep(2000); // Simulate delay this.imageData = new byte[10 * 1024 * 1024]; // 10MB } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Image " + fileName + " loaded successfully."); } @Override public void display() { System.out.println("Displaying image: " + fileName); // Actual rendering logic would go here } @Override public String getFileName() { return fileName; } } ================================================ FILE: design-patterns/java/proxy/Image.java ================================================ public interface Image { void display(); String getFileName(); } ================================================ FILE: design-patterns/java/proxy/ImageGalleryAppV1.java ================================================ public class ImageGalleryAppV1 { public static void main(String[] args) { System.out.println("Application Started. Initializing images for gallery..."); // Imagine we need to create image objects for a list of thumbnails // Even if the user never clicks them, they get loaded! Image image1 = new HighResolutionImage("photo1.jpg"); Image image2 = new HighResolutionImage("photo2.png"); Image image3 = new HighResolutionImage("photo3.gif"); System.out.println("\nGallery initialized. User might view an image now."); // User clicks on image1 System.out.println("User requests to display " + image1.getFileName()); image1.display(); // User clicks on image3 System.out.println("\nUser requests to display " + image3.getFileName()); image3.display(); // image2 was loaded but never displayed by the user in this session. Waste of resources! System.out.println("\nApplication finished."); } } ================================================ FILE: design-patterns/java/proxy/ImageGalleryAppV2.java ================================================ public class ImageGalleryAppV2 { public static void main(String[] args) { System.out.println("Application Started. Initializing image proxies for gallery..."); // Create lightweight proxies instead of full image objects Image image1 = new ImageProxy("photo1.jpg"); Image image2 = new ImageProxy("photo2.png"); // Never displayed Image image3 = new ImageProxy("photo3.gif"); System.out.println("\nGallery initialized. No images actually loaded yet."); System.out.println("Image 1 Filename: " + image1.getFileName()); // Does not trigger image load // User clicks on image1 System.out.println("\nUser requests to display " + image1.getFileName()); image1.display(); // Lazy loading happens here // User clicks on image1 again System.out.println("\nUser requests to display " + image1.getFileName() + " again."); image1.display(); // Already loaded; no loading delay // User clicks on image3 System.out.println("\nUser requests to display " + image3.getFileName()); image3.display(); // Triggers loading for image3 System.out.println("\nApplication finished. Note: photo2.png was never loaded."); } } ================================================ FILE: design-patterns/java/proxy/ImageProxy.java ================================================ public class ImageProxy implements Image { private String fileName; private HighResolutionImage realImage; // RealSubject public ImageProxy(String fileName) { this.fileName = fileName; System.out.println("ImageProxy: Created for " + fileName + ". Real image not loaded yet."); } @Override public String getFileName() { // Can safely return without loading the image return fileName; } @Override public void display() { // Lazy initialization: Load only when display() is called if (realImage == null) { System.out.println("ImageProxy: display() requested for " + fileName + ". Loading high-resolution image..."); realImage = new HighResolutionImage(fileName); } else { System.out.println("ImageProxy: Using cached high-resolution image for " + fileName); } // Delegate the display call to the real image realImage.display(); } } ================================================ FILE: design-patterns/java/singleton/BillPughSingleton.java ================================================ class BillPughSingleton { // Private constructor to prevent instantiation private BillPughSingleton() {} // Static inner class that holds the instance private static class SingletonHelper { private static final BillPughSingleton INSTANCE = new BillPughSingleton(); } // Public method to get the instance public static BillPughSingleton getInstance() { return SingletonHelper.INSTANCE; } } ================================================ FILE: design-patterns/java/singleton/DoubleCheckedLockingSingleton.java ================================================ class DoubleCheckedSingleton { // The single instance, initially null, marked as volatile private static volatile DoubleCheckedSingleton instance; // Private constructor to prevent instantiation private DoubleCheckedSingleton() {} // Public method to get the instance public static DoubleCheckedSingleton getInstance() { // First check (not synchronized) if (instance == null) { // Synchronize on the class object synchronized (DoubleCheckedSingleton.class) { // Second check (synchronized) if (instance == null) { // Create the instance instance = new DoubleCheckedSingleton(); } } } // Return the instance (either newly created or existing) return instance; } } ================================================ FILE: design-patterns/java/singleton/EagerSingleton.java ================================================ class EagerSingleton { // The single instance, created immediately private static final EagerSingleton instance = new EagerSingleton(); // Private constructor to prevent instantiation private EagerSingleton() {} // Public method to get the instance public static EagerSingleton getInstance() { return instance; } } ================================================ FILE: design-patterns/java/singleton/EnumSingleton.java ================================================ public enum EnumSingleton { INSTANCE; public void doSomething() { // Add any singleton logic here } } ================================================ FILE: design-patterns/java/singleton/LazySingleton.java ================================================ class LazySingleton { // The single instance, initially null private static LazySingleton instance; // Private constructor to prevent instantiation private LazySingleton() {} // Public method to get the instance public static LazySingleton getInstance() { // Check if instance is null if (instance == null) { // If null, create a new instance instance = new LazySingleton(); } // Return the instance (either newly created or existing) return instance; } } ================================================ FILE: design-patterns/java/singleton/StaticBlockSingleton.java ================================================ class StaticBlockSingleton { // The single instance private static StaticBlockSingleton instance; // Private constructor to prevent instantiation private StaticBlockSingleton() {} // Static block for initialization static { try { instance = new StaticBlockSingleton(); } catch (Exception e) { throw new RuntimeException("Exception occurred in creating singleton instance"); } } // Public method to get the instance public static StaticBlockSingleton getInstance() { return instance; } } ================================================ FILE: design-patterns/java/singleton/ThreadSafeSingleton.java ================================================ class ThreadSafeSingleton { // The single instance, initially null private static ThreadSafeSingleton instance; // Private constructor to prevent instantiation private ThreadSafeSingleton() {} // Public method to get the instance, with synchronized keyword public static synchronized ThreadSafeSingleton getInstance() { // Check if instance is null if (instance == null) { // If null, create a new instance instance = new ThreadSafeSingleton(); } // Return the instance (either newly created or existing) return instance; } } ================================================ FILE: design-patterns/java/state/DispensingState.java ================================================ public class DispensingState implements MachineState { @Override public void selectItem(VendingMachine context, String itemCode) { System.out.println("Please wait, dispensing in progress."); } @Override public void insertCoin(VendingMachine context, double amount) { System.out.println("Please wait, dispensing in progress."); } @Override public void dispenseItem(VendingMachine context) { System.out.println("Already dispensing. Please wait."); } } ================================================ FILE: design-patterns/java/state/HasMoneyState.java ================================================ public class HasMoneyState implements MachineState { @Override public void selectItem(VendingMachine context, String itemCode) { System.out.println("Cannot change item after inserting money."); } @Override public void insertCoin(VendingMachine context, double amount) { System.out.println("Money already inserted."); } @Override public void dispenseItem(VendingMachine context) { System.out.println("Dispensing item: " + context.getSelectedItem()); context.setState(new DispensingState()); // Simulate dispensing try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Item dispensed successfully."); context.reset(); } } ================================================ FILE: design-patterns/java/state/IdleState.java ================================================ public class IdleState implements MachineState { @Override public void selectItem(VendingMachine context, String itemCode) { System.out.println("Item selected: " + itemCode); context.setSelectedItem(itemCode); context.setState(new ItemSelectedState()); } @Override public void insertCoin(VendingMachine context, double amount) { System.out.println("Please select an item before inserting coins."); } @Override public void dispenseItem(VendingMachine context) { System.out.println("No item selected. Nothing to dispense."); } } ================================================ FILE: design-patterns/java/state/ItemSelectedState.java ================================================ public class ItemSelectedState implements MachineState { @Override public void selectItem(VendingMachine context, String itemCode) { System.out.println("Item already selected: " + context.getSelectedItem()); } @Override public void insertCoin(VendingMachine context, double amount) { System.out.println("Inserted $" + amount + " for item: " + context.getSelectedItem()); context.setInsertedAmount(amount); context.setState(new HasMoneyState()); } @Override public void dispenseItem(VendingMachine context) { System.out.println("Insert coin before dispensing."); } } ================================================ FILE: design-patterns/java/state/MachineState.java ================================================ public interface MachineState { void selectItem(VendingMachine context, String itemCode); void insertCoin(VendingMachine context, double amount); void dispenseItem(VendingMachine context); } ================================================ FILE: design-patterns/java/state/VendingMachine.java ================================================ public class VendingMachine { private MachineState currentState; private String selectedItem; private double insertedAmount; public VendingMachine() { this.currentState = new IdleState(); // Initial state } public void setState(MachineState newState) { this.currentState = newState; } public void setSelectedItem(String itemCode) { this.selectedItem = itemCode; } public void setInsertedAmount(double amount) { this.insertedAmount = amount; } public String getSelectedItem() { return selectedItem; } public double getInsertedAmount() { return insertedAmount; } public void selectItem(String itemCode) { currentState.selectItem(this, itemCode); } public void insertCoin(double amount) { currentState.insertCoin(this, amount); } public void dispenseItem() { currentState.dispenseItem(this); } public void reset() { this.selectedItem = ""; this.insertedAmount = 0.0; this.currentState = new IdleState(); } } ================================================ FILE: design-patterns/java/state/VendingMachineApp.java ================================================ public class VendingMachineApp { public static void main(String[] args) { VendingMachine vm = new VendingMachine(); vm.insertCoin(1.0); // Invalid in IdleState vm.selectItem("A1"); vm.insertCoin(1.5); vm.dispenseItem(); System.out.println("\n--- Second Transaction ---"); vm.selectItem("B2"); vm.insertCoin(2.0); vm.dispenseItem(); } } ================================================ FILE: design-patterns/java/state/VendingMachineNaive.java ================================================ public class VendingMachineNaive { private enum State { IDLE, ITEM_SELECTED, HAS_MONEY, DISPENSING } private State currentState = State.IDLE; private String selectedItem = ""; private double insertedAmount = 0.0; public void selectItem(String itemCode) { switch (currentState) { case IDLE: selectedItem = itemCode; System.out.println("Item '" + itemCode + "' selected. Please insert coin."); currentState = State.ITEM_SELECTED; break; case ITEM_SELECTED: System.out.println("Item already selected: '" + selectedItem + "'. Insert coin or cancel."); break; case HAS_MONEY: System.out.println("Payment already received for item '" + selectedItem + "'. Dispense in progress."); break; case DISPENSING: System.out.println("Cannot select new item. Currently dispensing."); break; } } public void insertCoin(double amount) { switch (currentState) { case IDLE: System.out.println("No item selected. Please select an item before inserting coins."); break; case ITEM_SELECTED: insertedAmount = amount; System.out.println("Inserted $" + amount + " for item '" + selectedItem + "'. Ready to dispense."); currentState = State.HAS_MONEY; break; case HAS_MONEY: System.out.println("Money already inserted. Please wait or press dispense."); break; case DISPENSING: System.out.println("Currently dispensing. Please wait."); break; } } public void dispenseItem() { switch (currentState) { case IDLE: System.out.println("No item selected. Nothing to dispense."); break; case ITEM_SELECTED: System.out.println("Please insert coin before dispensing."); break; case HAS_MONEY: System.out.println("Dispensing item '" + selectedItem + "'..."); currentState = State.DISPENSING; // Simulate delay and completion try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Item dispensed successfully."); resetMachine(); break; case DISPENSING: System.out.println("Already dispensing. Please wait."); break; } } public void cancelTransaction() { switch (currentState) { case IDLE: System.out.println("Nothing to cancel."); break; case ITEM_SELECTED: System.out.println("Transaction cancelled. Returning to IDLE."); resetMachine(); break; case HAS_MONEY: System.out.println("Transaction cancelled. Refunding $" + insertedAmount + "."); resetMachine(); break; case DISPENSING: System.out.println("Cannot cancel. Item is being dispensed."); break; } } private void resetMachine() { selectedItem = ""; insertedAmount = 0.0; currentState = State.IDLE; } } ================================================ FILE: design-patterns/java/strategy/DistanceBasedShipping.java ================================================ public class DistanceBasedShipping implements ShippingStrategy { private double ratePerKm; public DistanceBasedShipping(double ratePerKm) { this.ratePerKm = ratePerKm; } @Override public double calculateCost(Order order) { System.out.println("Calculating with Distance-Based strategy for zone: " + order.getDestinationZone()); return switch (order.getDestinationZone()) { case "ZoneA" -> ratePerKm * 5.0; case "ZoneB" -> ratePerKm * 7.0; default -> ratePerKm * 10.0; }; } } ================================================ FILE: design-patterns/java/strategy/ECommerceAppV1.java ================================================ public class ECommerceAppV1 { public static void main(String[] args) { ShippingCostCalculatorNaive calculator = new ShippingCostCalculatorNaive(); Order order1 = new Order(); System.out.println("--- Order 1 ---"); calculator.calculateShippingCost(order1, "FLAT_RATE"); calculator.calculateShippingCost(order1, "WEIGHT_BASED"); calculator.calculateShippingCost(order1, "DISTANCE_BASED"); calculator.calculateShippingCost(order1, "THIRD_PARTY_API"); // What if we want to try a new "PremiumZone" strategy? // We have to modify the ShippingCostCalculatorNaive class! } } ================================================ FILE: design-patterns/java/strategy/ECommerceAppV2.java ================================================ public class ECommerceAppV2 { public static void main(String[] args) { Order order1 = new Order(); // Create different strategy instances ShippingStrategy flatRate = new FlatRateShipping(10.0); ShippingStrategy weightBased = new WeightBasedShipping(2.5); ShippingStrategy distanceBased = new DistanceBasedShipping(5.0); ShippingStrategy thirdParty = new ThirdPartyApiShipping(7.5, 0.02); // Create context with an initial strategy ShippingCostService shippingService = new ShippingCostService(flatRate); System.out.println("--- Order 1: Using Flat Rate (initial) ---"); shippingService.calculateShippingCost(order1); System.out.println("\n--- Order 1: Changing to Weight-Based ---"); shippingService.setStrategy(weightBased); shippingService.calculateShippingCost(order1); System.out.println("\n--- Order 1: Changing to Distance-Based ---"); shippingService.setStrategy(distanceBased); shippingService.calculateShippingCost(order1); System.out.println("\n--- Order 1: Changing to Third-Party API ---"); shippingService.setStrategy(thirdParty); shippingService.calculateShippingCost(order1); // Adding a NEW strategy is easy: // 1. Create a new class implementing ShippingStrategy (e.g., FreeShippingStrategy) // 2. Client can then instantiate and use it: // ShippingStrategy freeShipping = new FreeShippingStrategy(); // shippingService.setStrategy(freeShipping); // shippingService.calculateShippingCost(primeMemberOrder); // No modification to ShippingCostService is needed! } } ================================================ FILE: design-patterns/java/strategy/FlatRateShipping.java ================================================ public class FlatRateShipping implements ShippingStrategy { private double rate; public FlatRateShipping(double rate) { this.rate = rate; } @Override public double calculateCost(Order order) { System.out.println("Calculating with Flat Rate strategy ($" + rate + ")"); return rate; } } ================================================ FILE: design-patterns/java/strategy/Order.java ================================================ public class Order { public double getTotalWeight() { return 5.0; /* kg */ } public String getDestinationZone() { return "ZoneA"; } public double getOrderValue() { return 150.0; } // ... other order details } ================================================ FILE: design-patterns/java/strategy/ShippingCostCalculatorNaive.java ================================================ public class ShippingCostCalculatorNaive { public double calculateShippingCost(Order order, String strategyType) { double cost = 0.0; if ("FLAT_RATE".equalsIgnoreCase(strategyType)) { System.out.println("Calculating with Flat Rate strategy."); cost = 10.0; // Fixed $10 } else if ("WEIGHT_BASED".equalsIgnoreCase(strategyType)) { System.out.println("Calculating with Weight-Based strategy."); cost = order.getTotalWeight() * 2.5; // $2.5 per kg } else if ("DISTANCE_BASED".equalsIgnoreCase(strategyType)) { System.out.println("Calculating with Distance-Based strategy."); if ("ZoneA".equals(order.getDestinationZone())) { cost = 5.0; } else if ("ZoneB".equals(order.getDestinationZone())) { cost = 12.0; } else { cost = 20.0; // Default for other zones } } else if ("THIRD_PARTY_API".equalsIgnoreCase(strategyType)) { System.out.println("Calculating with Third-Party API strategy."); // Simulate API call cost = 7.5 + (order.getOrderValue() * 0.02); // Example: base fee + % of order value } else { throw new IllegalArgumentException("Unknown shipping strategy type: " + strategyType); } System.out.println("Calculated Shipping Cost: $" + cost); return cost; } } ================================================ FILE: design-patterns/java/strategy/ShippingCostService.java ================================================ public class ShippingCostService { private ShippingStrategy strategy; // Constructor to set initial strategy public ShippingCostService(ShippingStrategy strategy) { this.strategy = strategy; } // Method to change strategy at runtime public void setStrategy(ShippingStrategy strategy) { System.out.println("ShippingCostService: Strategy changed to " + strategy.getClass().getSimpleName()); this.strategy = strategy; } public double calculateShippingCost(Order order) { if (strategy == null) { throw new IllegalStateException("Shipping strategy not set."); } double cost = strategy.calculateCost(order); // Delegate to the strategy System.out.println("ShippingCostService: Final Calculated Shipping Cost: $" + cost + " (using " + strategy.getClass().getSimpleName() + ")"); return cost; } } ================================================ FILE: design-patterns/java/strategy/ShippingStrategy.java ================================================ public interface ShippingStrategy { double calculateCost(Order order); } ================================================ FILE: design-patterns/java/strategy/ThirdPartyApiShipping.java ================================================ public class ThirdPartyApiShipping implements ShippingStrategy { private final double baseFee; private final double percentageFee; public ThirdPartyApiShipping(double baseFee, double percentageFee) { this.baseFee = baseFee; this.percentageFee = percentageFee; } @Override public double calculateCost(Order order) { System.out.println("Calculating with Third-Party API strategy."); // Simulate API call return baseFee + (order.getOrderValue() * percentageFee); } } ================================================ FILE: design-patterns/java/strategy/WeightBasedShipping.java ================================================ public class WeightBasedShipping implements ShippingStrategy { private final double ratePerKg; public WeightBasedShipping(double ratePerKg) { this.ratePerKg = ratePerKg; } @Override public double calculateCost(Order order) { System.out.println("Calculating with Weight-Based strategy ($" + ratePerKg + "/kg)"); return order.getTotalWeight() * ratePerKg; } } ================================================ FILE: design-patterns/java/templatemethod/AbstractReportExporter.java ================================================ public abstract class AbstractReportExporter { public final void exportReport(ReportData data, String filePath) { prepareData(data); openFile(filePath); writeHeader(data); writeDataRows(data); writeFooter(data); closeFile(filePath); System.out.println("Report exported to " + filePath); } // Hook method – optional for subclasses to override protected void prepareData(ReportData data) { System.out.println("Preparing report data..."); } // Hook method – optional for subclasses to override protected void openFile(String filePath) { System.out.println("Opening file: " + filePath); } protected abstract void writeHeader(ReportData data); protected abstract void writeDataRows(ReportData data); // Hook method – optional for subclasses to override protected void writeFooter(ReportData data) { System.out.println("Writing footer..."); } // Hook method – optional for subclasses to override protected void closeFile(String filePath) { System.out.println("Closing file: " + filePath); } } ================================================ FILE: design-patterns/java/templatemethod/CsvReportExporter.java ================================================ import java.util.Map; public class CsvReportExporter extends AbstractReportExporter { //prepareData() not overridden - default will be used //openFile() not overridden - default will be used @Override protected void writeHeader(ReportData data) { System.out.println("CSV: Writing header: " + String.join(",", data.getHeaders())); } @Override protected void writeDataRows(ReportData data) { System.out.println("CSV: Writing data rows..."); for (Map row : data.getRows()) { System.out.println("CSV: " + row.values()); } } // writeFooter() not overridden - default will be used // closeFile() not overridden - default will be used } ================================================ FILE: design-patterns/java/templatemethod/CsvReportExporterNaive.java ================================================ class CsvReportExporterNaive { public void export(ReportData data, String filePath) { System.out.println("CSV Exporter: Preparing data (common)..."); // ... data preparation logic ... System.out.println("CSV Exporter: Opening file '" + filePath + ".csv' (common)..."); // ... file opening logic ... System.out.println("CSV Exporter: Writing CSV header (specific)..."); // String.join(",", data.getHeaders()); // ... write header to file ... System.out.println("CSV Exporter: Writing CSV data rows (specific)..."); // for (Map row : data.getRows()) { ... format and write row ... } System.out.println("CSV Exporter: Writing CSV footer (if any) (common)..."); System.out.println("CSV Exporter: Closing file '" + filePath + ".csv' (common)..."); // ... file closing logic ... System.out.println("CSV Report exported to " + filePath + ".csv"); } } ================================================ FILE: design-patterns/java/templatemethod/ExcelReportExporter.java ================================================ import java.util.Map; public class ExcelReportExporter extends AbstractReportExporter { //prepareData() not overridden - default will be used //openFile() not overridden - default will be used @Override protected void writeHeader(ReportData data) { System.out.println("Excel: Writing header: " + String.join(",", data.getHeaders())); } @Override protected void writeDataRows(ReportData data) { System.out.println("Excel: Writing data rows..."); for (Map row : data.getRows()) { System.out.println("Excel: " + row.values()); } } // writeFooter() not overridden - default will be used // closeFile() not overridden - default will be used } ================================================ FILE: design-patterns/java/templatemethod/ExcelReportExporterNaive.java ================================================ public class ExcelReportExporterNaive { public void export(ReportData data, String filePath) { System.out.println("Excel Report Exporter: Preparing data..."); // ... data preparation logic ... System.out.println("Excel Report Exporter: Opening file '" + filePath + ".xlsx'..."); // ... file opening logic ... System.out.println("Excel Report Exporter: Writing Excel header..."); // ... Excel header writing logic ... System.out.println("Excel Report Exporter: Writing Excel data rows..."); // ... Excel data rows writing logic ... System.out.println("Excel Report Exporter: Writing Excel footer..."); // ... Excel footer writing logic ... System.out.println("Excel Report Exporter: Closing file '" + filePath + ".xlsx'..."); // ... file closing logic ... } } ================================================ FILE: design-patterns/java/templatemethod/PdfReportExporter.java ================================================ import java.util.Map; public class PdfReportExporter extends AbstractReportExporter { //prepareData() not overridden - default will be used //openFile() not overridden - default will be used @Override protected void writeHeader(ReportData data) { System.out.println("PDF: Writing header: " + String.join(",", data.getHeaders())); } @Override protected void writeDataRows(ReportData data) { System.out.println("PDF: Writing data rows..."); for (Map row : data.getRows()) { System.out.println("PDF: " + row.values()); } } // writeFooter() not overridden - default will be used // closeFile() not overridden - default will be used } ================================================ FILE: design-patterns/java/templatemethod/PdfReportExporterNaive.java ================================================ class PdfReportExporterNaive { public void export(ReportData data, String filePath) { System.out.println("PDF Exporter: Preparing data (common)..."); // ... data preparation logic ... System.out.println("PDF Exporter: Opening file '" + filePath + ".pdf' (common)..."); // ... PDF library specific file opening ... System.out.println("PDF Exporter: Writing PDF header (specific)..."); // ... PDF library specific header writing ... System.out.println("PDF Exporter: Writing PDF data rows (specific)..."); // ... PDF library specific data row writing ... System.out.println("PDF Exporter: Writing PDF footer (if any) (common)..."); System.out.println("PDF Exporter: Closing file '" + filePath + ".pdf' (common)..."); // ... PDF library specific file closing ... System.out.println("PDF Report exported to " + filePath + ".pdf"); } } ================================================ FILE: design-patterns/java/templatemethod/ReportAppNaive.java ================================================ public class ReportAppNaive { public static void main(String[] args) { ReportData reportData = new ReportData(); CsvReportExporterNaive csvExporter = new CsvReportExporterNaive(); csvExporter.export(reportData, "sales_report"); System.out.println(); PdfReportExporterNaive pdfExporter = new PdfReportExporterNaive(); pdfExporter.export(reportData, "financial_summary"); } } ================================================ FILE: design-patterns/java/templatemethod/ReportAppTemplateMethod.java ================================================ public class ReportAppTemplateMethod { public static void main(String[] args) { ReportData reportData = new ReportData(); AbstractReportExporter csvExporter = new CsvReportExporter(); csvExporter.exportReport(reportData, "sales_report"); System.out.println(); AbstractReportExporter pdfExporter = new PdfReportExporter(); pdfExporter.exportReport(reportData, "financial_summary"); } } ================================================ FILE: design-patterns/java/templatemethod/ReportData.java ================================================ import java.util.List; import java.util.Map; import java.util.Arrays; public class ReportData { public List getHeaders() { return Arrays.asList("ID", "Name", "Value"); } public List> getRows() { return Arrays.asList( Map.of("ID", 1, "Name", "Item A", "Value", 100.0), Map.of("ID", 2, "Name", "Item B", "Value", 150.5), Map.of("ID", 3, "Name", "Item C", "Value", 75.25) ); } } ================================================ FILE: design-patterns/java/visitor/AreaCalculatorVisitor.java ================================================ public class AreaCalculatorVisitor implements ShapeVisitor { @Override public void visitCircle(Circle circle) { double area = Math.PI * circle.getRadius() * circle.getRadius(); System.out.println("Area of Circle: " + area); } @Override public void visitRectangle(Rectangle rectangle) { double area = rectangle.getWidth() * rectangle.getHeight(); System.out.println("Area of Rectangle: " + area); } } ================================================ FILE: design-patterns/java/visitor/Circle.java ================================================ public class Circle implements Shape { private final double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } @Override public void accept(ShapeVisitor visitor) { visitor.visitCircle(this); } } ================================================ FILE: design-patterns/java/visitor/Rectangle.java ================================================ public class Rectangle implements Shape { private final double width; private final double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public double getHeight() { return height; } @Override public void accept(ShapeVisitor visitor) { visitor.visitRectangle(this); } } ================================================ FILE: design-patterns/java/visitor/Shape.java ================================================ public interface Shape { void accept(ShapeVisitor visitor); } ================================================ FILE: design-patterns/java/visitor/ShapeVisitor.java ================================================ public interface ShapeVisitor { void visitCircle(Circle circle); void visitRectangle(Rectangle rectangle); } ================================================ FILE: design-patterns/java/visitor/SvgExporterVisitor.java ================================================ public class SvgExporterVisitor implements ShapeVisitor { @Override public void visitCircle(Circle circle) { System.out.println(""); } @Override public void visitRectangle(Rectangle rectangle) { System.out.println(""); } } ================================================ FILE: design-patterns/java/visitor/VisitorPatternDemo.java ================================================ public class VisitorPatternDemo { public static void main(String[] args) { List shapes = List.of( new Circle(5), new Rectangle(10, 4), new Circle(2.5) ); System.out.println("=== Calculating Areas ==="); ShapeVisitor areaCalculator = new AreaCalculatorVisitor(); for (Shape shape : shapes) { shape.accept(areaCalculator); } System.out.println("\n=== Exporting to SVG ==="); ShapeVisitor svgExporter = new SvgExporterVisitor(); for (Shape shape : shapes) { shape.accept(svgExporter); } } } ================================================ FILE: design-patterns/python/README.md ================================================ # Design Patterns in Python This directory contains Python implementations of various design patterns, following the same examples and structure as the Java implementations. ## Implemented Patterns ### Creational Patterns - **[Adapter Pattern](adapter/)** - Convert interface of a class into another interface - **[Factory Method Pattern](factory/)** - Create objects without specifying exact classes - **[Builder Pattern](builder/)** - Construct complex objects step by step - **[Singleton Pattern](singleton/)** - Ensure only one instance of a class exists ### Behavioral Patterns - **[Observer Pattern](observer/)** - Define one-to-many dependency between objects - **[Strategy Pattern](strategy/)** - Define family of algorithms and make them interchangeable ### Structural Patterns - **Abstract Factory Pattern** - Create families of related objects - **Bridge Pattern** - Separate abstraction from implementation - **Composite Pattern** - Compose objects into tree structures - **Decorator Pattern** - Add behavior to objects dynamically - **Facade Pattern** - Provide simplified interface to complex subsystem - **Flyweight Pattern** - Minimize memory usage with shared objects - **Proxy Pattern** - Provide placeholder/surrogate for another object ### Additional Behavioral Patterns - **Chain of Responsibility** - Pass requests along handler chain - **Command Pattern** - Encapsulate requests as objects - **Iterator Pattern** - Access elements sequentially without exposing structure - **Mediator Pattern** - Define how objects interact with each other - **Memento Pattern** - Capture and restore object state - **State Pattern** - Allow object to alter behavior when state changes - **Template Method Pattern** - Define skeleton of algorithm in base class - **Visitor Pattern** - Define new operations without changing classes ## Running the Examples Each pattern directory contains demo files that can be run independently: ```bash # Run adapter pattern demo python -m design-patterns.python.adapter.ecommerce_app # Run factory pattern demo python -m design-patterns.python.factory.factory_method_demo # Run builder pattern demo python -m design-patterns.python.builder.http_app_builder # Run singleton pattern demo python -m design-patterns.python.singleton.singleton_demo # Run observer pattern demo python -m design-patterns.python.observer.fitness_app_observer_demo # Run strategy pattern demo python -m design-patterns.python.strategy.ecommerce_app_demo ``` ## Key Features - **Same Examples**: Uses identical examples as Java implementations for consistency - **Pythonic Code**: Follows Python conventions and best practices - **Type Hints**: Includes type annotations for better code clarity - **Separate Files**: Each class is in its own file for better organization - **Abstract Base Classes**: Uses ABC for interfaces and abstract classes - **Documentation**: Comprehensive docstrings and comments ## Pattern Structure Each pattern follows this structure: ``` pattern_name/ ├── __init__.py ├── interface_or_abstract.py # Abstract base classes/interfaces ├── concrete_implementations.py # Concrete classes ├── context_or_client.py # Context classes or clients ├── demo.py # Demonstration of the pattern └── README.md # Pattern-specific documentation ``` ## Design Principles Demonstrated - **Open/Closed Principle**: Open for extension, closed for modification - **Dependency Inversion**: Depend on abstractions, not concretions - **Single Responsibility**: Each class has one reason to change - **Composition over Inheritance**: Favor object composition - **Encapsulation**: Hide implementation details behind interfaces ## Contributing When adding new patterns or modifying existing ones: 1. Follow the existing file structure and naming conventions 2. Include comprehensive type hints 3. Add detailed docstrings 4. Create meaningful demo examples 5. Maintain consistency with Java implementations 6. Include README documentation for each pattern ================================================ FILE: design-patterns/python/adapter/README.md ================================================ # Adapter Design Pattern in Python ## Problem Statement The Adapter pattern allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces by converting the interface of one class into another interface that clients expect. --- ## Core Components ### 1. Target Interface (PaymentProcessor) ```python class PaymentProcessor(ABC): @abstractmethod def process_payment(self, amount: float, currency: str) -> None: pass ``` ### 2. Adaptee (LegacyGateway) ```python class LegacyGateway: def make_payment(self, currency: str, amount: float) -> None: # Legacy payment processing logic pass ``` ### 3. Adapter (LegacyGatewayAdapter) ```python class LegacyGatewayAdapter(PaymentProcessor): def __init__(self, legacy_gateway: LegacyGateway): self.legacy_gateway = legacy_gateway def process_payment(self, amount: float, currency: str) -> None: self.legacy_gateway.make_payment(currency, amount) ``` ### 4. Client (CheckoutService) ```python class CheckoutService: def __init__(self, payment_processor: PaymentProcessor): self.payment_processor = payment_processor def checkout(self, amount: float, currency: str) -> None: self.payment_processor.process_payment(amount, currency) ``` --- ## Example Usage ```python def main(): # Using the in-house payment processor in_house_processor = InHousePaymentProcessor() checkout_service = CheckoutService(in_house_processor) checkout_service.checkout(100, "USD") # Using the legacy payment gateway through adapter legacy_processor = LegacyGatewayAdapter(LegacyGateway()) checkout_service = CheckoutService(legacy_processor) checkout_service.checkout(100, "USD") ``` --- ## Benefits 1. **Single Responsibility Principle:** - Separates the interface conversion logic from the business logic - Each class has a single responsibility 2. **Open/Closed Principle:** - New adapters can be added without modifying existing code - System remains open for extension but closed for modification 3. **Reusability:** - Existing classes can be reused with new interfaces - Reduces code duplication 4. **Flexibility:** - Multiple adapters can be created for different purposes - Easy to switch between different implementations --- ## When to Use 1. **When integrating incompatible interfaces:** - Working with legacy systems - Using third-party libraries - Migrating between different versions 2. **When creating a reusable class:** - The class needs to work with unrelated classes - The class needs to work with classes that don't have compatible interfaces 3. **When implementing multiple interfaces:** - A class needs to implement multiple interfaces - Different clients need different views of the same class --- ## Best Practices 1. **Keep it Simple:** - Adapters should be simple and focused - Avoid adding unnecessary functionality 2. **Documentation:** - Clearly document the purpose of the adapter - Explain the conversion logic 3. **Testing:** - Test the adapter thoroughly - Ensure it works with both the target and adaptee 4. **Error Handling:** - Handle conversion errors gracefully - Provide meaningful error messages --- ## Common Pitfalls 1. **Over-engineering:** - Creating adapters when not needed - Adding unnecessary complexity 2. **Tight Coupling:** - Creating dependencies between adapters - Making the system less flexible 3. **Performance Issues:** - Adding too many layers of adaptation - Impacting system performance --- ================================================ FILE: oop/cpp/abstraction/README.md ================================================ # Abstraction in C++ ## Introduction **Abstraction** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows you to hide **implementation details** while exposing only the necessary parts of an object. This helps in reducing complexity and increasing maintainability. Abstraction in C++ is mainly achieved using: 1. **Abstract Classes** 2. **Interfaces (Pure Virtual Functions)** --- ## **What is Abstraction?** **Abstraction** means showing only the **essential details** and hiding the **implementation**. It allows programmers to focus on **what an object does** rather than **how it does it**. ### **Key Benefits of Abstraction** - **Reduces complexity**: Hides unnecessary implementation details. - **Increases code reusability**: Encourages the reuse of abstracted logic. - **Enhances security**: Protects internal object details from unintended modifications. - **Improves maintainability**: Makes code easier to manage and update. --- ## **1. Abstraction Using Abstract Classes** An **abstract class** in C++ is a class that **cannot be instantiated**. It is used to define common behavior that multiple subclasses should implement. ### **Example: Abstract Class in C++** ```cpp #include #include using namespace std; // Abstract class class Vehicle { protected: string brand; public: Vehicle(string b) : brand(b) {} virtual void start() = 0; // Pure virtual function virtual ~Vehicle() = default; // virtual destructor void displayBrand() { cout << "Brand: " << brand << endl; } }; // Subclass implementing the abstract method class Car : public Vehicle { public: Car(string b) : Vehicle(b) {} void start() override { cout << "Car is starting..." << endl; } }; int main() { unique_ptr myCar = make_unique("Toyota"); myCar->displayBrand(); myCar->start(); return 0; } ``` ### **Output:** ``` Brand: Toyota Car is starting... ``` **Why Use Abstract Classes?** - Allows defining common behavior that subclasses must implement. - Enables partial abstraction (can have both abstract and concrete methods). - Prevents direct instantiation of base classes. --- ## **2. Abstraction Using Interfaces (Pure Virtual Functions)** An **interface** in C++ is created using a class that contains **only pure virtual functions**. ### **Example: Interface in C++** ```cpp #include #include using namespace std; // Defining an interface class Animal { public: virtual ~Animal() = default; // virtual destructor virtual void makeSound() = 0; // Pure virtual function }; // Implementing the interface in Dog class class Dog : public Animal { public: void makeSound() override { cout << "Dog barks" << endl; } }; // Implementing the interface in Cat class class Cat : public Animal { public: void makeSound() override { cout << "Cat meows" << endl; } }; int main() { unique_ptr myDog = make_unique(); myDog->makeSound(); unique_ptr myCat = make_unique(); myCat->makeSound(); return 0; } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Interfaces?** - Promotes **full abstraction** (hides all implementation details). - Supports **multiple inheritance** in C++. - Provides a standard way for different classes to implement behaviors. --- ## **Abstract Class vs Interface: Key Differences** | Feature | Abstract Class | Interface (Pure Virtual Functions) | |---------|---------------|----------------------------------| | Methods | Can have abstract and concrete methods | Only pure virtual methods | | Fields | Can have member variables | Should not have data members | | Constructor | Can have constructors | Cannot have constructors | | Multiple Inheritance | Not recommended | Supported | | Access Modifiers | Can have private, protected, public members | Methods are public by default | --- ## **Real-World Example: Payment System** Abstraction is widely used in real-world applications, such as payment processing. ### **Example: Payment System with Abstraction** ```cpp #include #include using namespace std; // Abstract class for Payment class Payment { protected: double amount; public: Payment(double amt) : amount(amt) {} virtual ~Payment() = default; // virtual destructor virtual void pay() = 0; // Abstract method }; // Implementing payment methods class CreditCardPayment : public Payment { public: CreditCardPayment(double amt) : Payment(amt) {} void pay() override { cout << "Paid " << amount << " using Credit Card" << endl; } }; class PayPalPayment : public Payment { public: PayPalPayment(double amt) : Payment(amt) {} void pay() override { cout << "Paid " << amount << " using PayPal" << endl; } }; int main() { unique_ptr payment; payment = make_unique(150.75); payment->pay(); payment = make_unique(200.50); payment->pay(); return 0; } ``` ### **Output:** ``` Paid 150.75 using Credit Card Paid 200.50 using PayPal ``` **Why Use Abstraction in Payment Systems?** - Allows multiple payment methods without modifying existing code. - Improves maintainability and scalability. - Provides a **common contract** for different payment types. ================================================ FILE: oop/cpp/aggregation/README.md ================================================ # Aggregation in C++ ## Introduction Aggregation is a key concept in object-oriented programming (OOP) that represents a "has-a" relationship between two classes, but with a crucial distinction: the lifecycle of the contained object is independent of the container object. This means that while one class contains another, the contained object can exist independently of the container. Aggregation allows for better modularity, code reuse, and maintainability. It is different from composition, where the contained object cannot exist without the container. ## What is Aggregation? Aggregation is a form of association in OOP where an object of one class contains a reference to an object of another class. However, the contained object can exist independently of the container. This means that even if the container object is destroyed, the contained object can still be used elsewhere in the application. ### Key Characteristics of Aggregation: - Represents a **has-a** relationship. - The contained object **can exist independently** of the container. - Implemented using references (pointers) to objects. - Promotes **loose coupling** between objects. ### Example: A University and its Professors Consider a scenario where a `University` contains multiple `Professor` objects. However, a `Professor` can exist independently of any university. This is an example of aggregation. ```cpp #include #include #include using namespace std; class Professor { private: string name; string subject; public: Professor(string name, string subject) : name(name), subject(subject) {} void teach() { cout << name << " is teaching " << subject << endl; } string getName() { return name; } }; class University { private: string universityName; vector professors; // Aggregation: University has a list of professors public: University(string name) : universityName(name) {} void addProfessor(Professor* professor) { professors.push_back(professor); } void showProfessors() { cout << "Professors at " << universityName << ":" << endl; for (auto professor : professors) { cout << " - " << professor->getName() << endl; } } }; int main() { Professor prof1("Dr. Smith", "Computer Science"); Professor prof2("Dr. Johnson", "Mathematics"); University university("Harvard University"); university.addProfessor(&prof1); university.addProfessor(&prof2); university.showProfessors(); // Professors can exist independently prof1.teach(); prof2.teach(); return 0; } ``` ### Output: ``` Professors at Harvard University: - Dr. Smith - Dr. Johnson Dr. Smith is teaching Computer Science Dr. Johnson is teaching Mathematics ``` --- ## Aggregation vs Composition | Feature | Aggregation | Composition | |--------------|------------|-------------| | Relationship | "Has-a" | "Has-a" | | Ownership | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | University and Professors | Car and Engine | --- ## Why Use Aggregation? ### 1. **Promotes Code Reusability** - Aggregated objects can be used in multiple places without being tightly coupled to a single container class. ### 2. **Encourages Loose Coupling** - Aggregation allows objects to interact without being dependent on the lifecycle of each other. ### 3. **Better Maintainability** - Changes in one class do not heavily impact the other, making the codebase easier to modify and extend. ### 4. **Real-World Applicability** - Many real-world relationships, such as a school and its teachers, a company and its employees, naturally fit the aggregation model. --- ## Aggregation with Interfaces (Abstract Classes) Using abstract classes, we can further enhance the flexibility of aggregation. ```cpp #include #include #include using namespace std; class Teachable { public: virtual void teach() = 0; // Pure virtual function virtual string getName() = 0; }; class Professor : public Teachable { private: string name; string subject; public: Professor(string name, string subject) : name(name), subject(subject) {} void teach() override { cout << name << " is teaching " << subject << endl; } string getName() override { return name; } }; class University { private: string universityName; vector professors; public: University(string name) : universityName(name) {} void addProfessor(Teachable* professor) { professors.push_back(professor); } void showProfessors() { cout << "Professors at " << universityName << ":" << endl; for (auto professor : professors) { professor->teach(); } } }; int main() { Professor prof1("Dr. Adams", "Physics"); Professor prof2("Dr. Lee", "Chemistry"); University university("MIT"); university.addProfessor(&prof1); university.addProfessor(&prof2); university.showProfessors(); return 0; } ``` ### Output: ``` Professors at MIT: Dr. Adams is teaching Physics Dr. Lee is teaching Chemistry ``` --- ## When to Use Aggregation? - When an object **can exist independently** from the container. - When designing **loosely coupled** systems. - When different objects need to be **shared** across multiple containers. - When following **SOLID principles**, particularly the **Dependency Inversion Principle (DIP)**. ================================================ FILE: oop/cpp/association/README.md ================================================ # Association in C++ ## Introduction Association is a key concept in object-oriented programming (OOP) that defines a relationship between two or more objects. It represents how objects interact with each other while maintaining their independence. Association is **not inheritance**—rather, it is a relationship between objects that allows communication while ensuring they remain loosely coupled. ## What is Association? Association defines a connection between two classes, where one class is linked to another. The association can be **one-to-one**, **one-to-many**, **many-to-one**, or **many-to-many**. Objects in an association can exist independently of each other. ### Key Characteristics of Association: - Represents a **uses-a** or **knows-a** relationship. - Objects in an association **can exist independently**. - Can be **unidirectional** or **bidirectional**. - Promotes **modularity** and **code reusability**. ### Example: A Student and a Teacher A `Student` can be associated with multiple `Teacher` objects, and a `Teacher` can have multiple `Student` objects. This represents a **many-to-many** association. ```cpp #include #include #include using namespace std; class Student; class Teacher { private: string name; vector students; public: Teacher(string name) : name(name) {} void addStudent(Student* student); void showStudents(); string getName() { return name; } }; class Student { private: string name; public: Student(string name) : name(name) {} string getName() { return name; } }; void Teacher::addStudent(Student* student) { students.push_back(student); } void Teacher::showStudents() { cout << name << " teaches:" << endl; for (Student* student : students) { cout << " - " << student->getName() << endl; } } int main() { Teacher teacher1("Mr. Smith"); Teacher teacher2("Mrs. Johnson"); Student student1("Alice"); Student student2("Bob"); teacher1.addStudent(&student1); teacher1.addStudent(&student2); teacher2.addStudent(&student2); teacher1.showStudents(); teacher2.showStudents(); return 0; } ``` ### Output: ``` Mr. Smith teaches: - Alice - Bob Mrs. Johnson teaches: - Bob ``` --- ## Types of Association ### 1. **One-to-One Association** - Each object of class A is associated with one object of class B. - Example: A `Person` has one `Passport`. ### 2. **One-to-Many Association** - One object of class A can be associated with multiple objects of class B. - Example: A `Teacher` teaches multiple `Students`. ### 3. **Many-to-One Association** - Multiple objects of class A can be associated with one object of class B. - Example: Multiple `Students` belong to one `School`. ### 4. **Many-to-Many Association** - Multiple objects of class A can be associated with multiple objects of class B. - Example: `Teachers` and `Students` (a student can have multiple teachers, and a teacher can have multiple students). --- ## Why Use Association? ### 1. **Promotes Code Reusability** - Objects can be reused across multiple associations without duplication. ### 2. **Encourages Loose Coupling** - Objects interact without depending on the internal implementation of each other. ### 3. **Improves Maintainability** - Changing one object does not heavily impact others, making code easier to manage. ### 4. **Better System Design** - Allows modeling of real-world relationships between entities effectively. --- ## Bidirectional Association Associations can be **unidirectional** (one object knows about another) or **bidirectional** (both objects know about each other). ### Example: A Library and Books (Bidirectional Association) ```cpp #include #include #include using namespace std; class Library; class Book { private: string title; Library* library; public: Book(string title, Library* library); void showLibrary(); string getTitle() { return title; } }; class Library { private: string name; vector books; public: Library(string name) : name(name) {} void addBook(Book* book) { books.push_back(book); } string getName() { return name; } void showBooks(); }; Book::Book(string title, Library* library) : title(title), library(library) {} void Book::showLibrary() { cout << title << " is in " << library->getName() << endl; } void Library::showBooks() { cout << "Books in " << name << ":" << endl; for (Book* book : books) { cout << " - " << book->getTitle() << endl; } } int main() { Library library("City Library"); Book book1("1984", &library); Book book2("Brave New World", &library); library.addBook(&book1); library.addBook(&book2); library.showBooks(); book1.showLibrary(); book2.showLibrary(); return 0; } ``` ### Output: ``` Books in City Library: - 1984 - Brave New World 1984 is in City Library Brave New World is in City Library ``` ================================================ FILE: oop/cpp/classesandobjects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? A class is a blueprint or template. It defines the attributes (fields) and behaviors (methods) of an object. ### Defining a Class in C++ To define a class in C++, you use the `class` keyword followed by the name of the class. Here's a simple example: ```cpp #include using namespace std; class Car { // Attributes private: string color; string make; string model; int year; public: // Constructor Car(string color, string make, string model, int year) { this->color = color; this->make = make; this->model = model; this->year = year; } // Method to display car details void displayInfo() { cout << "Car Make: " << make << endl; cout << "Car Model: " << model << endl; cout << "Car Year: " << year << endl; cout << "Car Color: " << color << endl; } }; ``` - **Attributes**: The class `Car` has four attributes that describe its state: `color`, `make`, `model`, and `year`. - **Constructor**: The constructor `Car(string color, string make, string model, int year)` initializes new objects of the class. - **Methods**: The `displayInfo` method is responsible for showcasing the car details. ## What is an Object? An object is an instance of a class. When you create an object, you are bringing the blueprint of the class into reality. It consists of state and behavior defined by the class, with each object holding its own copy of the data. ### Creating Objects in C++ To create an object, you use the class constructor. Here's how you can instantiate objects from the `Car` class: ```cpp int main() { // Creating an object of the Car class Car car1 = Car("Red", "Toyota", "Corolla", 2020); Car car2 = Car("Blue", "Ford", "Mustang", 2021); // Displaying information of each car car1.displayInfo(); cout << "-----------------"; car2.displayInfo(); return 0; } ``` 1. **Instantiation**: The `Car` constructor is used to create an object, which allocates memory for it. 2. **Initialization**: The constructor (`Car`) initializes the object state with given parameters. 3. **Reference**: The object is referenced through a variable (`car1`, `car2`) that points to its memory location. ================================================ FILE: oop/cpp/composition/README.md ================================================ # Composition in C++ ## Introduction Composition is one of the key concepts of object-oriented programming (OOP). It allows objects to be built using other objects, promoting code reuse, flexibility, and better maintainability. Unlike inheritance, which establishes an "is-a" relationship, composition represents a "has-a" relationship. ## What is Composition? Composition is a design principle in OOP where one class contains an instance (or instances) of another class as a field. The contained class is often called a component, and the containing class is referred to as a composite class. This helps in building complex systems by combining simpler objects. ### Example: A Car and its Components Consider a `Car` that consists of multiple components like an `Engine`, `Wheel`, and `Transmission`. Instead of inheriting from these components, a `Car` object will contain them as fields. ```cpp #include #include class Engine { private: int horsepower; public: Engine(int hp) : horsepower(hp) {} void start() { std::cout << "Engine started with " << horsepower << " HP." << std::endl; } }; class Wheel { private: std::string type; public: Wheel(std::string t) : type(t) {} void rotate() { std::cout << "The " << type << " wheel is rotating." << std::endl; } }; class Transmission { private: std::string type; public: Transmission(std::string t) : type(t) {} void shiftGear() { std::cout << "Transmission shifted: " << type << std::endl; } }; class Car { private: Engine engine; Wheel wheel; Transmission transmission; public: Car() : engine(150), wheel("Alloy"), transmission("Automatic") {} void drive() { engine.start(); wheel.rotate(); transmission.shiftGear(); std::cout << "Car is moving!" << std::endl; } }; int main() { Car car; car.drive(); return 0; } ``` ### Output: ``` Engine started with 150 HP. The Alloy wheel is rotating. Transmission shifted: Automatic Car is moving! ``` --- ## Why Prefer Composition Over Inheritance? ### 1. **Encapsulation and Flexibility** - Composition allows us to change the behavior of an object dynamically by replacing components at runtime. - Inheritance makes it difficult to modify an existing class hierarchy without breaking existing code. ### 2. **Better Code Reusability** - Composition promotes reusable components. The `Engine`, `Wheel`, and `Transmission` classes can be used in multiple types of vehicles (Car, Bike, Truck) without modification. ### 3. **Avoids Inheritance Pitfalls** - Inheritance can lead to deep class hierarchies, making maintenance difficult. - It enforces strict parent-child relationships, which can be too rigid for some designs. ### 4. **Supports Interface-Based Design** - Composition can be combined with abstract classes to achieve powerful decoupling. --- ## Composition with Abstract Classes Using abstract classes with composition allows for greater flexibility and loose coupling. ```cpp #include using namespace std; class Engine { public: virtual void start() = 0; // Pure virtual function }; class PetrolEngine : public Engine { public: void start() override { cout << "Petrol Engine started." << endl; } }; class DieselEngine : public Engine { public: void start() override { cout << "Diesel Engine started." << endl; } }; class Car { private: Engine* engine; public: Car(Engine* e) : engine(e) {} void startCar() { engine->start(); cout << "Car is ready to go!" << endl; } }; int main() { PetrolEngine petrolEngine; DieselEngine dieselEngine; Car petrolCar(&petrolEngine); petrolCar.startCar(); Car dieselCar(&dieselEngine); dieselCar.startCar(); return 0; } ``` ### Output: ``` Petrol Engine started. Car is ready to go! Diesel Engine started. Car is ready to go! ``` --- ## When to Use Composition? - When building complex objects that consist of multiple components. - When you want to achieve **code reusability** without rigid inheritance hierarchies. - When different behaviors need to be swapped dynamically (e.g., using different types of engines in a vehicle). - When following the **favor composition over inheritance** principle. ================================================ FILE: oop/cpp/encapsulation/README.md ================================================ # Encapsulation in C++ ## Introduction **Encapsulation** is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the practice of **bundling data (variables) and methods** that operate on that data into a single unit (class) while restricting direct access to the internal details. Encapsulation in C++ is achieved using: 1. **Access Specifiers** (`private`, `protected`, `public`) 2. **Getters and Setters** 3. **Data Hiding** Encapsulation helps in **data protection, modularity, and maintainability** of the code. ## **What is Encapsulation?** Encapsulation means **wrapping** the data (variables) and code (methods) together into a single unit (class). It restricts direct access to some of an object's components, which helps protect data integrity and prevents unintended modifications. ### **Key Benefits of Encapsulation** - **Data Hiding**: Prevents direct access to sensitive data. - **Increased Security**: Controls how data is accessed and modified. - **Improved Code Maintainability**: Allows changes without affecting other parts of the code. - **Better Modularity**: Organizes the code into logical components. --- ## **Encapsulation Using Access Specifiers** C++ provides **access specifiers** to enforce encapsulation: - **`private`**: Accessible only within the same class. - **`protected`**: Accessible within the same class and derived classes. - **`public`**: Accessible from anywhere. ### **Example: Encapsulation with Private Variables** ```cpp #include using namespace std; // Class with encapsulated data class BankAccount { private: string accountHolder; double balance; public: // Constructor BankAccount(string name, double bal) { accountHolder = name; balance = bal; } // Getter method to access balance double getBalance() { return balance; } // Setter method to modify balance void deposit(double amount) { if (amount > 0) { balance += amount; cout << "Deposited: " << amount << endl; } else { cout << "Invalid deposit amount" << endl; } } }; int main() { BankAccount account("Alice", 1000); cout << "Current Balance: " << account.getBalance() << endl; account.deposit(500); cout << "Updated Balance: " << account.getBalance() << endl; return 0; } ``` ### **Output:** ``` Current Balance: 1000 Deposited: 500 Updated Balance: 1500 ``` **Why Use Encapsulation?** - Prevents unauthorized access to the data. - Allows controlled modifications through methods. --- ## **Encapsulation Using Getters and Setters** Encapsulation ensures that **data cannot be directly accessed** but must be retrieved or modified through methods. ### **Example: Getters and Setters in C++** ```cpp #include using namespace std; class Employee { private: string name; int age; public: // Getter method string getName() { return name; } // Setter method void setName(string newName) { name = newName; } int getAge() { return age; } void setAge(int newAge) { if (newAge > 18) { age = newAge; } else { cout << "Age must be greater than 18" << endl; } } }; int main() { Employee emp; emp.setName("John Doe"); emp.setAge(25); cout << "Employee Name: " << emp.getName() << endl; cout << "Employee Age: " << emp.getAge() << endl; return 0; } ``` ### **Output:** ``` Employee Name: John Doe Employee Age: 25 ``` --- ## **Encapsulation and Data Hiding** Encapsulation helps **hide implementation details** while exposing only necessary methods. ### **Example: Hiding Implementation Details** ```cpp #include using namespace std; class Account { private: double balance; bool validateWithdrawal(double amount) { return amount > 0 && amount <= balance; } public: Account(double initialBalance) { balance = initialBalance; } void withdraw(double amount) { if (validateWithdrawal(amount)) { balance -= amount; cout << "Withdrawal Successful: " << amount << endl; } else { cout << "Insufficient balance or invalid amount" << endl; } } double getBalance() { return balance; } }; int main() { Account myAccount(1000); myAccount.withdraw(300); cout << "Remaining Balance: " << myAccount.getBalance() << endl; return 0; } ``` ### **Output:** ``` Withdrawal Successful: 300 Remaining Balance: 700 ``` **Why Hide Data?** - Prevents direct modification of important fields. - Ensures data integrity by validating inputs. --- ## **Encapsulation in Real-World Applications** Encapsulation is used in many real-world applications such as: 1. **Banking Systems** - Ensuring account details are private. 2. **Healthcare Applications** - Protecting patient records. 3. **E-Commerce Platforms** - Hiding payment processing details. ### **Example: Encapsulation in Payment Processing** ```cpp #include using namespace std; class PaymentProcessor { private: string cardNumber; double amount; string maskCardNumber(string cardNumber) { return "****-****-****-" + cardNumber.substr(cardNumber.length() - 4); } public: PaymentProcessor(string card, double amt) : cardNumber(card), amount(amt) {} void processPayment() { cout << "Processing payment of " << amount << " for card " << maskCardNumber(cardNumber) << endl; } }; int main() { PaymentProcessor payment("1234567812345678", 250.00); payment.processPayment(); return 0; } ``` ### **Output:** ``` Processing payment of 250 for card ****-****-****-5678 ``` **Why Use Encapsulation in Payment Processing?** - Protects sensitive data (e.g., credit card numbers). - Hides unnecessary details from users. - Ensures secure transactions. ================================================ FILE: oop/cpp/inheritance/README.md ================================================ # Inheritance in C++ ## Introduction **Inheritance** is one of the core principles of Object-Oriented Programming (OOP). It allows a class (subclass or child class) to acquire the properties and behaviors of another class (superclass or parent class). This promotes **code reuse**, **scalability**, and **maintainability**. --- ## **What is Inheritance?** **Inheritance** is a mechanism where a child class derives properties and behaviors from a parent class. The child class can: - Use the fields and methods of the parent class - Override parent class methods to provide a specific implementation - Add its own additional properties and methods ### **Key Benefits of Inheritance** - **Code Reusability**: Avoids code duplication by reusing fields and methods of the parent class. - **Improves Maintainability**: Reduces redundancy, making code easier to manage. - **Enhances Extensibility**: New functionality can be added easily without modifying existing code. --- ## **How to Implement Inheritance in C++** ### **Step 1: Create a Parent Class** The parent class contains common fields and methods. ```cpp #include using namespace std; // Parent class class Animal { public: string name; void eat() { cout << name << " is eating..." << endl; } }; ``` ### **Step 2: Create a Child Class using `public` Inheritance** The child class inherits the properties and methods of the parent class. ```cpp // Child class class Dog : public Animal { public: void bark() { cout << name << " is barking..." << endl; } }; ``` ### **Step 3: Use the Child Class** Now, let's create an object and use the inherited methods. ```cpp int main() { Dog myDog; myDog.name = "Buddy"; myDog.eat(); // Inherited from Animal class myDog.bark(); // Defined in Dog class return 0; } ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Types of Inheritance in C++** C++ supports different types of inheritance: ### **1. Single Inheritance** A subclass inherits from one superclass. ```cpp class Parent { public: void show() { cout << "This is the parent class" << endl; } }; class Child : public Parent { public: void display() { cout << "This is the child class" << endl; } }; ``` ### **2. Multilevel Inheritance** A subclass inherits from another subclass, forming a chain. ```cpp class Grandparent { public: void show() { cout << "Grandparent class" << endl; } }; class Parent : public Grandparent { public: void display() { cout << "Parent class" << endl; } }; class Child : public Parent { public: void print() { cout << "Child class" << endl; } }; ``` ### **3. Hierarchical Inheritance** A single parent class has multiple child classes. ```cpp class Parent { public: void show() { cout << "Parent class" << endl; } }; class Child1 : public Parent { public: void display() { cout << "Child1 class" << endl; } }; class Child2 : public Parent { public: void print() { cout << "Child2 class" << endl; } }; ``` ### **4. Multiple Inheritance** (Supported in C++) Unlike Java, C++ allows a child class to inherit from multiple parent classes. ```cpp class Parent1 { public: void show1() { cout << "Parent1 class" << endl; } }; class Parent2 { public: void show2() { cout << "Parent2 class" << endl; } }; class Child : public Parent1, public Parent2 { }; ``` --- ## **Method Overriding in Inheritance** Method overriding allows a child class to **redefine** a method from the parent class. ```cpp class Animal { public: virtual void makeSound() { cout << "Animal makes a sound" << endl; } }; class Dog : public Animal { public: void makeSound() override { cout << "Dog barks" << endl; } }; ``` ### **Usage** ```cpp int main() { Animal* myAnimal = new Dog(); // Polymorphism myAnimal->makeSound(); delete myAnimal; return 0; } ``` ### **Output:** ``` Dog barks ``` --- ## **The `super` Equivalent: Using `Base Class` Constructor in C++** C++ uses the **constructor of the base class** to initialize inherited fields. ```cpp class Animal { public: Animal() { cout << "Animal Constructor" << endl; } void makeSound() { cout << "Animal makes a sound" << endl; } }; class Dog : public Animal { public: Dog() { cout << "Dog Constructor" << endl; } void makeSound() { Animal::makeSound(); // Calls parent method cout << "Dog barks" << endl; } }; ``` ### **Usage** ```cpp int main() { Dog myDog; myDog.makeSound(); return 0; } ``` ### **Output:** ``` Animal Constructor Dog Constructor Animal makes a sound Dog barks ``` ================================================ FILE: oop/cpp/interfaces/README.md ================================================ # Interfaces in C++ ## Introduction In Object-Oriented Programming (OOP), an **interface** is a crucial concept that defines a contract for classes to follow. It allows multiple classes to share a common structure while enforcing certain behaviors. While C++ does not have explicit support for interfaces like Java, it achieves the same functionality using **pure virtual functions** in abstract classes. ## What is an Interface? An **interface** is a collection of method definitions that a class must implement. It defines a contract that implementing classes must adhere to. ### **Key Characteristics of Interfaces in C++** - Uses **abstract classes with pure virtual functions** to define interfaces. - Defines methods without implementation that must be overridden. - Supports **multiple inheritance**, unlike normal classes. - Improves **code flexibility and maintainability**. --- ## **Defining and Implementing an Interface in C++** ### **Step 1: Define an Interface using an Abstract Class** To define an interface, we use a class with at least one **pure virtual function**. ```cpp #include using namespace std; // Defining an interface class Vehicle { public: virtual void start() = 0; // Pure virtual function virtual void stop() = 0; // Pure virtual function }; ``` ### **Step 2: Implement the Interface** A class implements an interface by inheriting from it and providing concrete implementations of the pure virtual functions. ```cpp // Implementing the Vehicle interface in a Car class class Car : public Vehicle { public: void start() override { cout << "Car is starting..." << endl; } void stop() override { cout << "Car is stopping..." << endl; } }; ``` ### **Step 3: Using the Implemented Class** Now, let's create objects and call the methods. ```cpp int main() { Vehicle* myCar = new Car(); // Polymorphism: Interface reference myCar->start(); myCar->stop(); delete myCar; // Clean up memory return 0; } ``` ### **Output:** ``` Car is starting... Car is stopping... ``` --- ## **Multiple Inheritance with Interfaces** Unlike normal classes, C++ **supports multiple inheritance** with interfaces. ```cpp // First interface class Flyable { public: virtual void fly() = 0; }; // Second interface class Drivable { public: virtual void drive() = 0; }; // Implementing multiple interfaces class FlyingCar : public Flyable, public Drivable { public: void fly() override { cout << "FlyingCar is flying..." << endl; } void drive() override { cout << "FlyingCar is driving..." << endl; } }; ``` ### **Usage** ```cpp int main() { FlyingCar myVehicle; myVehicle.fly(); myVehicle.drive(); return 0; } ``` ### **Output:** ``` FlyingCar is flying... FlyingCar is driving... ``` --- ## **Providing Default Implementations in Interfaces** Unlike Java, C++ does not have **default methods** in interfaces, but we can provide default implementations in base classes. ```cpp class Animal { public: virtual void sound() = 0; void sleep() { // Default method cout << "Sleeping..." << endl; } }; class Dog : public Animal { public: void sound() override { cout << "Dog barks" << endl; } }; ``` ### **Usage** ```cpp int main() { Dog myDog; myDog.sound(); myDog.sleep(); return 0; } ``` ### **Output:** ``` Dog barks Sleeping... ``` --- ## **Real-World Example: Payment System** ```cpp class Payment { public: virtual void pay(double amount) = 0; }; class CreditCardPayment : public Payment { public: void pay(double amount) override { cout << "Paid " << amount << " using Credit Card" << endl; } }; class PayPalPayment : public Payment { public: void pay(double amount) override { cout << "Paid " << amount << " using PayPal" << endl; } }; ``` ### **Usage** ```cpp int main() { Payment* payment1 = new CreditCardPayment(); payment1->pay(100.50); Payment* payment2 = new PayPalPayment(); payment2->pay(200.75); delete payment1; delete payment2; return 0; } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` ================================================ FILE: oop/cpp/polymorphism/README.md ================================================ # Polymorphism in C++ ## Introduction **Polymorphism** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. Polymorphism in C++ can be classified into two types: 1. **Compile-time Polymorphism (Function Overloading & Operator Overloading)** 2. **Run-time Polymorphism (Function Overriding & Virtual Functions)** ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a method, function, or object to behave differently based on the context. Polymorphism enables **dynamic method resolution** and **method flexibility**, making applications easier to extend and maintain. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single interface that works for multiple types. - **Scalability**: Add new functionalities with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **1. Compile-Time Polymorphism (Function Overloading)** Compile-time polymorphism occurs when multiple functions in the same class share the same name but have **different method signatures** (parameters). The method to be called is determined **at compile time**. ### **Example of Function Overloading** ```cpp #include using namespace std; class MathOperations { public: // Function with two parameters int add(int a, int b) { return a + b; } // Function with three parameters (overloaded) int add(int a, int b, int c) { return a + b + c; } }; int main() { MathOperations math; cout << "Sum (2 numbers): " << math.add(5, 10) << endl; cout << "Sum (3 numbers): " << math.add(5, 10, 15) << endl; return 0; } ``` ### **Output:** ``` Sum (2 numbers): 15 Sum (3 numbers): 30 ``` **Why Use Function Overloading?** - Provides a cleaner and more intuitive interface. - Reduces redundancy by using a single function name for similar operations. --- ## **2. Run-Time Polymorphism (Function Overriding & Virtual Functions)** Run-time polymorphism occurs when a subclass provides a **specific implementation** of a method already defined in its parent class. The method to be called is determined **at runtime** using **virtual functions**. ### **Example of Function Overriding with Virtual Functions** ```cpp #include using namespace std; class Animal { public: virtual void makeSound() { cout << "Animal makes a sound" << endl; } }; class Dog : public Animal { public: void makeSound() override { cout << "Dog barks" << endl; } }; class Cat : public Animal { public: void makeSound() override { cout << "Cat meows" << endl; } }; int main() { Animal* myAnimal = new Dog(); // Upcasting myAnimal->makeSound(); myAnimal = new Cat(); // Dynamic method dispatch myAnimal->makeSound(); delete myAnimal; return 0; } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Function Overriding?** - Enables **dynamic method resolution**. - Supports **polymorphic behavior**, where one interface can be used for multiple implementations. - Makes code **extensible** by allowing future modifications. --- ## **Using Polymorphism with Abstract Classes** Polymorphism is widely used with **abstract classes**, allowing multiple derived classes to share a common contract. ```cpp #include using namespace std; class Vehicle { public: virtual void start() = 0; // Pure virtual function }; class Car : public Vehicle { public: void start() override { cout << "Car is starting..." << endl; } }; class Bike : public Vehicle { public: void start() override { cout << "Bike is starting..." << endl; } }; int main() { Vehicle* myVehicle = new Car(); myVehicle->start(); myVehicle = new Bike(); myVehicle->start(); delete myVehicle; return 0; } ``` ### **Output:** ``` Car is starting... Bike is starting... ``` **Why Use Abstract Classes with Polymorphism?** - Promotes **loose coupling**, making code more flexible. - Allows multiple implementations of the same behavior. - Enforces common structure in derived classes. --- ## **Real-World Example: Payment System** A common real-world use case of polymorphism is in **payment processing**. ```cpp #include using namespace std; class Payment { public: virtual void pay(double amount) = 0; // Pure virtual function }; class CreditCardPayment : public Payment { public: void pay(double amount) override { cout << "Paid " << amount << " using Credit Card" << endl; } }; class PayPalPayment : public Payment { public: void pay(double amount) override { cout << "Paid " << amount << " using PayPal" << endl; } }; int main() { Payment* payment; payment = new CreditCardPayment(); payment->pay(100.50); payment = new PayPalPayment(); payment->pay(200.75); delete payment; return 0; } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` **Why Use Polymorphism in Payment Systems?** - Allows new payment methods to be added **without modifying existing code**. - Provides a **flexible and scalable** design. - Improves **code readability and maintainability**. ================================================ FILE: oop/csharp/abstraction/README.md ================================================ # Abstraction in C# ## Introduction **Abstraction** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows you to hide **implementation details** while exposing only the necessary parts of an object. This helps in reducing complexity and increasing maintainability. Abstraction in C# is mainly achieved using: 1. **Abstract Classes** 2. **Interfaces** --- ## **What is Abstraction?** **Abstraction** means showing only the **essential details** and hiding the **implementation**. It allows programmers to focus on **what an object does** rather than **how it does it**. ### **Key Benefits of Abstraction** - **Reduces complexity**: Hides unnecessary implementation details. - **Increases code reusability**: Encourages the reuse of abstracted logic. - **Enhances security**: Protects internal object details from unintended modifications. - **Improves maintainability**: Makes code easier to manage and update. --- ## **1. Abstraction Using Abstract Classes** An **abstract class** in C# is a class that **cannot be instantiated**. It is used to define common behavior that multiple subclasses should implement. ### **Example: Abstract Class in C#** ```csharp using System; // Abstract class abstract class Vehicle { protected string Brand; public Vehicle(string brand) { Brand = brand; } public abstract void Start(); // Abstract method public void DisplayBrand() { Console.WriteLine("Brand: " + Brand); } } // Subclass implementing the abstract method class Car : Vehicle { public Car(string brand) : base(brand) {} public override void Start() { Console.WriteLine("Car is starting..."); } } class Program { static void Main() { Vehicle myCar = new Car("Toyota"); myCar.DisplayBrand(); myCar.Start(); } } ``` ### **Output:** ``` Brand: Toyota Car is starting... ``` **Why Use Abstract Classes?** - Allows defining common behavior that subclasses must implement. - Enables partial abstraction (can have both abstract and concrete methods). - Prevents direct instantiation of base classes. --- ## **2. Abstraction Using Interfaces** An **interface** in C# is a contract that defines methods a class must implement. ### **Example: Interface in C#** ```csharp using System; // Defining an interface interface IAnimal { void MakeSound(); // Abstract method } // Implementing the interface in Dog class class Dog : IAnimal { public void MakeSound() { Console.WriteLine("Dog barks"); } } // Implementing the interface in Cat class class Cat : IAnimal { public void MakeSound() { Console.WriteLine("Cat meows"); } } class Program { static void Main() { IAnimal myDog = new Dog(); myDog.MakeSound(); IAnimal myCat = new Cat(); myCat.MakeSound(); } } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Interfaces?** - Promotes **full abstraction** (hides all implementation details). - Supports **multiple inheritance** in C#. - Provides a standard way for different classes to implement behaviors. --- ## **Abstract Class vs Interface: Key Differences** | Feature | Abstract Class | Interface | |---------|---------------|-----------| | Methods | Can have abstract and concrete methods | Only abstract methods (before C# 8) | | Fields | Can have member variables | Cannot have instance variables | | Constructor | Can have constructors | Cannot have constructors | | Multiple Inheritance | Not supported | Supported | | Access Modifiers | Can have different access modifiers | Methods are `public` by default | --- ## **Real-World Example: Payment System** Abstraction is widely used in real-world applications, such as payment processing. ### **Example: Payment System with Abstraction** ```csharp using System; // Abstract class for Payment abstract class Payment { protected double Amount; public Payment(double amount) { Amount = amount; } public abstract void Pay(); // Abstract method } // Implementing payment methods class CreditCardPayment : Payment { public CreditCardPayment(double amount) : base(amount) {} public override void Pay() { Console.WriteLine("Paid " + Amount + " using Credit Card"); } } class PayPalPayment : Payment { public PayPalPayment(double amount) : base(amount) {} public override void Pay() { Console.WriteLine("Paid " + Amount + " using PayPal"); } } class Program { static void Main() { Payment payment; payment = new CreditCardPayment(150.75); payment.Pay(); payment = new PayPalPayment(200.50); payment.Pay(); } } ``` ### **Output:** ``` Paid 150.75 using Credit Card Paid 200.50 using PayPal ``` **Why Use Abstraction in Payment Systems?** - Allows multiple payment methods without modifying existing code. - Improves maintainability and scalability. - Provides a **common contract** for different payment types. ================================================ FILE: oop/csharp/aggregation/README.md ================================================ # Aggregation in C# ## Introduction Aggregation is a key concept in object-oriented programming (OOP) that represents a "has-a" relationship between two classes, but with a crucial distinction: the lifecycle of the contained object is independent of the container object. This means that while one class contains another, the contained object can exist independently of the container. Aggregation allows for better modularity, code reuse, and maintainability. It is different from composition, where the contained object cannot exist without the container. ## What is Aggregation? Aggregation is a form of association in OOP where an object of one class contains a reference to an object of another class. However, the contained object can exist independently of the container. This means that even if the container object is destroyed, the contained object can still be used elsewhere in the application. ### Key Characteristics of Aggregation: - Represents a **has-a** relationship. - The contained object **can exist independently** of the container. - Implemented using references to objects. - Promotes **loose coupling** between objects. ### Example: A University and its Professors Consider a scenario where a `University` contains multiple `Professor` objects. However, a `Professor` can exist independently of any university. This is an example of aggregation. ```csharp using System; using System.Collections.Generic; class Professor { public string Name { get; private set; } public string Subject { get; private set; } public Professor(string name, string subject) { Name = name; Subject = subject; } public void Teach() { Console.WriteLine($"{Name} is teaching {Subject}"); } } class University { private string universityName; private List professors; public University(string universityName) { this.universityName = universityName; professors = new List(); } public void AddProfessor(Professor professor) { professors.Add(professor); } public void ShowProfessors() { Console.WriteLine($"Professors at {universityName}:"); foreach (var professor in professors) { Console.WriteLine($" - {professor.Name}"); } } } class AggregationExample { static void Main() { Professor prof1 = new Professor("Dr. Smith", "Computer Science"); Professor prof2 = new Professor("Dr. Johnson", "Mathematics"); University university = new University("Harvard University"); university.AddProfessor(prof1); university.AddProfessor(prof2); university.ShowProfessors(); // Professors can exist independently prof1.Teach(); prof2.Teach(); } } ``` ### Output: ``` Professors at Harvard University: - Dr. Smith - Dr. Johnson Dr. Smith is teaching Computer Science Dr. Johnson is teaching Mathematics ``` --- ## Aggregation vs Composition | Feature | Aggregation | Composition | |--------------|------------|-------------| | Relationship | "Has-a" | "Has-a" | | Ownership | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | University and Professors | Car and Engine | --- ## Why Use Aggregation? ### 1. **Promotes Code Reusability** - Aggregated objects can be used in multiple places without being tightly coupled to a single container class. ### 2. **Encourages Loose Coupling** - Aggregation allows objects to interact without being dependent on the lifecycle of each other. ### 3. **Better Maintainability** - Changes in one class do not heavily impact the other, making the codebase easier to modify and extend. ### 4. **Real-World Applicability** - Many real-world relationships, such as a school and its teachers, a company and its employees, naturally fit the aggregation model. --- ## Aggregation with Interfaces Using interfaces, we can further enhance the flexibility of aggregation. ```csharp using System; using System.Collections.Generic; interface ITeachable { void Teach(); } class Professor : ITeachable { public string Name { get; private set; } public string Subject { get; private set; } public Professor(string name, string subject) { Name = name; Subject = subject; } public void Teach() { Console.WriteLine($"{Name} is teaching {Subject}"); } } class University { private string universityName; private List professors; public University(string universityName) { this.universityName = universityName; professors = new List(); } public void AddProfessor(ITeachable professor) { professors.Add(professor); } public void ShowProfessors() { Console.WriteLine($"Professors at {universityName}:"); foreach (var professor in professors) { professor.Teach(); } } } class InterfaceAggregationExample { static void Main() { Professor prof1 = new Professor("Dr. Adams", "Physics"); Professor prof2 = new Professor("Dr. Lee", "Chemistry"); University university = new University("MIT"); university.AddProfessor(prof1); university.AddProfessor(prof2); university.ShowProfessors(); } } ``` ### Output: ``` Professors at MIT: Dr. Adams is teaching Physics Dr. Lee is teaching Chemistry ``` --- ## When to Use Aggregation? - When an object **can exist independently** from the container. - When designing **loosely coupled** systems. - When different objects need to be **shared** across multiple containers. - When following **SOLID principles**, particularly the **Dependency Inversion Principle (DIP)**. ================================================ FILE: oop/csharp/association/README.md ================================================ # Association in C# ## Introduction Association is a key concept in object-oriented programming (OOP) that defines a relationship between two or more objects. It represents how objects interact with each other while maintaining their independence. Association is **not inheritance**—rather, it is a relationship between objects that allows communication while ensuring they remain loosely coupled. ## What is Association? Association defines a connection between two classes, where one class is linked to another. The association can be **one-to-one**, **one-to-many**, **many-to-one**, or **many-to-many**. Objects in an association can exist independently of each other. ### Key Characteristics of Association: - Represents a **uses-a** or **knows-a** relationship. - Objects in an association **can exist independently**. - Can be **unidirectional** or **bidirectional**. - Promotes **modularity** and **code reusability**. ### Example: A Student and a Teacher A `Student` can be associated with multiple `Teacher` objects, and a `Teacher` can have multiple `Student` objects. This represents a **many-to-many** association. ```csharp using System; using System.Collections.Generic; class Teacher { public string Name { get; private set; } private List students; public Teacher(string name) { Name = name; students = new List(); } public void AddStudent(Student student) { students.Add(student); } public void ShowStudents() { Console.WriteLine($"{Name} teaches:"); foreach (var student in students) { Console.WriteLine($" - {student.Name}"); } } } class Student { public string Name { get; private set; } public Student(string name) { Name = name; } } class AssociationExample { static void Main() { Teacher teacher1 = new Teacher("Mr. Smith"); Teacher teacher2 = new Teacher("Mrs. Johnson"); Student student1 = new Student("Alice"); Student student2 = new Student("Bob"); teacher1.AddStudent(student1); teacher1.AddStudent(student2); teacher2.AddStudent(student2); teacher1.ShowStudents(); teacher2.ShowStudents(); } } ``` ### Output: ``` Mr. Smith teaches: - Alice - Bob Mrs. Johnson teaches: - Bob ``` --- ## Types of Association ### 1. **One-to-One Association** - Each object of class A is associated with one object of class B. - Example: A `Person` has one `Passport`. ### 2. **One-to-Many Association** - One object of class A can be associated with multiple objects of class B. - Example: A `Teacher` teaches multiple `Students`. ### 3. **Many-to-One Association** - Multiple objects of class A can be associated with one object of class B. - Example: Multiple `Students` belong to one `School`. ### 4. **Many-to-Many Association** - Multiple objects of class A can be associated with multiple objects of class B. - Example: `Teachers` and `Students` (a student can have multiple teachers, and a teacher can have multiple students). --- ## Why Use Association? ### 1. **Promotes Code Reusability** - Objects can be reused across multiple associations without duplication. ### 2. **Encourages Loose Coupling** - Objects interact without depending on the internal implementation of each other. ### 3. **Improves Maintainability** - Changing one object does not heavily impact others, making code easier to manage. ### 4. **Better System Design** - Allows modeling of real-world relationships between entities effectively. --- ## Bidirectional Association Associations can be **unidirectional** (one object knows about another) or **bidirectional** (both objects know about each other). ### Example: A Library and Books (Bidirectional Association) ```csharp using System; using System.Collections.Generic; class Book { public string Title { get; private set; } private Library library; public Book(string title, Library library) { Title = title; this.library = library; } public void ShowLibrary() { Console.WriteLine($"{Title} is in {library.Name}"); } } class Library { public string Name { get; private set; } private List books; public Library(string name) { Name = name; books = new List(); } public void AddBook(Book book) { books.Add(book); } public void ShowBooks() { Console.WriteLine($"Books in {Name}:"); foreach (var book in books) { Console.WriteLine($" - {book.Title}"); } } } class BidirectionalAssociationExample { static void Main() { Library library = new Library("City Library"); Book book1 = new Book("1984", library); Book book2 = new Book("Brave New World", library); library.AddBook(book1); library.AddBook(book2); library.ShowBooks(); book1.ShowLibrary(); book2.ShowLibrary(); } } ``` ### Output: ``` Books in City Library: - 1984 - Brave New World 1984 is in City Library Brave New World is in City Library ``` ================================================ FILE: oop/csharp/classesandobjects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? A class is a blueprint or template. It defines the attributes (fields) and behaviors (methods) of an object. ### Defining a Class in C# To define a class in C#, you use the `class` keyword followed by the name of the class. Here's a simple example: ```csharp public class Car { // Attributes private string color; private string make; private string model; private int year; // Constructor public Car(string color, string make, string model, int year) { this.color = color; this.make = make; this.model = model; this.year = year; } // Method to display car details public void displayInfo() { Console.WriteLine("Car Make: " + make); Console.WriteLine("Car Model: " + model); Console.WriteLine("Car Year: " + year); Console.WriteLine("Car Color: " + color); } } ``` - **Attributes**: The class `Car` has four attributes that describe its state: `color`, `make`, `model`, and `year`. - **Constructor**: The constructor `Car(string color, string make, string model, int year)` initializes new objects of the class. - **Methods**: The `displayInfo` method is responsible for showcasing the car details. ## What is an Object? An object is an instance of a class. When you create an object, you are bringing the blueprint of the class into reality. It consists of state and behavior defined by the class, with each object holding its own copy of the data. ### Creating Objects in C# To create an object, you use the `new` keyword followed by the class constructor. Here's how you can instantiate objects from the `Car` class: ```csharp public class Main { public static void main(string[] args) { // Creating an object of the Car class Car car1 = new Car("Red", "Toyota", "Corolla", 2020); Car car2 = new Car("Blue", "Ford", "Mustang", 2021); // Displaying information of each car car1.displayInfo(); Console.WriteLine("-----------------"); car2.displayInfo(); } } ``` 1. **Instantiation**: The `new` keyword is used to create an object, which allocates memory for it. 2. **Initialization**: The constructor (`Car`) initializes the object state with given parameters. 3. **Reference**: The object is referenced through a variable (`car1`, `car2`) that points to its memory location. ================================================ FILE: oop/csharp/composition/README.md ================================================ # Composition in C# ## Introduction Composition is one of the key concepts of object-oriented programming (OOP). It allows objects to be built using other objects, promoting code reuse, flexibility, and better maintainability. Unlike inheritance, which establishes an "is-a" relationship, composition represents a "has-a" relationship. ## What is Composition? Composition is a design principle in OOP where one class contains an instance (or instances) of another class as a field. The contained class is often called a component, and the containing class is referred to as a composite class. This helps in building complex systems by combining simpler objects. ### Example: A Car and its Components Consider a `Car` that consists of multiple components like an `Engine`, `Wheel`, and `Transmission`. Instead of inheriting from these components, a `Car` object will contain them as fields. ```csharp using System; class Engine { private int horsepower; public Engine(int horsepower) { this.horsepower = horsepower; } public void Start() { Console.WriteLine($"Engine started with {horsepower} HP."); } } class Wheel { private string type; public Wheel(string type) { this.type = type; } public void Rotate() { Console.WriteLine($"The {type} wheel is rotating."); } } class Transmission { private string type; public Transmission(string type) { this.type = type; } public void ShiftGear() { Console.WriteLine($"Transmission shifted: {type}"); } } class Car { private Engine engine; private Wheel wheel; private Transmission transmission; public Car(Engine engine, Wheel wheel, Transmission transmission) { this.engine = engine; this.wheel = wheel; this.transmission = transmission; } public void Drive() { engine.Start(); wheel.Rotate(); transmission.ShiftGear(); Console.WriteLine("Car is moving!"); } } class CompositionExample { static void Main() { Car car = new Car(new Engine(150), new Wheel("Alloy"), new Transmission("Automatic")); car.Drive(); } } ``` ### Output: ``` Engine started with 150 HP. The Alloy wheel is rotating. Transmission shifted: Automatic Car is moving! ``` --- ## Why Prefer Composition Over Inheritance? ### 1. **Encapsulation and Flexibility** - Composition allows us to change the behavior of an object dynamically by replacing components at runtime. - Inheritance makes it difficult to modify an existing class hierarchy without breaking existing code. ### 2. **Better Code Reusability** - Composition promotes reusable components. The `Engine`, `Wheel`, and `Transmission` classes can be used in multiple types of vehicles (Car, Bike, Truck) without modification. ### 3. **Avoids Inheritance Pitfalls** - Inheritance can lead to deep class hierarchies, making maintenance difficult. - It enforces strict parent-child relationships, which can be too rigid for some designs. ### 4. **Supports Interface-Based Design** - Composition can be combined with interfaces to achieve powerful decoupling. --- ## Composition with Interfaces Using interfaces with composition allows for greater flexibility and loose coupling. ```csharp using System; interface IEngine { void Start(); } class PetrolEngine : IEngine { public void Start() { Console.WriteLine("Petrol Engine started."); } } class DieselEngine : IEngine { public void Start() { Console.WriteLine("Diesel Engine started."); } } class Car { private IEngine engine; public Car(IEngine engine) { this.engine = engine; } public void StartCar() { engine.Start(); Console.WriteLine("Car is ready to go!"); } } class InterfaceCompositionExample { static void Main() { Car petrolCar = new Car(new PetrolEngine()); petrolCar.StartCar(); Car dieselCar = new Car(new DieselEngine()); dieselCar.StartCar(); } } ``` ### Output: ``` Petrol Engine started. Car is ready to go! Diesel Engine started. Car is ready to go! ``` --- ## When to Use Composition? - When building complex objects that consist of multiple components. - When you want to achieve **code reusability** without rigid inheritance hierarchies. - When different behaviors need to be swapped dynamically (e.g., using different types of engines in a vehicle). - When following the **favor composition over inheritance** principle. ================================================ FILE: oop/csharp/encapsulation/README.md ================================================ # Encapsulation in C# ## Introduction **Encapsulation** is one of the four fundamental principles of **Object-Oriented Programming (OOP)**. It is the practice of **bundling data (fields) and methods** that operate on that data into a single unit (**class**) while **restricting direct access** to the internal details. Encapsulation in C# is achieved using: 1. **Access Modifiers** (`private`, `protected`, `public`) 2. **Properties (Getters and Setters)** 3. **Data Hiding** Encapsulation helps in **data protection, modularity, and maintainability** of the code. ## **What is Encapsulation?** Encapsulation means **wrapping** the data (fields) and code (methods) together into a single unit (class). It restricts direct access to some of an object's components, ensuring **data integrity and security**. ### **Key Benefits of Encapsulation** - **Data Hiding**: Prevents direct access to sensitive data. - **Increased Security**: Controls how data is accessed and modified. - **Improved Code Maintainability**: Allows changes without affecting other parts of the code. - **Better Modularity**: Organizes the code into logical components. --- ## **Encapsulation Using Access Modifiers in C#** C# provides **access modifiers** to enforce encapsulation: - **`private`**: Accessible only within the same class. - **`protected`**: Accessible within the same class and derived (child) classes. - **`public`**: Accessible from anywhere. - **`internal`**: Accessible only within the same assembly. ### **Example: Encapsulation with Private Fields** ```csharp using System; class BankAccount { private string accountHolder; private double balance; // Constructor public BankAccount(string accountHolder, double balance) { this.accountHolder = accountHolder; this.balance = balance; } // Getter method to access balance public double GetBalance() { return balance; } // Setter method to modify balance public void Deposit(double amount) { if (amount > 0) { balance += amount; Console.WriteLine($"Deposited: {amount}"); } else { Console.WriteLine("Invalid deposit amount"); } } } class Program { static void Main() { BankAccount account = new BankAccount("Alice", 1000); Console.WriteLine($"Current Balance: {account.GetBalance()}"); account.Deposit(500); Console.WriteLine($"Updated Balance: {account.GetBalance()}"); } } ``` ### **Output:** ``` Current Balance: 1000 Deposited: 500 Updated Balance: 1500 ``` --- ## **Encapsulation Using Properties (Getters and Setters)** Encapsulation ensures that **data cannot be directly accessed** but must be retrieved or modified through **properties**. ### **Example: Properties in C#** ```csharp using System; class Employee { private string name; private int age; // Property for Name public string Name { get { return name; } set { name = value; } } // Property for Age with validation public int Age { get { return age; } set { if (value > 18) age = value; else Console.WriteLine("Age must be greater than 18"); } } } class Program { static void Main() { Employee emp = new Employee(); emp.Name = "John Doe"; emp.Age = 25; Console.WriteLine($"Employee Name: {emp.Name}"); Console.WriteLine($"Employee Age: {emp.Age}"); } } ``` ### **Output:** ``` Employee Name: John Doe Employee Age: 25 ``` --- ## **Encapsulation in Real-World Applications** Encapsulation is used in many real-world applications such as: 1. **Banking Systems** - Ensuring account details are private. 2. **Healthcare Applications** - Protecting patient records. 3. **E-Commerce Platforms** - Hiding payment processing details. ### **Example: Encapsulation in Payment Processing** ```csharp using System; class PaymentProcessor { private string cardNumber; private double amount; public PaymentProcessor(string cardNumber, double amount) { this.cardNumber = MaskCardNumber(cardNumber); this.amount = amount; } private string MaskCardNumber(string cardNumber) { return "****-****-****-" + cardNumber.Substring(cardNumber.Length - 4); } public void ProcessPayment() { Console.WriteLine($"Processing payment of {amount} for card {cardNumber}"); } } class Program { static void Main() { PaymentProcessor payment = new PaymentProcessor("1234567812345678", 250.00); payment.ProcessPayment(); } } ``` ### **Output:** ``` Processing payment of 250 for card ****-****-****-5678 ``` ================================================ FILE: oop/csharp/inheritance/README.md ================================================ # Inheritance in C# ## Introduction **Inheritance** is one of the core principles of Object-Oriented Programming (OOP). It allows a class (subclass or child class) to acquire the properties and behaviors of another class (superclass or parent class). This promotes **code reuse**, **scalability**, and **maintainability**. --- ## **What is Inheritance?** **Inheritance** is a mechanism where a child class derives properties and behaviors from a parent class. The child class can: - Use the fields and methods of the parent class - Override parent class methods to provide a specific implementation - Add its own additional properties and methods ### **Key Benefits of Inheritance** - **Code Reusability**: Avoids code duplication by reusing fields and methods of the parent class. - **Improves Maintainability**: Reduces redundancy, making code easier to manage. - **Enhances Extensibility**: New functionality can be added easily without modifying existing code. --- ## **How to Implement Inheritance in C#** ### **Step 1: Create a Parent Class** The parent class contains common fields and methods. ```csharp using System; // Parent class class Animal { public string Name; public void Eat() { Console.WriteLine(Name + " is eating..."); } } ``` ### **Step 2: Create a Child Class using `:`** The child class inherits the properties and methods of the parent class. ```csharp // Child class class Dog : Animal { public void Bark() { Console.WriteLine(Name + " is barking..."); } } ``` ### **Step 3: Use the Child Class** Now, let's create an object and use the inherited methods. ```csharp class Program { static void Main() { Dog myDog = new Dog(); myDog.Name = "Buddy"; myDog.Eat(); // Inherited from Animal class myDog.Bark(); // Defined in Dog class } } ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Types of Inheritance in C#** C# supports different types of inheritance: ### **1. Single Inheritance** A subclass inherits from one superclass. ```csharp class Parent { public void Show() { Console.WriteLine("This is the parent class"); } } class Child : Parent { public void Display() { Console.WriteLine("This is the child class"); } } ``` ### **2. Multilevel Inheritance** A subclass inherits from another subclass, forming a chain. ```csharp class Grandparent { public void Show() { Console.WriteLine("Grandparent class"); } } class Parent : Grandparent { public void Display() { Console.WriteLine("Parent class"); } } class Child : Parent { public void Print() { Console.WriteLine("Child class"); } } ``` ### **3. Hierarchical Inheritance** A single parent class has multiple child classes. ```csharp class Parent { public void Show() { Console.WriteLine("Parent class"); } } class Child1 : Parent { public void Display() { Console.WriteLine("Child1 class"); } } class Child2 : Parent { public void Print() { Console.WriteLine("Child2 class"); } } ``` **Note:** C# **does not support multiple inheritance** (i.e., a child class inheriting from multiple parents) due to ambiguity problems. --- ## **Method Overriding in Inheritance** Method overriding allows a child class to **redefine** a method from the parent class. ```csharp class Animal { public virtual void MakeSound() { Console.WriteLine("Animal makes a sound"); } } class Dog : Animal { public override void MakeSound() { Console.WriteLine("Dog barks"); } } ``` ### **Usage** ```csharp class Program { static void Main() { Animal myAnimal = new Dog(); // Polymorphism myAnimal.MakeSound(); } } ``` ### **Output:** ``` Dog barks ``` --- ## **The `base` Keyword in Inheritance** The `base` keyword is used to **refer to the parent class**. It helps to: 1. Call the parent class constructor. 2. Access the parent class methods. 3. Access the parent class fields. ```csharp class Animal { public Animal() { Console.WriteLine("Animal Constructor"); } public virtual void MakeSound() { Console.WriteLine("Animal makes a sound"); } } class Dog : Animal { public Dog() { Console.WriteLine("Dog Constructor"); } public override void MakeSound() { base.MakeSound(); // Calls parent method Console.WriteLine("Dog barks"); } } ``` ### **Usage** ```csharp class Program { static void Main() { Dog myDog = new Dog(); myDog.MakeSound(); } } ``` ### **Output:** ``` Animal Constructor Dog Constructor Animal makes a sound Dog barks ``` ================================================ FILE: oop/csharp/interfaces/README.md ================================================ # Interfaces in C# ## Introduction In Object-Oriented Programming (OOP), an **interface** is a crucial concept that defines a contract for classes to follow. It allows multiple classes to share a common structure while enforcing certain behaviors. Interfaces are widely used in C# and other OOP languages to achieve **abstraction, polymorphism, and loose coupling**. ## What is an Interface? An **interface** is a collection of method definitions that a class must implement. It defines a contract that implementing classes must adhere to. ### **Key Characteristics of Interfaces in C#** - Defines a **contract** that implementing classes must follow. - All methods are **implicitly public and abstract** (unless they have a default implementation). - Cannot have instance variables (only static and constant fields are allowed). - Supports **multiple inheritance**, unlike classes. - Improves **code flexibility and maintainability**. --- ## **Defining and Implementing an Interface in C#** ### **Step 1: Define an Interface** To define an interface, use the `interface` keyword. ```csharp // Defining an interface public interface IVehicle { void Start(); // Abstract method (no implementation) void Stop(); // Abstract method (no implementation) } ``` ### **Step 2: Implement the Interface** A class implements an interface using the `: (colon)` symbol. ```csharp // Implementing the IVehicle interface in a Car class public class Car : IVehicle { public void Start() { Console.WriteLine("Car is starting..."); } public void Stop() { Console.WriteLine("Car is stopping..."); } } ``` ### **Step 3: Using the Implemented Class** Now, let's create objects and call the methods. ```csharp public class Program { public static void Main(string[] args) { IVehicle myCar = new Car(); // Polymorphism: Interface reference myCar.Start(); myCar.Stop(); } } ``` ### **Output:** ``` Car is starting... Car is stopping... ``` --- ## **Multiple Inheritance with Interfaces** Unlike classes, C# **supports multiple inheritance** with interfaces. ```csharp // First interface public interface IFlyable { void Fly(); } // Second interface public interface IDrivable { void Drive(); } // Implementing multiple interfaces public class FlyingCar : IFlyable, IDrivable { public void Fly() { Console.WriteLine("FlyingCar is flying..."); } public void Drive() { Console.WriteLine("FlyingCar is driving..."); } } ``` ### **Usage** ```csharp public class Program { public static void Main(string[] args) { FlyingCar myVehicle = new FlyingCar(); myVehicle.Fly(); myVehicle.Drive(); } } ``` ### **Output:** ``` FlyingCar is flying... FlyingCar is driving... ``` --- ## **Default Method Behavior in Interfaces** C# 8 introduced **default methods** in interfaces, allowing methods with a body. ```csharp public interface IAnimal { void Sound(); // Default method with implementation public void Sleep() { Console.WriteLine("Sleeping..."); } } public class Dog : IAnimal { public void Sound() { Console.WriteLine("Dog barks"); } } ``` ### **Usage** ```csharp public class Program { public static void Main(string[] args) { Dog myDog = new Dog(); myDog.Sound(); myDog.Sleep(); // Calling default method } } ``` ### **Output:** ``` Dog barks Sleeping... ``` --- ## **Real-World Example: Payment System** ```csharp public interface IPayment { void Pay(double amount); } public class CreditCardPayment : IPayment { public void Pay(double amount) { Console.WriteLine($"Paid {amount} using Credit Card"); } } public class PayPalPayment : IPayment { public void Pay(double amount) { Console.WriteLine($"Paid {amount} using PayPal"); } } ``` ### **Usage** ```csharp public class Program { public static void Main(string[] args) { IPayment payment1 = new CreditCardPayment(); payment1.Pay(100.50); IPayment payment2 = new PayPalPayment(); payment2.Pay(200.75); } } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` ================================================ FILE: oop/csharp/polymorphism/README.md ================================================ # Polymorphism in C# ## Introduction **Polymorphism** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. Polymorphism in C# can be classified into two types: 1. **Compile-time Polymorphism (Method Overloading & Operator Overloading)** 2. **Run-time Polymorphism (Method Overriding & Interfaces)** ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a method, function, or object to behave differently based on the context. Polymorphism enables **dynamic method resolution** and **method flexibility**, making applications easier to extend and maintain. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single interface that works for multiple types. - **Scalability**: Add new functionalities with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **1. Compile-Time Polymorphism (Method Overloading)** Compile-time polymorphism occurs when multiple methods in the same class share the same name but have **different method signatures** (parameters). The method to be called is determined **at compile time**. ### **Example of Method Overloading** ```csharp using System; class MathOperations { // Method with two parameters public int Add(int a, int b) { return a + b; } // Method with three parameters (overloaded) public int Add(int a, int b, int c) { return a + b + c; } } class Program { static void Main() { MathOperations math = new MathOperations(); Console.WriteLine("Sum (2 numbers): " + math.Add(5, 10)); Console.WriteLine("Sum (3 numbers): " + math.Add(5, 10, 15)); } } ``` ### **Output:** ``` Sum (2 numbers): 15 Sum (3 numbers): 30 ``` **Why Use Method Overloading?** - Provides a cleaner and more intuitive interface. - Reduces redundancy by using a single method name for similar operations. --- ## **2. Run-Time Polymorphism (Method Overriding)** Run-time polymorphism occurs when a subclass provides a **specific implementation** of a method already defined in its parent class. The method to be called is determined **at runtime**. ### **Example of Method Overriding** ```csharp using System; class Animal { public virtual void MakeSound() { Console.WriteLine("Animal makes a sound"); } } class Dog : Animal { public override void MakeSound() { Console.WriteLine("Dog barks"); } } class Cat : Animal { public override void MakeSound() { Console.WriteLine("Cat meows"); } } class Program { static void Main() { Animal myAnimal = new Dog(); // Upcasting myAnimal.MakeSound(); myAnimal = new Cat(); // Dynamic method dispatch myAnimal.MakeSound(); } } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Method Overriding?** - Enables **dynamic method resolution**. - Supports **polymorphic behavior**, where one interface can be used for multiple implementations. - Makes code **extensible** by allowing future modifications. --- ## **Using Polymorphism with Interfaces** Polymorphism is widely used with **interfaces**, allowing multiple classes to share a common contract. ```csharp using System; interface IVehicle { void Start(); } class Car : IVehicle { public void Start() { Console.WriteLine("Car is starting..."); } } class Bike : IVehicle { public void Start() { Console.WriteLine("Bike is starting..."); } } class Program { static void Main() { IVehicle myVehicle = new Car(); myVehicle.Start(); myVehicle = new Bike(); myVehicle.Start(); } } ``` ### **Output:** ``` Car is starting... Bike is starting... ``` **Why Use Interfaces with Polymorphism?** - Promotes **loose coupling**, making code more flexible. - Allows multiple implementations of the same behavior. - Enables **dependency injection**, improving testability. --- ## **Real-World Example: Payment System** A common real-world use case of polymorphism is in **payment processing**. ```csharp using System; interface IPayment { void Pay(double amount); } class CreditCardPayment : IPayment { public void Pay(double amount) { Console.WriteLine("Paid " + amount + " using Credit Card"); } } class PayPalPayment : IPayment { public void Pay(double amount) { Console.WriteLine("Paid " + amount + " using PayPal"); } } class Program { static void Main() { IPayment payment; payment = new CreditCardPayment(); payment.Pay(100.50); payment = new PayPalPayment(); payment.Pay(200.75); } } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` **Why Use Polymorphism in Payment Systems?** - Allows new payment methods to be added **without modifying existing code**. - Provides a **flexible and scalable** design. - Improves **code readability and maintainability**. ================================================ FILE: oop/golang/abstraction/README.md ================================================ # Abstraction in Go ## Introduction **Abstraction** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows you to hide **implementation details** while exposing only the necessary parts of an object. This helps in reducing complexity and increasing maintainability. Unlike traditional OOP languages like Java or C++, **Golang does not support classes**. However, abstraction in Go is achieved using: 1. **Interfaces** 2. **Structs with Methods** ## **What is Abstraction?** **Abstraction** means showing only the **essential details** and hiding the **implementation**. It allows programmers to focus on **what an object does** rather than **how it does it**. ### **Key Benefits of Abstraction** - **Reduces complexity**: Hides unnecessary implementation details. - **Increases code reusability**: Encourages the reuse of abstracted logic. - **Improves maintainability**: Makes code easier to manage and update. - **Enhances flexibility**: Enables polymorphic behavior in Go. --- ## **1. Abstraction Using Interfaces** An **interface** in Go defines a set of methods that a type must implement. This allows different types to be treated uniformly. ### **Example: Interface in Golang** ```go package main import "fmt" // Defining an interface type Vehicle interface { Start() DisplayBrand() } // Concrete implementation of Vehicle (Car) type Car struct { brand string } func (c Car) Start() { fmt.Println("Car is starting...") } func (c Car) DisplayBrand() { fmt.Println("Brand:", c.brand) } func main() { var myCar Vehicle = Car{"Toyota"} myCar.DisplayBrand() myCar.Start() } ``` ### **Output:** ``` Brand: Toyota Car is starting... ``` **Why Use Interfaces?** - Promotes **abstraction** by defining behaviors without implementation details. - Allows multiple types to adhere to the same contract. - Supports **polymorphism** by enabling different implementations to be used interchangeably. --- ## **2. Abstraction Using Structs with Methods** Go does not have traditional classes, but **structs with methods** provide an alternative way to achieve abstraction. ### **Example: Abstracting Animal Behavior** ```go package main import "fmt" // Abstract behavior using an interface type Animal interface { MakeSound() } // Concrete struct (Dog) type Dog struct {} func (d Dog) MakeSound() { fmt.Println("Dog barks") } // Concrete struct (Cat) type Cat struct {} func (c Cat) MakeSound() { fmt.Println("Cat meows") } func main() { var myAnimal Animal myAnimal = Dog{} myAnimal.MakeSound() myAnimal = Cat{} myAnimal.MakeSound() } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Structs with Methods?** - Provides a clean and flexible way to define behavior. - Makes it easy to extend functionality. - Improves code readability and organization. --- ## **Real-World Example: Payment System** Abstraction is widely used in real-world applications, such as payment processing. ### **Example: Payment System with Abstraction** ```go package main import "fmt" // Payment interface type Payment interface { Pay(amount float64) } // CreditCardPayment struct type CreditCardPayment struct {} func (c CreditCardPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using Credit Card\n", amount) } // PayPalPayment struct type PayPalPayment struct {} func (p PayPalPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using PayPal\n", amount) } func main() { var payment Payment payment = CreditCardPayment{} payment.Pay(150.75) payment = PayPalPayment{} payment.Pay(200.50) } ``` ### **Output:** ``` Paid 150.75 using Credit Card Paid 200.50 using PayPal ``` **Why Use Abstraction in Payment Systems?** - Allows multiple payment methods without modifying existing code. - Improves maintainability and scalability. - Provides a **common contract** for different payment types. ================================================ FILE: oop/golang/aggregation/README.md ================================================ # Aggregation in Golang ## Introduction Aggregation is a key concept in object-oriented programming (OOP) that represents a "has-a" relationship between two classes (or structs in Golang), but with a crucial distinction: the lifecycle of the contained object is independent of the container object. This means that while one struct contains another, the contained struct can exist independently of the container. Aggregation allows for better modularity, code reuse, and maintainability. It is different from composition, where the contained struct cannot exist without the container. ## What is Aggregation? Aggregation is a form of association in OOP where an object of one struct contains a reference (pointer) to an object of another struct. However, the contained object can exist independently of the container. This means that even if the container object is destroyed, the contained object can still be used elsewhere in the application. ### Key Characteristics of Aggregation: - Represents a **has-a** relationship. - The contained object **can exist independently** of the container. - Implemented using references (pointers) to objects. - Promotes **loose coupling** between objects. ### Example: A University and its Professors Consider a scenario where a `University` contains multiple `Professor` objects. However, a `Professor` can exist independently of any university. This is an example of aggregation. ```go package main import "fmt" // Professor struct (independent entity) type Professor struct { Name string Subject string } func (p Professor) Teach() { fmt.Printf("%s is teaching %s\n", p.Name, p.Subject) } // University struct contains a list of professors (aggregation) type University struct { Name string Professors []*Professor // Aggregation: University has a list of professors } func (u *University) AddProfessor(professor *Professor) { u.Professors = append(u.Professors, professor) } func (u University) ShowProfessors() { fmt.Printf("Professors at %s:\n", u.Name) for _, professor := range u.Professors { fmt.Printf(" - %s\n", professor.Name) } } func main() { prof1 := &Professor{Name: "Dr. Smith", Subject: "Computer Science"} prof2 := &Professor{Name: "Dr. Johnson", Subject: "Mathematics"} university := &University{Name: "Harvard University"} university.AddProfessor(prof1) university.AddProfessor(prof2) university.ShowProfessors() // Professors can exist independently prof1.Teach() prof2.Teach() } ``` ### Output: ``` Professors at Harvard University: - Dr. Smith - Dr. Johnson Dr. Smith is teaching Computer Science Dr. Johnson is teaching Mathematics ``` --- ## Aggregation vs Composition | Feature | Aggregation | Composition | |--------------|------------|-------------| | Relationship | "Has-a" | "Has-a" | | Ownership | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | University and Professors | Car and Engine | --- ## Why Use Aggregation? ### 1. **Promotes Code Reusability** - Aggregated objects can be used in multiple places without being tightly coupled to a single container struct. ### 2. **Encourages Loose Coupling** - Aggregation allows objects to interact without being dependent on the lifecycle of each other. ### 3. **Better Maintainability** - Changes in one struct do not heavily impact the other, making the codebase easier to modify and extend. ### 4. **Real-World Applicability** - Many real-world relationships, such as a school and its teachers, a company and its employees, naturally fit the aggregation model. --- ## Aggregation with Interfaces Using interfaces, we can further enhance the flexibility of aggregation. ```go package main import "fmt" // Teachable interface type Teachable interface { Teach() } // Professor struct implementing Teachable interface type Professor struct { Name string Subject string } func (p Professor) Teach() { fmt.Printf("%s is teaching %s\n", p.Name, p.Subject) } // University struct containing a list of professors type University struct { Name string Professors []Teachable } func (u *University) AddProfessor(professor Teachable) { u.Professors = append(u.Professors, professor) } func (u University) ShowProfessors() { fmt.Printf("Professors at %s:\n", u.Name) for _, professor := range u.Professors { professor.Teach() } } func main() { prof1 := Professor{Name: "Dr. Adams", Subject: "Physics"} prof2 := Professor{Name: "Dr. Lee", Subject: "Chemistry"} university := &University{Name: "MIT"} university.AddProfessor(prof1) university.AddProfessor(prof2) university.ShowProfessors() } ``` ### Output: ``` Professors at MIT: Dr. Adams is teaching Physics Dr. Lee is teaching Chemistry ``` --- ## When to Use Aggregation? - When an object **can exist independently** from the container. - When designing **loosely coupled** systems. - When different objects need to be **shared** across multiple containers. - When following **SOLID principles**, particularly the **Dependency Inversion Principle (DIP)**. ================================================ FILE: oop/golang/association/README.md ================================================ # Association in Golang ## Introduction Association is a key concept in object-oriented programming (OOP) that defines a relationship between two or more objects. It represents how objects interact with each other while maintaining their independence. Association is **not inheritance**—rather, it is a relationship between objects that allows communication while ensuring they remain loosely coupled. ## What is Association? Association defines a connection between two structs, where one struct is linked to another. The association can be **one-to-one**, **one-to-many**, **many-to-one**, or **many-to-many**. Objects in an association can exist independently of each other. ### Key Characteristics of Association: - Represents a **uses-a** or **knows-a** relationship. - Objects in an association **can exist independently**. - Can be **unidirectional** or **bidirectional**. - Promotes **modularity** and **code reusability**. ### Example: A Student and a Teacher A `Student` can be associated with multiple `Teacher` objects, and a `Teacher` can have multiple `Student` objects. This represents a **many-to-many** association. ```go package main import "fmt" type Student struct { Name string } type Teacher struct { Name string Students []*Student } func (t *Teacher) AddStudent(s *Student) { t.Students = append(t.Students, s) } func (t *Teacher) ShowStudents() { fmt.Println(t.Name, "teaches:") for _, student := range t.Students { fmt.Println(" -", student.Name) } } func main() { teacher1 := Teacher{Name: "Mr. Smith"} teacher2 := Teacher{Name: "Mrs. Johnson"} student1 := Student{Name: "Alice"} student2 := Student{Name: "Bob"} teacher1.AddStudent(&student1) teacher1.AddStudent(&student2) teacher2.AddStudent(&student2) teacher1.ShowStudents() teacher2.ShowStudents() } ``` ### Output: ``` Mr. Smith teaches: - Alice - Bob Mrs. Johnson teaches: - Bob ``` --- ## Types of Association ### 1. **One-to-One Association** - Each object of struct A is associated with one object of struct B. - Example: A `Person` has one `Passport`. ### 2. **One-to-Many Association** - One object of struct A can be associated with multiple objects of struct B. - Example: A `Teacher` teaches multiple `Students`. ### 3. **Many-to-One Association** - Multiple objects of struct A can be associated with one object of struct B. - Example: Multiple `Students` belong to one `School`. ### 4. **Many-to-Many Association** - Multiple objects of struct A can be associated with multiple objects of struct B. - Example: `Teachers` and `Students`. --- ## Why Use Association? - **Promotes Code Reusability**: Objects can be reused across multiple associations without duplication. - **Encourages Loose Coupling**: Objects interact without depending on the internal implementation of each other. - **Improves Maintainability**: Changing one object does not heavily impact others, making code easier to manage. - **Better System Design**: Allows modeling of real-world relationships between entities effectively. --- ## Association vs Aggregation vs Composition | Feature | Association | Aggregation | Composition | |--------------|------------|------------|------------| | Relationship | "Knows-a" | "Has-a" | "Has-a" | | Object Independence | Objects are independent | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Objects exist separately | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | Teacher and Student | University and Professors | Car and Engine | --- ## Bidirectional Association Associations can be **unidirectional** (one object knows about another) or **bidirectional** (both objects know about each other). ### Example: A Library and Books (Bidirectional Association) ```go package main import "fmt" type Library struct { Name string Books []*Book } type Book struct { Title string Library *Library } func (l *Library) AddBook(b *Book) { l.Books = append(l.Books, b) } func (l *Library) ShowBooks() { fmt.Println("Books in", l.Name, ":") for _, book := range l.Books { fmt.Println(" -", book.Title) } } func (b *Book) ShowLibrary() { fmt.Println(b.Title, "is in", b.Library.Name) } func main() { library := Library{Name: "City Library"} book1 := Book{Title: "1984", Library: &library} book2 := Book{Title: "Brave New World", Library: &library} library.AddBook(&book1) library.AddBook(&book2) library.ShowBooks() book1.ShowLibrary() book2.ShowLibrary() } ``` ### Output: ``` Books in City Library: - 1984 - Brave New World 1984 is in City Library Brave New World is in City Library ``` ================================================ FILE: oop/golang/classesandobjects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? A class is a blueprint or template. It defines the attributes (fields) and behaviors (methods) of an object. ### Defining a Class in Go Go does not have traditional classes, but you can achieve similar behavior using `struct` and methods. Here's a simple example: ```go type Car struct { // Attributes Color string Make string Model string Year int } // Method defined with Car as the receiver func (c Car) DisplayInfo() { fmt.Println("Car Make: " + c.Make) fmt.Println("Car Model: " + c.Model) fmt.Println("Car Year:", c.Year) fmt.Println("Car Color: " + c.Color) } ``` - **Attributes**: The struct `Car` has four attributes that describe its state: `Color`, `Make`, `Model`, and `Year`. - **Methods**: The `DisplayInfo` function is responsible for showcasing the car details. ## What is an Object? An object is an instance of a struct. When you create an object, you are bringing the blueprint of the struct into reality. It consists of state and behavior defined by the struct, with each object holding its own copy of the data. ### Creating Objects in Go To create an object, you instantiate the struct `Car`. Here's how you can instantiate objects from the `Car` struct: ```go func main() { // Creating an object of the Car class car1 := Car{"Red", "Toyota", "Corolla", 2020} car2 := Car{"Blue", "Ford", "Mustang", 2021} // Displaying information of each car car1.DisplayInfo() fmt.Println("-----------------") car2.DisplayInfo() } ``` 1. **Instantiation**: The struct `Car` is used to create an object, which allocates memory for it. 2. **Initialization**: The struct instance holds its own set of values. 3. **Reference**: The object is referenced using a variable (`car1`, `car2`) that holds its memory location. ================================================ FILE: oop/golang/composition/README.md ================================================ # Composition in Golang ## Introduction Composition is one of the key concepts of object-oriented programming (OOP). It allows objects to be built using other objects, promoting code reuse, flexibility, and better maintainability. Unlike inheritance, which establishes an "is-a" relationship, composition represents a "has-a" relationship. ## What is Composition? Composition is a design principle in OOP where one struct contains an instance (or instances) of another struct as a field. The contained struct is often called a component, and the containing struct is referred to as a composite struct. This helps in building complex systems by combining simpler objects. ### Example: A Car and its Components Consider a `Car` that consists of multiple components like an `Engine`, `Wheel`, and `Transmission`. Instead of inheriting from these components, a `Car` object will contain them as fields. ```go package main import "fmt" type Engine struct { Horsepower int } func (e Engine) Start() { fmt.Printf("Engine started with %d HP.\n", e.Horsepower) } type Wheel struct { Type string } func (w Wheel) Rotate() { fmt.Printf("The %s wheel is rotating.\n", w.Type) } type Transmission struct { Type string } func (t Transmission) ShiftGear() { fmt.Printf("Transmission shifted: %s\n", t.Type) } type Car struct { Engine Engine Wheel Wheel Transmission Transmission } func NewCar() Car { return Car{ Engine: Engine{Horsepower: 150}, Wheel: Wheel{Type: "Alloy"}, Transmission: Transmission{Type: "Automatic"}, } } func (c Car) Drive() { c.Engine.Start() c.Wheel.Rotate() c.Transmission.ShiftGear() fmt.Println("Car is moving!") } func main() { car := NewCar() car.Drive() } ``` ### Output: ``` Engine started with 150 HP. The Alloy wheel is rotating. Transmission shifted: Automatic Car is moving! ``` --- ## Why Prefer Composition Over Inheritance? ### 1. **Encapsulation and Flexibility** - Composition allows us to change the behavior of an object dynamically by replacing components at runtime. - Inheritance makes it difficult to modify an existing class hierarchy without breaking existing code. ### 2. **Better Code Reusability** - Composition promotes reusable components. The `Engine`, `Wheel`, and `Transmission` structs can be used in multiple types of vehicles (Car, Bike, Truck) without modification. ### 3. **Avoids Inheritance Pitfalls** - Inheritance can lead to deep struct hierarchies, making maintenance difficult. - It enforces strict parent-child relationships, which can be too rigid for some designs. ### 4. **Supports Interface-Based Design** - Composition can be combined with interfaces to achieve powerful decoupling. --- ## Composition with Interfaces Using interfaces with composition allows for greater flexibility and loose coupling. ```go package main import "fmt" type Engine interface { Start() } type PetrolEngine struct {} func (p PetrolEngine) Start() { fmt.Println("Petrol Engine started.") } type DieselEngine struct {} func (d DieselEngine) Start() { fmt.Println("Diesel Engine started.") } type Car struct { engine Engine } func (c Car) StartCar() { c.engine.Start() fmt.Println("Car is ready to go!") } func main() { petrolCar := Car{engine: PetrolEngine{}} petrolCar.StartCar() dieselCar := Car{engine: DieselEngine{}} dieselCar.StartCar() } ``` ### Output: ``` Petrol Engine started. Car is ready to go! Diesel Engine started. Car is ready to go! ``` --- ## When to Use Composition? - When building complex objects that consist of multiple components. - When you want to achieve **code reusability** without rigid inheritance hierarchies. - When different behaviors need to be swapped dynamically (e.g., using different types of engines in a vehicle). - When following the **favor composition over inheritance** principle. ================================================ FILE: oop/golang/encapsulation/README.md ================================================ # Encapsulation in Golang ## Introduction **Encapsulation** is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the practice of **bundling data (variables) and methods** that operate on that data into a single unit (struct) while restricting direct access to the internal details. Encapsulation in Golang is achieved using: 1. **Exported and Unexported Fields (Visibility Control)** 2. **Getters and Setters (Methods for Data Access)** 3. **Data Hiding** Encapsulation helps in **data protection, modularity, and maintainability** of the code. ## **What is Encapsulation?** Encapsulation means **wrapping** the data (fields) and code (methods) together into a single unit (struct). It restricts direct access to some of an object's components, which helps protect data integrity and prevents unintended modifications. ### **Key Benefits of Encapsulation** - **Data Hiding**: Prevents direct access to sensitive data. - **Increased Security**: Controls how data is accessed and modified. - **Improved Code Maintainability**: Allows changes without affecting other parts of the code. - **Better Modularity**: Organizes the code into logical components. --- ## **Encapsulation Using Exported and Unexported Fields** Golang does not have traditional access modifiers like `private`, `protected`, or `public`. Instead, it uses **capitalization** to determine visibility: - **Exported fields (Public)**: Fields that start with an **uppercase letter** can be accessed outside the package. - **Unexported fields (Private)**: Fields that start with a **lowercase letter** are only accessible within the same package. ### **Example: Encapsulation with Unexported Fields** ```go package main import ( "fmt" ) // BankAccount struct with encapsulated data type BankAccount struct { accountHolder string // Unexported field (private) balance float64 // Unexported field (private) } // Constructor function to initialize BankAccount func NewBankAccount(holder string, balance float64) *BankAccount { return &BankAccount{accountHolder: holder, balance: balance} } // Getter method to access balance func (b *BankAccount) GetBalance() float64 { return b.balance } // Setter method to modify balance func (b *BankAccount) Deposit(amount float64) { if amount > 0 { b.balance += amount fmt.Println("Deposited:", amount) } else { fmt.Println("Invalid deposit amount") } } func main() { account := NewBankAccount("Alice", 1000) fmt.Println("Current Balance:", account.GetBalance()) account.Deposit(500) fmt.Println("Updated Balance:", account.GetBalance()) } ``` ### **Output:** ``` Current Balance: 1000 Deposited: 500 Updated Balance: 1500 ``` **Why Use Encapsulation?** - Prevents unauthorized access to the data. - Allows controlled modifications through methods. --- ## **Encapsulation Using Getters and Setters** Encapsulation ensures that **data cannot be directly accessed** but must be retrieved or modified through methods. ### **Example: Getters and Setters in Golang** ```go package main import ( "fmt" ) // Employee struct with private fields type Employee struct { name string age int } // Getter for name func (e *Employee) GetName() string { return e.name } // Setter for name func (e *Employee) SetName(name string) { e.name = name } // Getter for age func (e *Employee) GetAge() int { return e.age } // Setter for age with validation func (e *Employee) SetAge(age int) { if age > 18 { e.age = age } else { fmt.Println("Age must be greater than 18") } } func main() { emp := Employee{} emp.SetName("John Doe") emp.SetAge(25) fmt.Println("Employee Name:", emp.GetName()) fmt.Println("Employee Age:", emp.GetAge()) } ``` ### **Output:** ``` Employee Name: John Doe Employee Age: 25 ``` --- ## **Encapsulation and Data Hiding** Encapsulation helps **hide implementation details** while exposing only necessary methods. ### **Example: Hiding Implementation Details** ```go package main import ( "fmt" ) // Account struct with private balance type Account struct { balance float64 } // Constructor function func NewAccount(initialBalance float64) *Account { return &Account{balance: initialBalance} } // Private method for withdrawal validation func (a *Account) validateWithdrawal(amount float64) bool { return amount > 0 && amount <= a.balance } // Public method to withdraw func (a *Account) Withdraw(amount float64) { if a.validateWithdrawal(amount) { a.balance -= amount fmt.Println("Withdrawal Successful:", amount) } else { fmt.Println("Insufficient balance or invalid amount") } } // Getter for balance func (a *Account) GetBalance() float64 { return a.balance } func main() { myAccount := NewAccount(1000) myAccount.Withdraw(300) fmt.Println("Remaining Balance:", myAccount.GetBalance()) } ``` ### **Output:** ``` Withdrawal Successful: 300 Remaining Balance: 700 ``` **Why Hide Data?** - Prevents direct modification of important fields. - Ensures data integrity by validating inputs. --- ## **Encapsulation in Real-World Applications** Encapsulation is used in many real-world applications such as: 1. **Banking Systems** - Ensuring account details are private. 2. **Healthcare Applications** - Protecting patient records. 3. **E-Commerce Platforms** - Hiding payment processing details. ### **Example: Encapsulation in Payment Processing** ```go package main import ( "fmt" "strings" ) // PaymentProcessor struct type PaymentProcessor struct { cardNumber string amount float64 } // Constructor function func NewPaymentProcessor(cardNumber string, amount float64) *PaymentProcessor { return &PaymentProcessor{cardNumber: maskCardNumber(cardNumber), amount: amount} } // Private function to mask card number func maskCardNumber(cardNumber string) string { return "****-****-****-" + cardNumber[len(cardNumber)-4:] } // Public method to process payment func (p *PaymentProcessor) ProcessPayment() { fmt.Println("Processing payment of", p.amount, "for card", p.cardNumber) } func main() { payment := NewPaymentProcessor("1234567812345678", 250.00) payment.ProcessPayment() } ``` ### **Output:** ``` Processing payment of 250 for card ****-****-****-5678 ``` **Why Use Encapsulation in Payment Processing?** - Protects sensitive data (e.g., credit card numbers). - Hides unnecessary details from users. - Ensures secure transactions. ================================================ FILE: oop/golang/inheritance/README.md ================================================ # Inheritance in Go ## Introduction Unlike traditional OOP languages like Java and C++, **Go does not have classical inheritance**. Instead, Go achieves similar functionality using **struct embedding and interfaces**. This promotes **code reuse**, **composition over inheritance**, and **flexibility**. --- ## **What is Inheritance (or its Alternative in Go)?** Go does not support class-based inheritance. Instead, it uses **struct embedding**, which allows one struct to include another, inheriting its fields and methods. This achieves a similar effect to traditional inheritance. ### **Key Benefits of Struct Embedding in Go** - **Composition over Inheritance**: Encourages modular and maintainable design. - **Code Reusability**: Allows reusing functionality without rigid class hierarchies. - **Method Overriding**: Embedded structs’ methods can be overridden in the outer struct. - **Polymorphism**: Achieved using interfaces rather than class-based inheritance. --- ## **How to Implement Inheritance-like Behavior in Go** ### **Step 1: Define a Parent Struct** A struct in Go acts like a class with fields and methods. ```go package main import "fmt" // Parent struct type Animal struct { Name string } func (a Animal) Eat() { fmt.Println(a.Name, "is eating...") } ``` ### **Step 2: Embed the Parent Struct in a Child Struct** The `Dog` struct embeds `Animal`, inheriting its fields and methods. ```go // Child struct embedding Animal type Dog struct { Animal // Embedding Animal struct } func (d Dog) Bark() { fmt.Println(d.Name, "is barking...") } ``` ### **Step 3: Use the Child Struct** We create an instance of `Dog`, which has access to both `Animal` and `Dog` methods. ```go func main() { myDog := Dog{Animal{Name: "Buddy"}} myDog.Eat() // Inherited from Animal struct myDog.Bark() // Defined in Dog struct } ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Multiple Inheritance Alternative: Composition** Go does not support multiple inheritance, but struct embedding allows a struct to include multiple embedded structs. ```go // First embedded struct type Engine struct { Horsepower int } // Second embedded struct type Wheels struct { Count int } // Car struct embedding Engine and Wheels type Car struct { Engine Wheels } ``` ### **Usage** ```go func main() { myCar := Car{Engine{200}, Wheels{4}} fmt.Println("Horsepower:", myCar.Horsepower) fmt.Println("Wheels:", myCar.Count) } ``` ### **Output:** ``` Horsepower: 200 Wheels: 4 ``` --- ## **Method Overriding in Struct Embedding** A child struct can override an inherited method by defining a new method with the same name. ```go type Animal struct { Name string } func (a Animal) Speak() { fmt.Println(a.Name, "makes a sound") } // Overriding Speak method type Dog struct { Animal } func (d Dog) Speak() { fmt.Println(d.Name, "barks") } ``` ### **Usage** ```go func main() { myDog := Dog{Animal{Name: "Buddy"}} myDog.Speak() // Calls the overridden method } ``` ### **Output:** ``` Buddy barks ``` --- ## **Using Interfaces for Polymorphism** In Go, **interfaces** allow struct-based polymorphism, similar to inheritance in OOP languages. ```go type Animal interface { Speak() } type Dog struct { Name string } func (d Dog) Speak() { fmt.Println(d.Name, "barks") } ``` ### **Usage** ```go func main() { var myAnimal Animal = Dog{Name: "Buddy"} myAnimal.Speak() } ``` ### **Output:** ``` Buddy barks ``` ================================================ FILE: oop/golang/interfaces/README.md ================================================ # Interfaces in Go (Golang) ## Introduction In Object-Oriented Programming (OOP), an **interface** is a crucial concept that defines a contract for types to follow. It allows multiple types to share a common structure while enforcing certain behaviors. Unlike Java and C++, Go interfaces are **implicit**—a type satisfies an interface simply by implementing its methods. ## What is an Interface? An **interface** is a set of method signatures that a type must implement. It defines a contract that implementing types must adhere to. ### **Key Characteristics of Interfaces in Go** - Interfaces in Go are **implicit**, meaning types don’t explicitly declare they implement an interface. - They define **method signatures** that types must implement. - Interfaces **enable polymorphism**, allowing functions to operate on different types that share a common behavior. - They support **multiple interface implementation**, unlike struct embedding. --- ## **Defining and Implementing an Interface in Go** ### **Step 1: Define an Interface** To define an interface, we use the `interface` keyword. ```go package main import "fmt" // Defining an interface type Vehicle interface { Start() Stop() } ``` ### **Step 2: Implement the Interface** A type implements an interface by defining methods with the same signatures. ```go // Implementing the Vehicle interface in a Car struct type Car struct { brand string } func (c Car) Start() { fmt.Println("Car is starting...") } func (c Car) Stop() { fmt.Println("Car is stopping...") } ``` ### **Step 3: Using the Implemented Interface** Now, let's create an instance and call the methods. ```go func main() { var myCar Vehicle = Car{brand: "Toyota"} // Interface reference myCar.Start() myCar.Stop() } ``` ### **Output:** ``` Car is starting... Car is stopping... ``` --- ## **Multiple Interface Implementation in Go** Go allows a struct to implement multiple interfaces implicitly. ```go // First interface type Flyable interface { Fly() } // Second interface type Drivable interface { Drive() } // Implementing multiple interfaces type FlyingCar struct {} func (f FlyingCar) Fly() { fmt.Println("FlyingCar is flying...") } func (f FlyingCar) Drive() { fmt.Println("FlyingCar is driving...") } ``` ### **Usage** ```go func main() { var myVehicle Flyable = FlyingCar{} myVehicle.Fly() var myCar Drivable = FlyingCar{} myCar.Drive() } ``` ### **Output:** ``` FlyingCar is flying... FlyingCar is driving... ``` --- ## **Interface Composition in Go** Go interfaces can be composed of other interfaces. ```go type Engine interface { Start() Stop() } type Transmission interface { ShiftGear(gear int) } type CarInterface interface { Engine Transmission } ``` This means any type that implements `Start()`, `Stop()`, and `ShiftGear()` automatically implements `CarInterface`. --- ## **Real-World Example: Payment System** ```go type Payment interface { Pay(amount float64) } type CreditCardPayment struct {} func (c CreditCardPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using Credit Card\n", amount) } type PayPalPayment struct {} func (p PayPalPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using PayPal\n", amount) } ``` ### **Usage** ```go func main() { var payment1 Payment = CreditCardPayment{} payment1.Pay(100.50) var payment2 Payment = PayPalPayment{} payment2.Pay(200.75) } ``` ### **Output:** ``` Paid 100.50 using Credit Card Paid 200.75 using PayPal ``` ================================================ FILE: oop/golang/polymorphism/README.md ================================================ # Polymorphism in Object-Oriented Programming (OOP) in Golang ## Introduction **Polymorphism** is one of the fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. Polymorphism in Go is primarily achieved using **interfaces**, as Go does not support method overloading or classical inheritance like Java or C#. --- ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a method, function, or object to behave differently based on the context. Polymorphism enables **dynamic method resolution** and **method flexibility**, making applications easier to extend and maintain. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single interface that works for multiple types. - **Scalability**: Add new functionalities with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **Polymorphism using Interfaces in Go** Go achieves polymorphism through **interfaces**. An interface defines a set of method signatures, and any type that implements those methods satisfies the interface. ### **Example: Polymorphism using Interfaces** ```go package main import "fmt" // Define an interface type Animal interface { MakeSound() } // Implementing the interface in Dog type Dog struct{} func (d Dog) MakeSound() { fmt.Println("Dog barks") } // Implementing the interface in Cat type Cat struct{} func (c Cat) MakeSound() { fmt.Println("Cat meows") } func main() { var animal Animal animal = Dog{} animal.MakeSound() animal = Cat{} animal.MakeSound() } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Interfaces for Polymorphism?** - Provides a flexible and modular design. - Encourages dependency inversion and loose coupling. - Allows multiple types to satisfy the same interface. --- ## **Using Polymorphism with Functions** A common use of polymorphism in Go is passing different types to the same function. ```go package main import "fmt" // Define an interface type Vehicle interface { Start() } // Implementing the interface in Car type Car struct{} func (c Car) Start() { fmt.Println("Car is starting...") } // Implementing the interface in Bike type Bike struct{} func (b Bike) Start() { fmt.Println("Bike is starting...") } // Function that takes any Vehicle func StartVehicle(v Vehicle) { v.Start() } func main() { car := Car{} bike := Bike{} StartVehicle(car) StartVehicle(bike) } ``` ### **Output:** ``` Car is starting... Bike is starting... ``` **Why Use Function Parameters for Polymorphism?** - Allows flexible function behavior based on the type passed. - Enhances code modularity and testability. --- ## **Real-World Example: Payment System** A common real-world use case of polymorphism is in **payment processing**. ```go package main import "fmt" // Define an interface type Payment interface { Pay(amount float64) } // Implementing the interface in CreditCardPayment type CreditCardPayment struct{} func (c CreditCardPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using Credit Card\n", amount) } // Implementing the interface in PayPalPayment type PayPalPayment struct{} func (p PayPalPayment) Pay(amount float64) { fmt.Printf("Paid %.2f using PayPal\n", amount) } func main() { var payment Payment payment = CreditCardPayment{} payment.Pay(100.50) payment = PayPalPayment{} payment.Pay(200.75) } ``` ### **Output:** ``` Paid 100.50 using Credit Card Paid 200.75 using PayPal ``` **Why Use Polymorphism in Payment Systems?** - Allows new payment methods to be added **without modifying existing code**. - Provides a **flexible and scalable** design. - Improves **code readability and maintainability**. ================================================ FILE: oop/java/AggregationVsComposition/README.MD ================================================ # Aggregation vs Composition in Java (Code-Focused) In OOP, **Aggregation** and **Composition** both express "has-a" relationships, but they differ in **ownership**, **object lifecycle**, and **instantiation strategy**. --- ## 🔗 Aggregation — External Object Reference ### ✅ Key Code Characteristic: > The referenced object is **passed from outside** and can exist independently. ```java class Engine { String type; Engine(String type) { this.type = type; } } class Car { Engine engine; // Aggregation - reference passed from outside Car(Engine engine) { this.engine = engine; } void showEngineType() { System.out.println("Engine: " + engine.type); } } public class AggregationDemo { public static void main(String[] args) { Engine e1 = new Engine("V8"); // Created externally Car car1 = new Car(e1); // Shared with car1 Engine e2 = new Engine("V6"); Car car2 = new Car(e2); // Shared with car2 car1.showEngineType(); // Engine: V8 car2.showEngineType(); // Engine: V6 } } ``` **🧠 Key Point:** - `Car` does **not own** `Engine`. - The same `Engine` can be reused across multiple `Car` objects. - `Engine` can outlive or live independently of `Car`. --- ## 🔒 Composition — Object Created Internally ### ✅ Key Code Characteristic: > The referenced object is **created inside** the constructor. It **cannot exist without the parent.** ```java class Engine { String type; Engine(String type) { this.type = type; } } class Car { private Engine engine; // Composition - created inside Car(String engineType) { this.engine = new Engine(engineType); // tightly coupled } void showEngineType() { System.out.println("Engine: " + engine.type); } } public class CompositionDemo { public static void main(String[] args) { Car car = new Car("Electric"); // Engine is part of Car car.showEngineType(); // Engine: Electric } } ``` **🧠 Key Point:** - `Car` **fully owns** `Engine`. - `Engine` cannot be reused or accessed independently. - Lifecycle of `Engine` is strictly bound to `Car`. --- ## 🔍 Code-Level Differences Summary | Aspect | Aggregation | Composition | |------------------------|---------------------------------------------|--------------------------------------------| | Object creation | Object is passed from outside | Object is created internally | | Ownership | Parent has a reference | Parent owns the object | | Lifecycle dependency | Child can live without parent | Child dies with parent | | Reusability | Child can be reused by multiple parents | Child is bound to one parent only | | Code style | `this.child = child;` | `this.child = new Child();` or similar | --- ## 💡 When to Use - **Use Aggregation** when you want to share or reuse the same instance. - **Use Composition** when you want a part to be a core, non-detachable component of the object. --- ================================================ FILE: oop/java/abstraction/README.md ================================================ # Abstraction in Java ## Introduction **Abstraction** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows you to hide **implementation details** while exposing only the necessary parts of an object. This helps in reducing complexity and increasing maintainability. Abstraction in Java is mainly achieved using: 1. **Abstract Classes** 2. **Interfaces** --- ## **What is Abstraction?** **Abstraction** means showing only the **essential details** and hiding the **implementation**. It allows programmers to focus on **what an object does** rather than **how it does it**. ### **Key Benefits of Abstraction** - **Reduces complexity**: Hides unnecessary implementation details. - **Increases code reusability**: Encourages the reuse of abstracted logic. - **Enhances security**: Protects internal object details from unintended modifications. - **Improves maintainability**: Makes code easier to manage and update. --- ## **1. Abstraction Using Abstract Classes** An **abstract class** in Java is a class that cannot be instantiated. It is used to define common behavior that multiple subclasses should implement. ### **Example: Abstract Class in Java** ```java // Abstract class abstract class Vehicle { String brand; // Constructor Vehicle(String brand) { this.brand = brand; } // Abstract method (must be implemented by subclasses) abstract void start(); // Concrete method (can be inherited) void displayBrand() { System.out.println("Brand: " + brand); } } // Subclass implementing the abstract method class Car extends Vehicle { Car(String brand) { super(brand); } @Override void start() { System.out.println("Car is starting..."); } } public class Main { public static void main(String[] args) { Vehicle myCar = new Car("Toyota"); myCar.displayBrand(); myCar.start(); } } ``` ### **Output:** ``` Brand: Toyota Car is starting... ``` **Why Use Abstract Classes?** - Allows defining common behavior that subclasses must implement. - Enables partial abstraction (can have both abstract and concrete methods). - Prevents direct instantiation of base classes. --- ## **2. Abstraction Using Interfaces** An **interface** in Java is a blueprint that defines a contract for classes to follow. It contains **only abstract methods** (until Java 8 introduced default and static methods). ### **Example: Interface in Java** ```java // Defining an interface interface Animal { void makeSound(); // Abstract method } // Implementing the interface in Dog class class Dog implements Animal { @Override public void makeSound() { System.out.println("Dog barks"); } } // Implementing the interface in Cat class class Cat implements Animal { @Override public void makeSound() { System.out.println("Cat meows"); } } public class Main { public static void main(String[] args) { Animal myDog = new Dog(); myDog.makeSound(); Animal myCat = new Cat(); myCat.makeSound(); } } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Interfaces?** - Promotes **full abstraction** (hides all implementation details). - Supports **multiple inheritance** in Java (a class can implement multiple interfaces). - Provides a standard way for different classes to implement behaviors. --- ## **Abstract Class vs Interface: Key Differences** | Feature | Abstract Class | Interface | |------------------------|----------------------------------------------------|-----------------------------------------------| | **Inheritance** | A class **extends** only **one** abstract class | A class **implements multiple** interfaces | | **Methods** | Can have **abstract + concrete** methods | Only abstract methods (before Java 8) | | **Default Methods** | Concrete methods work without `default` keyword | Supports `default` methods (Java 8+) | | **Static Methods** | Can have static methods | Supports static methods (Java 8+) | | **Fields** | Can have **instance variables** (non-final) | Only **public static final** (constants) | | **Constructor** | Can have constructors | **No constructors** allowed | | **Multiple Inheritance** | Not supported (only **single** inheritance) | Supports **multiple** inheritance | | **Access Modifiers** | Methods/fields can be `public`, `protected`, `private`, or default | Methods are `public` by default | | **Purpose** | **Partial implementation** (code reuse) | **Full abstraction** (contract definition) | | **Object Creation** | Cannot be instantiated directly | Cannot be instantiated directly | | **`super` Keyword** | Can use `super()` to call parent constructor | No `super()` (no constructors) | | **Private Methods** | Supports `private` methods (Java 9+) | Supports `private` methods (Java 9+) | | **`final` Methods** | Can have `final` methods | Cannot have `final` methods | --- ## **Real-World Example: Payment System** Abstraction is widely used in real-world applications, such as payment processing. ### **Example: Payment System with Abstraction** ```java // Abstract class for Payment abstract class Payment { double amount; Payment(double amount) { this.amount = amount; } abstract void pay(); // Abstract method } // Implementing payment methods class CreditCardPayment extends Payment { CreditCardPayment(double amount) { super(amount); } @Override void pay() { System.out.println("Paid " + amount + " using Credit Card"); } } class PayPalPayment extends Payment { PayPalPayment(double amount) { super(amount); } @Override void pay() { System.out.println("Paid " + amount + " using PayPal"); } } public class Main { public static void main(String[] args) { Payment payment; payment = new CreditCardPayment(150.75); payment.pay(); payment = new PayPalPayment(200.50); payment.pay(); } } ``` ### **Output:** ``` Paid 150.75 using Credit Card Paid 200.50 using PayPal ``` **Why Use Abstraction in Payment Systems?** - Allows multiple payment methods without modifying existing code. - Improves maintainability and scalability. - Provides a **common contract** for different payment types. ================================================ FILE: oop/java/aggregation/README.md ================================================ # Aggregation in Java ## Introduction Aggregation is a key concept in object-oriented programming (OOP) that represents a "has-a" relationship between two classes, but with a crucial distinction: the lifecycle of the contained object is independent of the container object. This means that while one class contains another, the contained object can exist independently of the container. Aggregation allows for better modularity, code reuse, and maintainability. It is different from composition, where the contained object cannot exist without the container. --- ## What is Aggregation? Aggregation is a form of association in OOP where an object of one class contains a reference to an object of another class. However, the contained object can exist independently of the container. This means that even if the container object is destroyed, the contained object can still be used elsewhere in the application. ### Key Characteristics of Aggregation: - Represents a **has-a** relationship. - The contained object **can exist independently** of the container. - Implemented using references (pointers) to objects. - Promotes **loose coupling** between objects. ### Example: A University and its Professors Consider a scenario where a `University` contains multiple `Professor` objects. However, a `Professor` can exist independently of any university. This is an example of aggregation. ```java class Professor { private String name; private String subject; public Professor(String name, String subject) { this.name = name; this.subject = subject; } public String getName(){ return name; } public void teach() { System.out.println(name + " is teaching " + subject); } } class University { private String universityName; private List professors; public University(String universityName) { this.universityName = universityName; this.professors = new ArrayList<>(); } public void addProfessor(Professor professor) { professors.add(professor); } public void showProfessors() { System.out.println("Professors at " + universityName + ":"); for (Professor professor : professors) { System.out.println(" - " + professor.getName()); } } } import java.util.*; public class AggregationExample { public static void main(String[] args) { Professor prof1 = new Professor("Dr. Smith", "Computer Science"); Professor prof2 = new Professor("Dr. Johnson", "Mathematics"); University university = new University("Harvard University"); university.addProfessor(prof1); university.addProfessor(prof2); university.showProfessors(); // Professors can exist independently prof1.teach(); prof2.teach(); } } ``` ### Output: ``` Professors at Harvard University: - Dr. Smith - Dr. Johnson Dr. Smith is teaching Computer Science Dr. Johnson is teaching Mathematics ``` --- ## Aggregation vs Composition | Feature | Aggregation | Composition | |--------------|------------|-------------| | Relationship | "Has-a" | "Has-a" | | Ownership | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | University and Professors | Car and Engine | --- ## Why Use Aggregation? ### 1. **Promotes Code Reusability** - Aggregated objects can be used in multiple places without being tightly coupled to a single container class. ### 2. **Encourages Loose Coupling** - Aggregation allows objects to interact without being dependent on the lifecycle of each other. ### 3. **Better Maintainability** - Changes in one class do not heavily impact the other, making the codebase easier to modify and extend. ### 4. **Real-World Applicability** - Many real-world relationships, such as a school and its teachers, a company and its employees, naturally fit the aggregation model. --- ## Aggregation with Interfaces Using interfaces, we can further enhance the flexibility of aggregation. ```java interface Teachable { void teach(); } class Professor implements Teachable { private String name; private String subject; public Professor(String name, String subject) { this.name = name; this.subject = subject; } public void teach() { System.out.println(name + " is teaching " + subject); } } class University { private String universityName; private List professors; public University(String universityName) { this.universityName = universityName; this.professors = new ArrayList<>(); } public void addProfessor(Teachable professor) { professors.add(professor); } public void showProfessors() { System.out.println("Professors at " + universityName + ":"); for (Teachable professor : professors) { professor.teach(); } } } import java.util.*; public class InterfaceAggregationExample { public static void main(String[] args) { Professor prof1 = new Professor("Dr. Adams", "Physics"); Professor prof2 = new Professor("Dr. Lee", "Chemistry"); University university = new University("MIT"); university.addProfessor(prof1); university.addProfessor(prof2); university.showProfessors(); } } ``` ### Output: ``` Professors at MIT: Dr. Adams is teaching Physics Dr. Lee is teaching Chemistry ``` --- ## When to Use Aggregation? - When an object **can exist independently** from the container. - When designing **loosely coupled** systems. - When different objects need to be **shared** across multiple containers. - When following **SOLID principles**, particularly the **Dependency Inversion Principle (DIP)**. ================================================ FILE: oop/java/association/README.md ================================================ # Association in Object-Oriented Programming (OOP) ## Introduction Association is a key concept in object-oriented programming (OOP) that defines a relationship between two or more objects. It represents how objects interact with each other while maintaining their independence. Association is **not inheritance**—rather, it is a relationship between objects that allows communication while ensuring they remain loosely coupled. ## What is Association? Association defines a connection between two classes, where one class is linked to another. The association can be **one-to-one**, **one-to-many**, **many-to-one**, or **many-to-many**. Objects in an association can exist independently of each other. ### Key Characteristics of Association: - Represents a **uses-a** or **knows-a** relationship. - Objects in an association **can exist independently**. - Can be **unidirectional** or **bidirectional**. - Promotes **modularity** and **code reusability**. ### Example: A Student and a Teacher A `Student` can be associated with multiple `Teacher` objects, and a `Teacher` can have multiple `Student` objects. This represents a **many-to-many** association. ```java import java.util.*; class Teacher { private String name; private List students; public Teacher(String name) { this.name = name; this.students = new ArrayList<>(); } public void addStudent(Student student) { students.add(student); } public void showStudents() { System.out.println(name + " teaches:"); for (Student student : students) { System.out.println(" - " + student.getName()); } } public String getName() { return name; } } class Student { private String name; public Student(String name) { this.name = name; } public String getName() { return name; } } public class AssociationExample { public static void main(String[] args) { Teacher teacher1 = new Teacher("Mr. Smith"); Teacher teacher2 = new Teacher("Mrs. Johnson"); Student student1 = new Student("Alice"); Student student2 = new Student("Bob"); teacher1.addStudent(student1); teacher1.addStudent(student2); teacher2.addStudent(student2); teacher1.showStudents(); teacher2.showStudents(); } } ``` ### Output: ``` Mr. Smith teaches: - Alice - Bob Mrs. Johnson teaches: - Bob ``` --- ## Types of Association ### 1. **One-to-One Association** - Each object of class A is associated with one object of class B. - Example: A `Person` has one `Passport`. ### 2. **One-to-Many Association** - One object of class A can be associated with multiple objects of class B. - Example: A `Teacher` teaches multiple `Students`. ### 3. **Many-to-One Association** - Multiple objects of class A can be associated with one object of class B. - Example: Multiple `Students` belong to one `School`. ### 4. **Many-to-Many Association** - Multiple objects of class A can be associated with multiple objects of class B. - Example: `Teachers` and `Students` (a student can have multiple teachers, and a teacher can have multiple students). --- ## Why Use Association? ### 1. **Promotes Code Reusability** - Objects can be reused across multiple associations without duplication. ### 2. **Encourages Loose Coupling** - Objects interact without depending on the internal implementation of each other. ### 3. **Improves Maintainability** - Changing one object does not heavily impact others, making code easier to manage. ### 4. **Better System Design** - Allows modeling of real-world relationships between entities effectively. --- ## Association vs Aggregation vs Composition | Feature | Association | Aggregation | Composition | |--------------|------------|------------|------------| | Relationship | "Knows-a" | "Has-a" | "Has-a" | | Object Independence | Objects are independent | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Objects exist separately | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | Teacher and Student | University and Professors | Car and Engine | --- ## Bidirectional Association Associations can be **unidirectional** (one object knows about another) or **bidirectional** (both objects know about each other). ### Example: A Library and Books (Bidirectional Association) ```java import java.util.*; class Book { private String title; private Library library; public Book(String title, Library library) { this.title = title; this.library = library; } public void showLibrary() { System.out.println(title + " is in " + library.getName()); } public String getTitle() { return title; } } class Library { private String name; private List books; public Library(String name) { this.name = name; this.books = new ArrayList<>(); } public void addBook(Book book) { books.add(book); } public String getName() { return name; } public void showBooks() { System.out.println("Books in " + name + ":"); for (Book book : books) { System.out.println(" - " + book.getTitle()); } } } public class BidirectionalAssociationExample { public static void main(String[] args) { Library library = new Library("City Library"); Book book1 = new Book("1984", library); Book book2 = new Book("Brave New World", library); library.addBook(book1); library.addBook(book2); library.showBooks(); book1.showLibrary(); book2.showLibrary(); } } ``` ### Output: ``` Books in City Library: - 1984 - Brave New World 1984 is in City Library Brave New World is in City Library ``` ================================================ FILE: oop/java/classesandobjects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? A class is a blueprint or template. It defines the attributes (fields) and behaviors (methods) of an object. ### Defining a Class in Java To define a class in Java, you use the `class` keyword followed by the name of the class. Here's a simple example: ```java public class Car { // Attributes private String color; private String make; private String model; private int year; // Constructor public Car(String color, String make, String model, int year) { this.color = color; this.make = make; this.model = model; this.year = year; } // Method to display car details public void displayInfo() { System.out.println("Car Make: " + make); System.out.println("Car Model: " + model); System.out.println("Car Year: " + year); System.out.println("Car Color: " + color); } } ``` - **Attributes**: The class `Car` has four attributes that describe its state: `color`, `make`, `model`, and `year`. - **Constructor**: The constructor `Car(String color, String make, String model, int year)` initializes new objects of the class. - **Methods**: The `displayInfo` method is responsible for showcasing the car details. ## What is an Object? An object is an instance of a class. When you create an object, you are bringing the blueprint of the class into reality. It consists of state and behavior defined by the class, with each object holding its own copy of the data. ### Creating Objects in Java To create an object, you use the `new` keyword followed by the class constructor. Here's how you can instantiate objects from the `Car` class: ```java public class Main { public static void main(String[] args) { // Creating an object of the Car class Car car1 = new Car("Red", "Toyota", "Corolla", 2020); Car car2 = new Car("Blue", "Ford", "Mustang", 2021); // Displaying information of each car car1.displayInfo(); System.out.println("-----------------"); car2.displayInfo(); } } ``` 1. **Instantiation**: The `new` keyword is used to create an object, which allocates memory for it. 2. **Initialization**: The constructor (`Car`) initializes the object state with given parameters. 3. **Reference**: The object is referenced through a variable (`car1`, `car2`) that points to its memory location. ================================================ FILE: oop/java/composition/README.md ================================================ # Composition in Java ## Introduction Composition is one of the key concepts of object-oriented programming (OOP). It allows objects to be built using other objects, promoting code reuse, flexibility, and better maintainability. Unlike inheritance, which establishes an "is-a" relationship, composition represents a "has-a" relationship. ## What is Composition? Composition is a design principle in OOP where one class contains an instance (or instances) of another class as a field. The contained class is often called a component, and the containing class is referred to as a composite class. This helps in building complex systems by combining simpler objects. ### Example: A Car and its Components Consider a `Car` that consists of multiple components like an `Engine`, `Wheel`, and `Transmission`. Instead of inheriting from these components, a `Car` object will contain them as fields. ```java class Engine { private int horsepower; public Engine(int horsepower) { this.horsepower = horsepower; } public void start() { System.out.println("Engine started with " + horsepower + " HP."); } } class Wheel { private String type; public Wheel(String type) { this.type = type; } public void rotate() { System.out.println("The " + type + " wheel is rotating."); } } class Transmission { private String type; public Transmission(String type) { this.type = type; } public void shiftGear() { System.out.println("Transmission shifted: " + type); } } class Car { private Engine engine; private Wheel wheel; private Transmission transmission; public Car(Engine engine, Wheel wheel, Transmission transmission) { this.engine = engine; this.wheel = wheel; this.transmission = transmission; } public void drive() { engine.start(); wheel.rotate(); transmission.shiftGear(); System.out.println("Car is moving!"); } } public class CompositionExample { public static void main(String[] args) { Car car = new Car(new Engine(150), new Wheel("Alloy"), new Transmission("Automatic")); car.drive(); } } ``` ### Output: ``` Engine started with 150 HP. The Alloy wheel is rotating. Transmission shifted: Automatic Car is moving! ``` --- ## Why Prefer Composition Over Inheritance? ### 1. **Encapsulation and Flexibility** - Composition allows us to change the behavior of an object dynamically by replacing components at runtime. - Inheritance makes it difficult to modify an existing class hierarchy without breaking existing code. ### 2. **Better Code Reusability** - Composition promotes reusable components. The `Engine`, `Wheel`, and `Transmission` classes can be used in multiple types of vehicles (Car, Bike, Truck) without modification. ### 3. **Avoids Inheritance Pitfalls** - Inheritance can lead to deep class hierarchies, making maintenance difficult. - It enforces strict parent-child relationships, which can be too rigid for some designs. ### 4. **Supports Interface-Based Design** - Composition can be combined with interfaces to achieve powerful decoupling. --- ## Composition with Interfaces Using interfaces with composition allows for greater flexibility and loose coupling. ```java interface Engine { void start(); } class PetrolEngine implements Engine { public void start() { System.out.println("Petrol Engine started."); } } class DieselEngine implements Engine { public void start() { System.out.println("Diesel Engine started."); } } class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } public void startCar() { engine.start(); System.out.println("Car is ready to go!"); } } public class InterfaceCompositionExample { public static void main(String[] args) { Car petrolCar = new Car(new PetrolEngine()); petrolCar.startCar(); Car dieselCar = new Car(new DieselEngine()); dieselCar.startCar(); } } ``` ### Output: ``` Petrol Engine started. Car is ready to go! Diesel Engine started. Car is ready to go! ``` --- ## When to Use Composition? - When building complex objects that consist of multiple components. - When you want to achieve **code reusability** without rigid inheritance hierarchies. - When different behaviors need to be swapped dynamically (e.g., using different types of engines in a vehicle). - When following the **favor composition over inheritance** principle. ================================================ FILE: oop/java/encapsulation/README.md ================================================ # Encapsulation in Java ## Introduction **Encapsulation** is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the practice of **bundling data (variables) and methods** that operate on that data into a single unit (class) while restricting direct access to the internal details. Encapsulation in Java is achieved using: 1. **Access Modifiers** (`private`, `protected`, `public`) 2. **Getters and Setters** 3. **Data Hiding** Encapsulation helps in **data protection, modularity, and maintainability** of the code. --- ## **What is Encapsulation?** Encapsulation means **wrapping** the data (variables) and code (methods) together into a single unit (class). It restricts direct access to some of an object's components, which helps protect data integrity and prevents unintended modifications. ### **Key Benefits of Encapsulation** - **Data Hiding**: Prevents direct access to sensitive data. - **Increased Security**: Controls how data is accessed and modified. - **Improved Code Maintainability**: Allows changes without affecting other parts of the code. - **Better Modularity**: Organizes the code into logical components. --- ## **Encapsulation Using Access Modifiers** Java provides **access modifiers** to enforce encapsulation: - **`private`**: Accessible only within the same class. - **`protected`**: Accessible within the same package and subclasses. - **`public`**: Accessible from anywhere. ### **Example: Encapsulation with Private Variables** ```java // Class with encapsulated data class BankAccount { private String accountHolder; private double balance; // Constructor public BankAccount(String accountHolder, double balance) { this.accountHolder = accountHolder; this.balance = balance; } // Getter method to access balance public double getBalance() { return balance; } // Setter method to modify balance public void deposit(double amount) { if (amount > 0) { balance += amount; System.out.println("Deposited: " + amount); } else { System.out.println("Invalid deposit amount"); } } } public class Main { public static void main(String[] args) { BankAccount account = new BankAccount("Alice", 1000); System.out.println("Current Balance: " + account.getBalance()); account.deposit(500); System.out.println("Updated Balance: " + account.getBalance()); } } ``` ### **Output:** ``` Current Balance: 1000.0 Deposited: 500.0 Updated Balance: 1500.0 ``` **Why Use Encapsulation?** - Prevents unauthorized access to the data. - Allows controlled modifications through methods. --- ## **Encapsulation Using Getters and Setters** Encapsulation ensures that **data cannot be directly accessed** but must be retrieved or modified through methods. ### **Example: Getters and Setters in Java** ```java class Employee { private String name; private int age; // Getter method public String getName() { return name; } // Setter method public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { if (age > 18) { this.age = age; } else { System.out.println("Age must be greater than 18"); } } } public class Main { public static void main(String[] args) { Employee emp = new Employee(); emp.setName("John Doe"); emp.setAge(25); System.out.println("Employee Name: " + emp.getName()); System.out.println("Employee Age: " + emp.getAge()); } } ``` ### **Output:** ``` Employee Name: John Doe Employee Age: 25 ``` --- ## **Encapsulation and Data Hiding** Encapsulation helps **hide implementation details** while exposing only necessary methods. ### **Example: Hiding Implementation Details** ```java class Account { private double balance; public Account(double initialBalance) { this.balance = initialBalance; } private boolean validateWithdrawal(double amount) { return amount > 0 && amount <= balance; } public void withdraw(double amount) { if (validateWithdrawal(amount)) { balance -= amount; System.out.println("Withdrawal Successful: " + amount); } else { System.out.println("Insufficient balance or invalid amount"); } } public double getBalance() { return balance; } } public class Main { public static void main(String[] args) { Account myAccount = new Account(1000); myAccount.withdraw(300); System.out.println("Remaining Balance: " + myAccount.getBalance()); } } ``` ### **Output:** ``` Withdrawal Successful: 300.0 Remaining Balance: 700.0 ``` **Why Hide Data?** - Prevents direct modification of important fields. - Ensures data integrity by validating inputs. --- ## **Encapsulation in Real-World Applications** Encapsulation is used in many real-world applications such as: 1. **Banking Systems** - Ensuring account details are private. 2. **Healthcare Applications** - Protecting patient records. 3. **E-Commerce Platforms** - Hiding payment processing details. ### **Example: Encapsulation in Payment Processing** ```java class PaymentProcessor { private String cardNumber; private double amount; public PaymentProcessor(String cardNumber, double amount) { this.cardNumber = maskCardNumber(cardNumber); this.amount = amount; } private String maskCardNumber(String cardNumber) { return "****-****-****-" + cardNumber.substring(cardNumber.length() - 4); } public void processPayment() { System.out.println("Processing payment of " + amount + " for card " + cardNumber); } } public class Main { public static void main(String[] args) { PaymentProcessor payment = new PaymentProcessor("1234567812345678", 250.00); payment.processPayment(); } } ``` ### **Output:** ``` Processing payment of 250.0 for card ****-****-****-5678 ``` **Why Use Encapsulation in Payment Processing?** - Protects sensitive data (e.g., credit card numbers). - Hides unnecessary details from users. - Ensures secure transactions. ================================================ FILE: oop/java/inheritance/README.md ================================================ # Inheritance in Object-Oriented Programming (OOP) ## Introduction **Inheritance** is one of the core principles of Object-Oriented Programming (OOP). It allows a class (subclass or child class) to acquire the properties and behaviors of another class (superclass or parent class). This promotes **code reuse**, **scalability**, and **maintainability**. ## **What is Inheritance?** **Inheritance** is a mechanism where a child class derives properties and behaviors from a parent class. The child class can: - Use the fields and methods of the parent class - Override parent class methods to provide a specific implementation - Add its own additional properties and methods ### **Key Benefits of Inheritance** - **Code Reusability**: Avoids code duplication by reusing fields and methods of the parent class. - **Improves Maintainability**: Reduces redundancy, making code easier to manage. - **Enhances Extensibility**: New functionality can be added easily without modifying existing code. --- ## **How to Implement Inheritance in Java** ### **Step 1: Create a Parent Class** The parent class contains common fields and methods. ```java // Parent class public class Animal { String name; void eat() { System.out.println(name + " is eating..."); } } ``` ### **Step 2: Create a Child Class using `extends`** The child class inherits the properties and methods of the parent class. ```java // Child class public class Dog extends Animal { void bark() { System.out.println(name + " is barking..."); } } ``` ### **Step 3: Use the Child Class** Now, let's create an object and use the inherited methods. ```java public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.name = "Buddy"; myDog.eat(); // Inherited from Animal class myDog.bark(); // Defined in Dog class } } ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Types of Inheritance in Java** Java supports different types of inheritance: ### **1. Single Inheritance** A subclass inherits from one superclass. ```java class Parent { void show() { System.out.println("This is the parent class"); } } class Child extends Parent { void display() { System.out.println("This is the child class"); } } ``` ### **2. Multilevel Inheritance** A subclass inherits from another subclass, forming a chain. ```java class Grandparent { void show() { System.out.println("Grandparent class"); } } class Parent extends Grandparent { void display() { System.out.println("Parent class"); } } class Child extends Parent { void print() { System.out.println("Child class"); } } ``` ### **3. Hierarchical Inheritance** A single parent class has multiple child classes. ```java class Parent { void show() { System.out.println("Parent class"); } } class Child1 extends Parent { void display() { System.out.println("Child1 class"); } } class Child2 extends Parent { void print() { System.out.println("Child2 class"); } } ``` **Note:** Java **does not support multiple inheritance** (i.e., a child class inheriting from multiple parents) due to ambiguity problems. --- ## **Method Overriding in Inheritance** Method overriding allows a child class to **redefine** a method from the parent class. ```java class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void makeSound() { System.out.println("Dog barks"); } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { Animal myAnimal = new Dog(); // Polymorphism myAnimal.makeSound(); } } ``` ### **Output:** ``` Dog barks ``` --- ## **The `super` Keyword in Inheritance** The `super` keyword is used to **refer to the parent class**. It helps to: 1. Call the parent class constructor. 2. Access the parent class methods. 3. Access the parent class fields. ```java class Animal { Animal() { System.out.println("Animal Constructor"); } void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { Dog() { super(); // Calls the parent class constructor System.out.println("Dog Constructor"); } void makeSound() { super.makeSound(); // Calls parent method System.out.println("Dog barks"); } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.makeSound(); } } ``` ### **Output:** ``` Animal Constructor Dog Constructor Animal makes a sound Dog barks ``` ================================================ FILE: oop/java/interfaces/README.md ================================================ # Interfaces ## Introduction In Object-Oriented Programming (OOP), an **interface** is a crucial concept that defines a contract for classes to follow. It allows multiple classes to share a common structure while enforcing certain behaviors. Interfaces are widely used in Java and other OOP languages to achieve **abstraction, polymorphism, and loose coupling**. ## What is an Interface? An **interface** in Java is a collection of abstract methods (methods without implementation) that a class can implement. It defines a contract that the implementing classes must adhere to. ### **Key Characteristics of Interfaces** - Defines a **contract** that implementing classes must follow. - Cannot have instance variables (only `public static final` constants). - All methods are **implicitly public and abstract** (unless they have a default or static implementation). - Supports **multiple inheritance**, unlike classes. - Improves **code flexibility and testability**. --- ## **Defining and Implementing an Interface in Java** ### **Step 1: Define an Interface** To define an interface, use the `interface` keyword. ```java // Defining an interface public interface Vehicle { void start(); // Abstract method (no implementation) void stop(); // Abstract method (no implementation) } ``` ### **Step 2: Implement the Interface** A class implements an interface using the `implements` keyword. ```java // Implementing the Vehicle interface in a Car class public class Car implements Vehicle { @Override public void start() { System.out.println("Car is starting..."); } @Override public void stop() { System.out.println("Car is stopping..."); } } ``` ### **Step 3: Using the Implemented Class** Now, let's create objects and call the methods. ```java public class Main { public static void main(String[] args) { Vehicle myCar = new Car(); // Polymorphism: Interface reference myCar.start(); myCar.stop(); } } ``` ### **Output:** ``` Car is starting... Car is stopping... ``` --- ## **Multiple Inheritance with Interfaces** Unlike C++, Java **does not support multiple inheritance** with classes, but it does support **multiple inheritance** with interfaces. ```java // First interface interface Flyable { void fly(); } // Second interface interface Drivable { void drive(); } // Implementing multiple interfaces public class FlyingCar implements Flyable, Drivable { @Override public void fly() { System.out.println("FlyingCar is flying..."); } @Override public void drive() { System.out.println("FlyingCar is driving..."); } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { FlyingCar myVehicle = new FlyingCar(); myVehicle.fly(); myVehicle.drive(); } } ``` ### **Output:** ``` FlyingCar is flying... FlyingCar is driving... ``` --- ## **Default and Static Methods in Interfaces** ### **Default Methods** Java 8 introduced **default methods** in interfaces, allowing methods with a body. ```java interface Animal { void sound(); // Default method with implementation default void sleep() { System.out.println("Sleeping..."); } } class Dog implements Animal { @Override public void sound() { System.out.println("Dog barks"); } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.sound(); myDog.sleep(); // Calling default method } } ``` ### **Output:** ``` Dog barks Sleeping... ``` ### **Static Methods** Interfaces can also have **static methods**. ```java interface MathOperations { static int add(int a, int b) { return a + b; } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { int result = MathOperations.add(5, 10); System.out.println("Sum: " + result); } } ``` ### **Output:** ``` Sum: 15 ``` --- ## **Real-World Example: Payment System** ```java interface Payment { void pay(double amount); } class CreditCardPayment implements Payment { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using Credit Card"); } } class PayPalPayment implements Payment { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using PayPal"); } } ``` ### **Usage** ```java public class Main { public static void main(String[] args) { Payment payment1 = new CreditCardPayment(); payment1.pay(100.50); Payment payment2 = new PayPalPayment(); payment2.pay(200.75); } } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` ================================================ FILE: oop/java/polymorphism/README.md ================================================ # Polymorphism in Java ## Introduction **Polymorphism** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. Polymorphism in Java can be classified into two types: 1. **Compile-time Polymorphism (Method Overloading)** 2. **Run-time Polymorphism (Method Overriding)** ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a method, function, or object to behave differently based on the context. Polymorphism enables **dynamic method resolution** and **method flexibility**, making applications easier to extend and maintain. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single interface that works for multiple types. - **Scalability**: Add new functionalities with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **1. Compile-Time Polymorphism (Method Overloading)** Compile-time polymorphism occurs when multiple methods in the same class share the same name but have **different method signatures** (parameters). The method to be called is determined **at compile time**. ### **Example of Method Overloading** ```java class MathOperations { // Method with two parameters int add(int a, int b) { return a + b; } // Method with three parameters (overloaded) int add(int a, int b, int c) { return a + b + c; } } public class Main { public static void main(String[] args) { MathOperations math = new MathOperations(); System.out.println("Sum (2 numbers): " + math.add(5, 10)); System.out.println("Sum (3 numbers): " + math.add(5, 10, 15)); } } ``` ### **Output:** ``` Sum (2 numbers): 15 Sum (3 numbers): 30 ``` **Why Use Method Overloading?** - Provides a cleaner and more intuitive interface. - Reduces redundancy by using a single method name for similar operations. --- ## **2. Run-Time Polymorphism (Method Overriding)** Run-time polymorphism occurs when a subclass provides a **specific implementation** of a method already defined in its parent class. The method to be called is determined **at runtime**. ### **Example of Method Overriding** ```java class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void makeSound() { System.out.println("Dog barks"); } } class Cat extends Animal { @Override void makeSound() { System.out.println("Cat meows"); } } public class Main { public static void main(String[] args) { Animal myAnimal = new Dog(); // Upcasting myAnimal.makeSound(); myAnimal = new Cat(); // Dynamic method dispatch myAnimal.makeSound(); } } ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Method Overriding?** - Enables **dynamic method resolution**. - Supports **polymorphic behavior**, where one interface can be used for multiple implementations. - Makes code **extensible** by allowing future modifications. --- ## **Using Polymorphism with Interfaces** Polymorphism is widely used with **interfaces**, allowing multiple classes to share a common contract. ```java interface Vehicle { void start(); } class Car implements Vehicle { public void start() { System.out.println("Car is starting..."); } } class Bike implements Vehicle { public void start() { System.out.println("Bike is starting..."); } } public class Main { public static void main(String[] args) { Vehicle myVehicle = new Car(); myVehicle.start(); myVehicle = new Bike(); myVehicle.start(); } } ``` ### **Output:** ``` Car is starting... Bike is starting... ``` **Why Use Interfaces with Polymorphism?** - Promotes **loose coupling**, making code more flexible. - Allows multiple implementations of the same behavior. - Enables **dependency injection**, improving testability. --- ## **Real-World Example: Payment System** A common real-world use case of polymorphism is in **payment processing**. ```java interface Payment { void pay(double amount); } class CreditCardPayment implements Payment { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using Credit Card"); } } class PayPalPayment implements Payment { @Override public void pay(double amount) { System.out.println("Paid " + amount + " using PayPal"); } } public class Main { public static void main(String[] args) { Payment payment; payment = new CreditCardPayment(); payment.pay(100.50); payment = new PayPalPayment(); payment.pay(200.75); } } ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` **Why Use Polymorphism in Payment Systems?** - Allows new payment methods to be added **without modifying existing code**. - Provides a **flexible and scalable** design. - Improves **code readability and maintainability**. ================================================ FILE: oop/python/abstraction/README.md ================================================ # Abstraction in Python ## Introduction **Abstraction** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows you to hide **implementation details** while exposing only the necessary parts of an object. This helps in reducing complexity and increasing maintainability. Abstraction in Python is mainly achieved using: 1. **Abstract Classes** 2. **Interfaces (via Abstract Base Classes - ABCs)** ## **What is Abstraction?** **Abstraction** means showing only the **essential details** and hiding the **implementation**. It allows programmers to focus on **what an object does** rather than **how it does it**. ### **Key Benefits of Abstraction** - **Reduces complexity**: Hides unnecessary implementation details. - **Increases code reusability**: Encourages the reuse of abstracted logic. - **Enhances security**: Protects internal object details from unintended modifications. - **Improves maintainability**: Makes code easier to manage and update. --- ## **1. Abstraction Using Abstract Classes** An **abstract class** in Python is a class that **cannot be instantiated**. It is used to define common behavior that multiple subclasses should implement. Python provides the `ABC` module to define abstract classes. ### **Example: Abstract Class in Python** ```python from abc import ABC, abstractmethod # Abstract class class Vehicle(ABC): def __init__(self, brand): self.brand = brand @abstractmethod def start(self): pass # Abstract method (must be implemented by subclasses) def display_brand(self): print(f"Brand: {self.brand}") # Subclass implementing the abstract method class Car(Vehicle): def start(self): print("Car is starting...") # Usage my_car = Car("Toyota") my_car.display_brand() my_car.start() ``` ### **Output:** ``` Brand: Toyota Car is starting... ``` **Why Use Abstract Classes?** - Allows defining common behavior that subclasses must implement. - Enables partial abstraction (can have both abstract and concrete methods). - Prevents direct instantiation of base classes. --- ## **2. Abstraction Using Interfaces (Abstract Base Classes - ABCs)** An **interface** in Python can be implemented using **Abstract Base Classes (ABCs)**, which enforce method implementation. ### **Example: Interface in Python** ```python from abc import ABC, abstractmethod # Defining an interface class Animal(ABC): @abstractmethod def make_sound(self): pass # Implementing the interface in Dog class class Dog(Animal): def make_sound(self): print("Dog barks") # Implementing the interface in Cat class class Cat(Animal): def make_sound(self): print("Cat meows") # Usage my_dog = Dog() my_dog.make_sound() my_cat = Cat() my_cat.make_sound() ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Interfaces?** - Promotes **full abstraction** (hides all implementation details). - Provides a standard way for different classes to implement behaviors. --- ## **Abstract Class vs Interface: Key Differences** | Feature | Abstract Class | Interface (ABCs) | |---------|---------------|------------------| | Methods | Can have abstract and concrete methods | Only abstract methods | | Fields | Can have instance variables | Should not have instance variables | | Constructor | Can have constructors | Cannot have constructors | | Multiple Inheritance | Supported | Supported | | Access Modifiers | Can have private, protected, public members | Methods are public by default | --- ## **Real-World Example: Payment System** Abstraction is widely used in real-world applications, such as payment processing. ### **Example: Payment System with Abstraction** ```python from abc import ABC, abstractmethod # Abstract class for Payment class Payment(ABC): def __init__(self, amount): self.amount = amount @abstractmethod def pay(self): pass # Implementing payment methods class CreditCardPayment(Payment): def pay(self): print(f"Paid {self.amount} using Credit Card") class PayPalPayment(Payment): def pay(self): print(f"Paid {self.amount} using PayPal") # Usage payment = CreditCardPayment(150.75) payment.pay() payment = PayPalPayment(200.50) payment.pay() ``` ### **Output:** ``` Paid 150.75 using Credit Card Paid 200.50 using PayPal ``` **Why Use Abstraction in Payment Systems?** - Allows multiple payment methods without modifying existing code. - Improves maintainability and scalability. - Provides a **common contract** for different payment types. ================================================ FILE: oop/python/aggregation/README.md ================================================ # Aggregation in Python ## Introduction Aggregation is a key concept in object-oriented programming (OOP) that represents a "has-a" relationship between two classes, but with a crucial distinction: the lifecycle of the contained object is independent of the container object. This means that while one class contains another, the contained object can exist independently of the container. Aggregation allows for better modularity, code reuse, and maintainability. It is different from composition, where the contained object cannot exist without the container. ## What is Aggregation? Aggregation is a form of association in OOP where an object of one class contains a reference to an object of another class. However, the contained object can exist independently of the container. This means that even if the container object is destroyed, the contained object can still be used elsewhere in the application. ### Key Characteristics of Aggregation: - Represents a **has-a** relationship. - The contained object **can exist independently** of the container. - Implemented using references to objects. - Promotes **loose coupling** between objects. ### Example: A University and its Professors Consider a scenario where a `University` contains multiple `Professor` objects. However, a `Professor` can exist independently of any university. This is an example of aggregation. ```python class Professor: def __init__(self, name, subject): self.name = name self.subject = subject def teach(self): print(f"{self.name} is teaching {self.subject}") class University: def __init__(self, university_name): self.university_name = university_name self.professors = [] def add_professor(self, professor): self.professors.append(professor) def show_professors(self): print(f"Professors at {self.university_name}:") for professor in self.professors: print(f" - {professor.name}") # Example Usage if __name__ == "__main__": prof1 = Professor("Dr. Smith", "Computer Science") prof2 = Professor("Dr. Johnson", "Mathematics") university = University("Harvard University") university.add_professor(prof1) university.add_professor(prof2) university.show_professors() # Professors can exist independently prof1.teach() prof2.teach() ``` ### Output: ``` Professors at Harvard University: - Dr. Smith - Dr. Johnson Dr. Smith is teaching Computer Science Dr. Johnson is teaching Mathematics ``` --- ## Aggregation vs Composition | Feature | Aggregation | Composition | |--------------|------------|-------------| | Relationship | "Has-a" | "Has-a" | | Ownership | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | University and Professors | Car and Engine | --- ## Why Use Aggregation? ### 1. **Promotes Code Reusability** - Aggregated objects can be used in multiple places without being tightly coupled to a single container class. ### 2. **Encourages Loose Coupling** - Aggregation allows objects to interact without being dependent on the lifecycle of each other. ### 3. **Better Maintainability** - Changes in one class do not heavily impact the other, making the codebase easier to modify and extend. ### 4. **Real-World Applicability** - Many real-world relationships, such as a school and its teachers, a company and its employees, naturally fit the aggregation model. --- ## Aggregation with Interfaces (Abstract Base Classes) Using abstract base classes, we can further enhance the flexibility of aggregation. ```python from abc import ABC, abstractmethod class Teachable(ABC): @abstractmethod def teach(self): pass class Professor(Teachable): def __init__(self, name, subject): self.name = name self.subject = subject def teach(self): print(f"{self.name} is teaching {self.subject}") class University: def __init__(self, university_name): self.university_name = university_name self.professors = [] def add_professor(self, professor): self.professors.append(professor) def show_professors(self): print(f"Professors at {self.university_name}:") for professor in self.professors: professor.teach() # Example Usage if __name__ == "__main__": prof1 = Professor("Dr. Adams", "Physics") prof2 = Professor("Dr. Lee", "Chemistry") university = University("MIT") university.add_professor(prof1) university.add_professor(prof2) university.show_professors() ``` ### Output: ``` Professors at MIT: Dr. Adams is teaching Physics Dr. Lee is teaching Chemistry ``` --- ## When to Use Aggregation? - When an object **can exist independently** from the container. - When designing **loosely coupled** systems. - When different objects need to be **shared** across multiple containers. - When following **SOLID principles**, particularly the **Dependency Inversion Principle (DIP)**. ================================================ FILE: oop/python/association/README.md ================================================ # Association in Python ## Introduction Association is a key concept in object-oriented programming (OOP) that defines a relationship between two or more objects. It represents how objects interact with each other while maintaining their independence. Association is **not inheritance**—rather, it is a relationship between objects that allows communication while ensuring they remain loosely coupled. ## What is Association? Association defines a connection between two classes, where one class is linked to another. The association can be **one-to-one**, **one-to-many**, **many-to-one**, or **many-to-many**. Objects in an association can exist independently of each other. ### Key Characteristics of Association: - Represents a **uses-a** or **knows-a** relationship. - Objects in an association **can exist independently**. - Can be **unidirectional** or **bidirectional**. - Promotes **modularity** and **code reusability**. ### Example: A Student and a Teacher A `Student` can be associated with multiple `Teacher` objects, and a `Teacher` can have multiple `Student` objects. This represents a **many-to-many** association. ```python class Teacher: def __init__(self, name): self.name = name self.students = [] def add_student(self, student): self.students.append(student) def show_students(self): print(f"{self.name} teaches:") for student in self.students: print(f" - {student.name}") class Student: def __init__(self, name): self.name = name # Example Usage if __name__ == "__main__": teacher1 = Teacher("Mr. Smith") teacher2 = Teacher("Mrs. Johnson") student1 = Student("Alice") student2 = Student("Bob") teacher1.add_student(student1) teacher1.add_student(student2) teacher2.add_student(student2) teacher1.show_students() teacher2.show_students() ``` ### Output: ``` Mr. Smith teaches: - Alice - Bob Mrs. Johnson teaches: - Bob ``` --- ## Types of Association ### 1. **One-to-One Association** - Each object of class A is associated with one object of class B. - Example: A `Person` has one `Passport`. ### 2. **One-to-Many Association** - One object of class A can be associated with multiple objects of class B. - Example: A `Teacher` teaches multiple `Students`. ### 3. **Many-to-One Association** - Multiple objects of class A can be associated with one object of class B. - Example: Multiple `Students` belong to one `School`. ### 4. **Many-to-Many Association** - Multiple objects of class A can be associated with multiple objects of class B. - Example: `Teachers` and `Students`. --- ## Why Use Association? - **Promotes Code Reusability**: Objects can be reused across multiple associations without duplication. - **Encourages Loose Coupling**: Objects interact without depending on the internal implementation of each other. - **Improves Maintainability**: Changing one object does not heavily impact others, making code easier to manage. - **Better System Design**: Allows modeling of real-world relationships between entities effectively. --- ## Association vs Aggregation vs Composition | Feature | Association | Aggregation | Composition | |--------------|------------|------------|------------| | Relationship | "Knows-a" | "Has-a" | "Has-a" | | Object Independence | Objects are independent | Contained object **can exist independently** | Contained object **cannot exist without** the container | | Lifetime | Objects exist separately | Contained object **outlives** the container | Contained object **is destroyed** with the container | | Example | Teacher and Student | University and Professors | Car and Engine | --- ## Bidirectional Association Associations can be **unidirectional** (one object knows about another) or **bidirectional** (both objects know about each other). ### Example: A Library and Books (Bidirectional Association) ```python class Library: def __init__(self, name): self.name = name self.books = [] def add_book(self, book): self.books.append(book) def show_books(self): print(f"Books in {self.name}:") for book in self.books: print(f" - {book.title}") class Book: def __init__(self, title, library): self.title = title self.library = library def show_library(self): print(f"{self.title} is in {self.library.name}") # Example Usage if __name__ == "__main__": library = Library("City Library") book1 = Book("1984", library) book2 = Book("Brave New World", library) library.add_book(book1) library.add_book(book2) library.show_books() book1.show_library() book2.show_library() ``` ### Output: ``` Books in City Library: - 1984 - Brave New World 1984 is in City Library Brave New World is in City Library ``` ================================================ FILE: oop/python/classesandobjects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? A class is a blueprint or template. It defines the attributes (fields) and behaviors (methods) of an object. ### Defining a Class in Python To define a class in Python, you use the `class` keyword followed by the name of the class. Here's a simple example: ```python class Car: # Constructor def __init__(self, color, make, model, year): self.color = color self.make = make self.model = model self.year = year # Method to display car details def display_info(self): print(f"Car Make: {self.make}") print(f"Car Model: {self.model}") print(f"Car Year: {self.year}") print(f"Car Color: {self.color}") ``` - **Attributes**: The class `Car` has four attributes that describe its state: `color`, `make`, `model`, and `year`. - **Constructor**: The constructor `__init__(self, color, make, model, year)` initializes new objects of the class. - **Methods**: The `display_info` method is responsible for showcasing the car details. ## What is an Object? An object is an instance of a class. When you create an object, you are bringing the blueprint of the class into reality. It consists of state and behavior defined by the class, with each object holding its own copy of the data. ### Creating Objects in Python To create an object, you call the class constructor. Here's how you can instantiate objects from the `Car` class: ```python car1 = Car("Red", "Toyota", "Corolla", 2020) car2 = Car("Blue", "Ford", "Mustang", 2021) # Displaying information of each car car1.display_info() print("-----------------") car2.display_info() ``` 1. **Initialization**: The constructor (`Car`) initializes the object state with given parameters. 2. **Reference**: The object is referenced through a variable (`car1`, `car2`) that points to its memory location. ================================================ FILE: oop/python/composition/README.md ================================================ # Composition in Python ## Introduction Composition is one of the key concepts of object-oriented programming (OOP). It allows objects to be built using other objects, promoting code reuse, flexibility, and better maintainability. Unlike inheritance, which establishes an "is-a" relationship, composition represents a "has-a" relationship. ## What is Composition? Composition is a design principle in OOP where one class contains an instance (or instances) of another class as a field. The contained class is often called a component, and the containing class is referred to as a composite class. This helps in building complex systems by combining simpler objects. ### Example: A Car and its Components Consider a `Car` that consists of multiple components like an `Engine`, `Wheel`, and `Transmission`. Instead of inheriting from these components, a `Car` object will contain them as fields. ```python class Engine: def __init__(self, horsepower): self.horsepower = horsepower def start(self): print(f"Engine started with {self.horsepower} HP.") class Wheel: def __init__(self, type): self.type = type def rotate(self): print(f"The {self.type} wheel is rotating.") class Transmission: def __init__(self, type): self.type = type def shift_gear(self): print(f"Transmission shifted: {self.type}") class Car: def __init__(self): self.engine = Engine(150) self.wheel = Wheel("Alloy") self.transmission = Transmission("Automatic") def drive(self): self.engine.start() self.wheel.rotate() self.transmission.shift_gear() print("Car is moving!") # Example Usage if __name__ == "__main__": car = Car() car.drive() ``` ### Output: ``` Engine started with 150 HP. The Alloy wheel is rotating. Transmission shifted: Automatic Car is moving! ``` --- ## Why Prefer Composition Over Inheritance? ### 1. **Encapsulation and Flexibility** - Composition allows us to change the behavior of an object dynamically by replacing components at runtime. - Inheritance makes it difficult to modify an existing class hierarchy without breaking existing code. ### 2. **Better Code Reusability** - Composition promotes reusable components. The `Engine`, `Wheel`, and `Transmission` classes can be used in multiple types of vehicles (Car, Bike, Truck) without modification. ### 3. **Avoids Inheritance Pitfalls** - Inheritance can lead to deep class hierarchies, making maintenance difficult. - It enforces strict parent-child relationships, which can be too rigid for some designs. ### 4. **Supports Interface-Based Design** - Composition can be combined with interfaces (or abstract classes) to achieve powerful decoupling. --- ## Composition with Abstract Classes Using abstract base classes with composition allows for greater flexibility and loose coupling. ```python from abc import ABC, abstractmethod class Engine(ABC): @abstractmethod def start(self): pass class PetrolEngine(Engine): def start(self): print("Petrol Engine started.") class DieselEngine(Engine): def start(self): print("Diesel Engine started.") class Car: def __init__(self, engine: Engine): self.engine = engine def start_car(self): self.engine.start() print("Car is ready to go!") # Example Usage if __name__ == "__main__": petrol_car = Car(PetrolEngine()) petrol_car.start_car() diesel_car = Car(DieselEngine()) diesel_car.start_car() ``` ### Output: ``` Petrol Engine started. Car is ready to go! Diesel Engine started. Car is ready to go! ``` --- ## When to Use Composition? - When building complex objects that consist of multiple components. - When you want to achieve **code reusability** without rigid inheritance hierarchies. - When different behaviors need to be swapped dynamically (e.g., using different types of engines in a vehicle). - When following the **favor composition over inheritance** principle. ================================================ FILE: oop/python/encapsulation/README.md ================================================ # Encapsulation in Python ## Introduction **Encapsulation** is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the practice of **bundling data (variables) and methods** that operate on that data into a single unit (class) while restricting direct access to the internal details. Encapsulation in Python is achieved using: 1. **Access Modifiers** (`public`, `_protected`, `__private`) 2. **Getters and Setters** 3. **Data Hiding** Encapsulation helps in **data protection, modularity, and maintainability** of the code. ## **What is Encapsulation?** Encapsulation means **wrapping** the data (variables) and code (methods) together into a single unit (class). It restricts direct access to some of an object's components, which helps protect data integrity and prevents unintended modifications. ### **Key Benefits of Encapsulation** - **Data Hiding**: Prevents direct access to sensitive data. - **Increased Security**: Controls how data is accessed and modified. - **Improved Code Maintainability**: Allows changes without affecting other parts of the code. - **Better Modularity**: Organizes the code into logical components. --- ## **Encapsulation Using Access Modifiers** Python provides **access modifiers** to enforce encapsulation: - **`public`**: Accessible from anywhere. - **`_protected`**: Accessible within the class and subclasses. - **`__private`**: Accessible only within the class. ### **Example: Encapsulation with Private Variables** ```python class BankAccount: def __init__(self, account_holder, balance): self.__account_holder = account_holder # Private attribute self.__balance = balance # Private attribute # Getter method to access balance def get_balance(self): return self.__balance # Setter method to modify balance def deposit(self, amount): if amount > 0: self.__balance += amount print(f"Deposited: {amount}") else: print("Invalid deposit amount") # Usage account = BankAccount("Alice", 1000) print("Current Balance:", account.get_balance()) account.deposit(500) print("Updated Balance:", account.get_balance()) ``` ### **Output:** ``` Current Balance: 1000 Deposited: 500 Updated Balance: 1500 ``` **Why Use Encapsulation?** - Prevents unauthorized access to the data. - Allows controlled modifications through methods. --- ## **Encapsulation Using Getters and Setters** Encapsulation ensures that **data cannot be directly accessed** but must be retrieved or modified through methods. ### **Example: Getters and Setters in Python** ```python class Employee: def __init__(self): self.__name = "" self.__age = 0 # Getter method def get_name(self): return self.__name # Setter method def set_name(self, name): self.__name = name def get_age(self): return self.__age def set_age(self, age): if age > 18: self.__age = age else: print("Age must be greater than 18") # Usage emp = Employee() emp.set_name("John Doe") emp.set_age(25) print("Employee Name:", emp.get_name()) print("Employee Age:", emp.get_age()) ``` ### **Output:** ``` Employee Name: John Doe Employee Age: 25 ``` --- ## **Encapsulation and Data Hiding** Encapsulation helps **hide implementation details** while exposing only necessary methods. ### **Example: Hiding Implementation Details** ```python class Account: def __init__(self, initial_balance): self.__balance = initial_balance def __validate_withdrawal(self, amount): return amount > 0 and amount <= self.__balance def withdraw(self, amount): if self.__validate_withdrawal(amount): self.__balance -= amount print(f"Withdrawal Successful: {amount}") else: print("Insufficient balance or invalid amount") def get_balance(self): return self.__balance # Usage my_account = Account(1000) my_account.withdraw(300) print("Remaining Balance:", my_account.get_balance()) ``` ### **Output:** ``` Withdrawal Successful: 300 Remaining Balance: 700 ``` **Why Hide Data?** - Prevents direct modification of important fields. - Ensures data integrity by validating inputs. --- ## **Encapsulation in Real-World Applications** Encapsulation is used in many real-world applications such as: 1. **Banking Systems** - Ensuring account details are private. 2. **Healthcare Applications** - Protecting patient records. 3. **E-Commerce Platforms** - Hiding payment processing details. ### **Example: Encapsulation in Payment Processing** ```python class PaymentProcessor: def __init__(self, card_number, amount): self.__card_number = self.__mask_card_number(card_number) self.__amount = amount def __mask_card_number(self, card_number): return "****-****-****-" + card_number[-4:] def process_payment(self): print(f"Processing payment of {self.__amount} for card {self.__card_number}") # Usage payment = PaymentProcessor("1234567812345678", 250.00) payment.process_payment() ``` ### **Output:** ``` Processing payment of 250.0 for card ****-****-****-5678 ``` **Why Use Encapsulation in Payment Processing?** - Protects sensitive data (e.g., credit card numbers). - Hides unnecessary details from users. - Ensures secure transactions. ================================================ FILE: oop/python/inheritance/README.md ================================================ # Inheritance in Python ## Introduction **Inheritance** is one of the core principles of Object-Oriented Programming (OOP). It allows a class (subclass or child class) to acquire the properties and behaviors of another class (superclass or parent class). This promotes **code reuse**, **scalability**, and **maintainability**. ## **What is Inheritance?** **Inheritance** is a mechanism where a child class derives properties and behaviors from a parent class. The child class can: - Use the attributes and methods of the parent class - Override parent class methods to provide a specific implementation - Add its own additional attributes and methods ### **Key Benefits of Inheritance** - **Code Reusability**: Avoids code duplication by reusing attributes and methods of the parent class. - **Improves Maintainability**: Reduces redundancy, making code easier to manage. - **Enhances Extensibility**: New functionality can be added easily without modifying existing code. --- ## **How to Implement Inheritance in Python** ### **Step 1: Create a Parent Class** The parent class contains common attributes and methods. ```python # Parent class class Animal: def __init__(self, name): self.name = name def eat(self): print(f"{self.name} is eating...") ``` ### **Step 2: Create a Child Class using Parent Class** The child class inherits the properties and methods of the parent class. ```python # Child class class Dog(Animal): def bark(self): print(f"{self.name} is barking...") ``` ### **Step 3: Use the Child Class** Now, let's create an object and use the inherited methods. ```python # Using the child class if __name__ == "__main__": my_dog = Dog("Buddy") my_dog.eat() # Inherited from Animal class my_dog.bark() # Defined in Dog class ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Types of Inheritance in Python** Python supports different types of inheritance: ### **1. Single Inheritance** A subclass inherits from one superclass. ```python class Parent: def show(self): print("This is the parent class") class Child(Parent): def display(self): print("This is the child class") ``` ### **2. Multilevel Inheritance** A subclass inherits from another subclass, forming a chain. ```python class Grandparent: def show(self): print("Grandparent class") class Parent(Grandparent): def display(self): print("Parent class") class Child(Parent): def print_info(self): print("Child class") ``` ### **3. Hierarchical Inheritance** A single parent class has multiple child classes. ```python class Parent: def show(self): print("Parent class") class Child1(Parent): def display(self): print("Child1 class") class Child2(Parent): def print_info(self): print("Child2 class") ``` ### **4. Multiple Inheritance** Unlike Java, Python **supports multiple inheritance**, allowing a subclass to inherit from multiple parent classes. ```python class Parent1: def show1(self): print("Parent1 class") class Parent2: def show2(self): print("Parent2 class") class Child(Parent1, Parent2): def display(self): print("Child class") ``` --- ## **Method Overriding in Inheritance** Method overriding allows a child class to **redefine** a method from the parent class. ```python class Animal: def make_sound(self): print("Animal makes a sound") class Dog(Animal): def make_sound(self): print("Dog barks") ``` ### **Usage** ```python if __name__ == "__main__": my_animal = Dog() # Polymorphism my_animal.make_sound() ``` ### **Output:** ``` Dog barks ``` --- ## **The `super()` Function in Inheritance** The `super()` function is used to **refer to the parent class**. It helps to: 1. Call the parent class constructor. 2. Access the parent class methods. ```python class Animal: def __init__(self): print("Animal Constructor") def make_sound(self): print("Animal makes a sound") class Dog(Animal): def __init__(self): super().__init__() # Calls the parent class constructor print("Dog Constructor") def make_sound(self): super().make_sound() # Calls parent method print("Dog barks") ``` ### **Usage** ```python if __name__ == "__main__": my_dog = Dog() my_dog.make_sound() ``` ### **Output:** ``` Animal Constructor Dog Constructor Animal makes a sound Dog barks ``` ================================================ FILE: oop/python/interfaces/README.md ================================================ # Interfaces in Python ## Introduction In Object-Oriented Programming (OOP), an **interface** is a crucial concept that defines a contract for classes to follow. It allows multiple classes to share a common structure while enforcing certain behaviors. While Python does not have built-in support for interfaces like Java, it achieves the same functionality using **abstract base classes (ABCs)** from the `abc` module. ## What is an Interface? An **interface** is a collection of method definitions that a class must implement. It defines a contract that implementing classes must adhere to. ### **Key Characteristics of Interfaces in Python** - Uses the `abc` module to create abstract base classes (ABCs). - Defines methods without implementation that must be overridden. - Supports **multiple inheritance**, like normal classes. - Improves **code flexibility and maintainability**. --- ## **Defining and Implementing an Interface in Python** ### **Step 1: Define an Interface using `ABC`** To define an interface, we use the `ABC` class from the `abc` module. ```python from abc import ABC, abstractmethod # Defining an interface class Vehicle(ABC): @abstractmethod def start(self): pass # Abstract method (no implementation) @abstractmethod def stop(self): pass # Abstract method (no implementation) ``` ### **Step 2: Implement the Interface** A class implements an interface by inheriting from it and providing concrete implementations of the abstract methods. ```python # Implementing the Vehicle interface in a Car class class Car(Vehicle): def start(self): print("Car is starting...") def stop(self): print("Car is stopping...") ``` ### **Step 3: Using the Implemented Class** Now, let's create objects and call the methods. ```python if __name__ == "__main__": my_car = Car() # Instantiating the class my_car.start() my_car.stop() ``` ### **Output:** ``` Car is starting... Car is stopping... ``` --- ## **Multiple Inheritance with Interfaces** Unlike normal classes, Python **supports multiple inheritance** with interfaces. ```python from abc import ABC, abstractmethod # First interface class Flyable(ABC): @abstractmethod def fly(self): pass # Second interface class Drivable(ABC): @abstractmethod def drive(self): pass # Implementing multiple interfaces class FlyingCar(Flyable, Drivable): def fly(self): print("FlyingCar is flying...") def drive(self): print("FlyingCar is driving...") ``` ### **Usage** ```python if __name__ == "__main__": my_vehicle = FlyingCar() my_vehicle.fly() my_vehicle.drive() ``` ### **Output:** ``` FlyingCar is flying... FlyingCar is driving... ``` --- ## **Default Method Behavior in Interfaces** Unlike Java, Python does not have **default methods** in interfaces, but we can provide default implementations in base classes. ```python from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def sound(self): pass def sleep(self): # Default method print("Sleeping...") class Dog(Animal): def sound(self): print("Dog barks") ``` ### **Usage** ```python if __name__ == "__main__": my_dog = Dog() my_dog.sound() my_dog.sleep() ``` ### **Output:** ``` Dog barks Sleeping... ``` --- ## **Real-World Example: Payment System** ```python from abc import ABC, abstractmethod class Payment(ABC): @abstractmethod def pay(self, amount): pass class CreditCardPayment(Payment): def pay(self, amount): print(f"Paid {amount} using Credit Card") class PayPalPayment(Payment): def pay(self, amount): print(f"Paid {amount} using PayPal") ``` ### **Usage** ```python if __name__ == "__main__": payment1 = CreditCardPayment() payment1.pay(100.50) payment2 = PayPalPayment() payment2.pay(200.75) ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 200.75 using PayPal ``` ================================================ FILE: oop/python/polymorphism/README.md ================================================ # Polymorphism in Python ## Introduction **Polymorphism** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. Polymorphism in Python can be classified into two types: 1. **Compile-time Polymorphism (Method Overloading - Python handles it differently)** 2. **Run-time Polymorphism (Method Overriding & Duck Typing)** ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a method, function, or object to behave differently based on the context. Polymorphism enables **dynamic method resolution** and **method flexibility**, making applications easier to extend and maintain. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single interface that works for multiple types. - **Scalability**: Add new functionalities with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **1. Compile-Time Polymorphism (Method Overloading in Python)** Unlike Java or C++, Python does not support method overloading in the traditional sense. However, we can achieve similar functionality by using **default parameters** or variable arguments (`*args`). ### **Example of Method Overloading using Default Arguments** ```python class MathOperations: def add(self, a, b, c=0): return a + b + c math = MathOperations() print("Sum (2 numbers):", math.add(5, 10)) print("Sum (3 numbers):", math.add(5, 10, 15)) ``` ### **Output:** ``` Sum (2 numbers): 15 Sum (3 numbers): 30 ``` **Why Use Default Arguments?** - Simulates method overloading by providing optional parameters. - Reduces redundancy by using a single method name for similar operations. --- ## **2. Run-Time Polymorphism (Method Overriding)** Run-time polymorphism occurs when a subclass provides a **specific implementation** of a method already defined in its parent class. The method to be called is determined **at runtime**. ### **Example of Method Overriding** ```python class Animal: def make_sound(self): print("Animal makes a sound") class Dog(Animal): def make_sound(self): print("Dog barks") class Cat(Animal): def make_sound(self): print("Cat meows") # Demonstrating runtime polymorphism animals = [Dog(), Cat()] for animal in animals: animal.make_sound() ``` ### **Output:** ``` Dog barks Cat meows ``` **Why Use Method Overriding?** - Enables **dynamic method resolution**. - Supports **polymorphic behavior**, where one interface can be used for multiple implementations. - Makes code **extensible** by allowing future modifications. --- ## **Using Polymorphism with Duck Typing** Python follows the **Duck Typing** principle: "If it looks like a duck and quacks like a duck, it is a duck." This means that Python does not require explicit implementation of interfaces. ```python class Car: def start(self): print("Car is starting...") class Bike: def start(self): print("Bike is starting...") # Polymorphic function def vehicle_start(vehicle): vehicle.start() vehicle_start(Car()) vehicle_start(Bike()) ``` ### **Output:** ``` Car is starting... Bike is starting... ``` **Why Use Duck Typing?** - Promotes **loose coupling**, making code more flexible. - Allows multiple implementations of the same behavior without inheritance. - Enables **dependency injection**, improving testability. --- ## **Real-World Example: Payment System** A common real-world use case of polymorphism is in **payment processing**. ```python class Payment: def pay(self, amount): pass # Abstract method class CreditCardPayment(Payment): def pay(self, amount): print(f"Paid {amount} using Credit Card") class PayPalPayment(Payment): def pay(self, amount): print(f"Paid {amount} using PayPal") # Demonstrating polymorphism payments = [CreditCardPayment(), PayPalPayment()] for payment in payments: payment.pay(100.50) ``` ### **Output:** ``` Paid 100.5 using Credit Card Paid 100.5 using PayPal ``` **Why Use Polymorphism in Payment Systems?** - Allows new payment methods to be added **without modifying existing code**. - Provides a **flexible and scalable** design. - Improves **code readability and maintainability**. ================================================ FILE: oop/rust/.gitignore ================================================ # Generated by Cargo target/ # Ignoring the lockfile because this is an educational library, not a binary deployment Cargo.lock # Ignoring rustfmt backups **/*.rs.bk ================================================ FILE: oop/rust/Cargo.toml ================================================ [package] name = "rust_oop_concepts" version = "0.1.0" edition = "2021" # BINARY TARGETS # According to Cargo docs, we can explicitly define binaries # that are located outside the standard 'src/bin' directory. [[bin]] name = "classes_and_objects" path = "classes_and_objects/main.rs" [[bin]] name = "interfaces" path = "interfaces/main.rs" [[bin]] name = "abstraction" path = "abstraction/main.rs" [[bin]] name = "inheritance" path = "inheritance/main.rs" [[bin]] name = "polymorphism" path = "polymorphism/main.rs" [[bin]] name = "encapsulation" path = "encapsulation/main.rs" [[bin]] name = "aggregation" path = "aggregation/main.rs" [[bin]] name = "composition" path = "composition/main.rs" [[bin]] name = "association" path = "association/main.rs" ================================================ FILE: oop/rust/abstraction/README.md ================================================ # Abstraction in Rust **Abstraction** is the design pattern of hiding complex implementation details and exposing only the necessary functionality to the user. > **Simple Definition:** "Show what it does, hide how it does it." --- ## 🏗️ Prerequisites: The Building Blocks Before understanding Abstraction in Rust, we must understand two fundamental concepts that replace "Classes" in other languages: **Structs** and **Traits**. ### 1. What is a Struct? In Java/C++, a Class holds both data and methods. In Rust, data is separated. A **Struct** is strictly for holding **Data**. It has no behavior on its own. **Example:** ```rust // Just data. No logic here. struct CoffeeMachine { water_level: u32, beans: u32, } ``` ### 2. What is a Trait? A **Trait** is Rust's version of an **Interface**. It defines **Behavior**. It tells us *what* functionality an object must provide, but not *how* it does it. **Example:** ```rust // This is the "Contract" or "Interface" trait Brewable { fn make_coffee(&self); // abstract method (no body) } ``` ### 3. What is `impl`? The `impl` keyword is the glue. It implements the **Trait** (Behavior) for a specific **Struct** (Data). --- ## ☕ Abstraction: The Real-World Example Let's apply these concepts to build a **Coffee Machine**. ### The Problem (Without Abstraction) If we don't use abstraction, the user has to manually handle the machine's internal parts. This is dangerous and complex. ```rust let mut machine = CoffeeMachine { water: 0, beans: 0 }; // BAD: User has to know how the machine works internally! machine.water = 100; // User manually filling water? machine.beans = 50; // User manually loading beans? machine.grind_beans(); // User manually starting the grinder? // This is too complex for a normal user. ``` ### The Solution (With Abstraction) We want to hide the grinding and heating logic. The user should only see one simple button: `brew()`. #### Step 1: Define the Abstraction (The Interface) We create a public Trait. This is the **only** thing the user needs to understand. ```rust // PUBLIC: The user sees this. pub trait CoffeeMaker { fn add_ingredients(&mut self); fn press_button(&mut self); } ``` #### Step 2: Implement the Hidden Logic We hide the complex steps (`grind_beans`, `heat_water`) inside private helper methods. The user cannot call these directly. ```rust pub struct PremiumMachine { water: u32, beans: u32, } impl PremiumMachine { // PRIVATE: Internal logic (Hidden details) fn grind_beans(&self) { println!("Grinding beans... 🚜"); } fn heat_water(&self) { println!("Heating water... 🔥"); } } // CONNECTING THEM: Implementing the Public Trait impl CoffeeMaker for PremiumMachine { fn add_ingredients(&mut self) { self.water = 100; self.beans = 50; } fn press_button(&mut self) { // The abstraction happens here! // One simple call triggers complex internal logic. self.grind_beans(); self.heat_water(); println!("Coffee is ready! ☕"); } } ``` --- ## 🆚 Comparison: Rust vs. OOP Languages Rust handles abstraction differently than Java or Python because it emphasizes **memory safety** and **separation of concerns**. | Feature | Java / C++ / Python | Rust | | :--- | :--- | :--- | | **Container** | `Class` (Data + Methods together) | `Struct` (Data) + `impl` (Methods) separated | | **Interface** | `interface` or `abstract class` | `trait` | | **Hiding Data** | `private` / `protected` keywords | Struct fields are **private by default** to other modules | | **Override** | `@Override` annotation | Explicit implementation of Trait methods | --- ## 🧠 Why is this useful? 1. **Safety:** The user cannot accidentally change the `water_level` to a wrong value because the field is private. 2. **Simplicity:** The user doesn't need to know *how* to grind beans; they just press the button. 3. **Flexibility:** We can swap the `PremiumMachine` with a `CheapMachine`, and as long as they both implement the `CoffeeMaker` trait, the user code doesn't change. ================================================ FILE: oop/rust/abstraction/main.rs ================================================ /* * ABSTRACTION EXAMPLE: A Coffee Machine * * Goal: The user interacts with a simple interface (make_coffee), * hiding the complex logic (grinding, heating, checking water) inside. */ // 1. THE ABSTRACTION (The Interface) // We define a Trait to specify WHAT a Coffee Machine should do. // The user strictly interacts with these methods. pub trait CoffeeMaker { fn brew(&mut self); fn add_water(&mut self, amount: u32); } // 2. THE CONCRETE TYPE (The Data) // These fields represent the internal state. // Notice we do NOT make the fields 'pub'. They are hidden from the outside world. pub struct PremiumCoffeeMachine { water_level: u32, beans_level: u32, } // 3. INTERNAL LOGIC (Helper methods) // These methods are NOT part of the Trait. They are private internal logic // used to support the public abstraction. impl PremiumCoffeeMachine { pub fn new(water: u32, beans: u32) -> Self { PremiumCoffeeMachine { water_level: water, beans_level: beans, } } // This is an internal detail (Encapsulated logic). // The user doesn't need to call this manually. fn grind_beans(&mut self) -> bool { if self.beans_level > 10 { self.beans_level -= 10; println!("* Grinding beans... *"); return true; } println!("Error: Not enough beans!"); false } // Another internal detail. fn heat_water(&mut self) -> bool { if self.water_level > 20 { self.water_level -= 20; println!("* Heating water... *"); return true; } println!("Error: Add more water!"); false } } // 4. IMPLEMENTING THE ABSTRACTION // We expose only the high-level 'brew' functionality to the user. impl CoffeeMaker for PremiumCoffeeMachine { fn add_water(&mut self, amount: u32) { self.water_level += amount; println!("Added {}ml of water. Current level: {}ml", amount, self.water_level); } // This is the implementation of the Abstraction. // The complexity of grinding and heating is HIDDEN behind this single function call. fn brew(&mut self) { println!("\n--- Starting Brew Process ---"); // We chain internal steps here. The user doesn't know this complexity exists. if self.grind_beans() && self.heat_water() { println!("Success: Here is your hot coffee! ☕"); } else { println!("Failure: Could not brew coffee."); } println!("-----------------------------\n"); } } fn main() { // User creates the machine let mut machine = PremiumCoffeeMachine::new(0, 100); // USAGE // The user doesn't verify water temp or grind size manually. // They just use the abstract interface methods: add_water() and brew(). machine.add_water(50); // User interacts with the interface machine.brew(); // User interacts with the interface // Trying to brew again without water machine.brew(); } ================================================ FILE: oop/rust/aggregation/README.md ================================================ # Aggregation in Rust (References & Lifetimes) ## Introduction **Aggregation** is a specific type of association in Object-Oriented Programming (OOP) representing a **"Has-A"** relationship. * **Crucial Distinction:** The lifecycle of the contained object (Child) is **independent** of the container object (Parent). * **In plain English:** If the University closes down (is destroyed), the Professors do not die; they go home. **Does Rust support Aggregation?** Yes, but it is stricter than Java. In Rust, Aggregation is implemented using **References (`&T`)** and **Lifetimes (`'a`)**. --- ## **1. The Core Concept: Borrowing vs. Owning** To understand Aggregation, you must understand Rust's memory model: 1. **Composition (Strong):** The Parent **OWNS** the Child. * *Rust:* `struct Parent { child: Child }` * *Result:* If Parent dies, Child dies immediately. 2. **Aggregation (Weak):** The Parent **BORROWS** the Child. * *Rust:* `struct Parent<'a> { child: &'a Child }` * *Result:* Parent holds a pointer. If Parent dies, the Child is unaffected because the Parent never owned it. --- ## **2. The "Lifetime" Problem (`'a`)** This is the most unique part of Rust. If a struct holds a reference, the borrow checker will reject invalid lifetimes at compile time: > *"What if the University holds a pointer to a Professor, but the Professor has already been deleted? The University would be pointing to garbage memory!"* To prevent this, we use **Lifetime Annotations (`'a`)**. ```rust // <'a> reads as: "This struct lives for a duration called 'a" struct University<'a> { // This reference must live AT LEAST as long as 'a professor: &'a Professor, } ``` **What this tells the compiler:** *"I promise that the `Professor` will stay alive longer than (or at least as long as) the `University`."* --- ## **3. Code Implementation** ### **Step 1: The Independent Object** The `Professor` owns its own data. It doesn't know about the University. ```rust struct Professor { name: String, } ``` ### **Step 2: The Container (With Lifetimes)** The `University` holds a **Reference** (`&`) to the Professor. ```rust struct University<'a> { name: String, // Aggregation: We borrow the professor staff: Vec<&'a Professor>, } ``` ### **Step 3: Usage** ```rust fn main() { // 1. Create the Child (Owner) let prof = Professor { name: "Dr. Smith".into() }; { // 2. Create the Parent (Borrower) let mut uni = University { name: "MIT".into(), staff: vec![&prof] // Borrowing here }; // uni is destroyed here... } // 3. PROOF OF AGGREGATION: // The Professor is still alive! println!("{} is currently unemployed but alive.", prof.name); } ``` --- ## **4. Advanced: Shared Ownership (`Rc`)** Sometimes, you don't know who will die first. Maybe the Professor belongs to 3 Universities at once. For this, Rust uses **Reference Counting (`Rc`)**. * **`Rc`**: A smart pointer that keeps track of how many owners exist. * The object is only deleted when the **count reaches 0**. ```rust use std::rc::Rc; struct Company { // Shared Ownership Aggregation employee: Rc, } ``` --- ## **Comparison: Aggregation vs Composition** | Feature | Aggregation (Weak) | Composition (Strong) | | --- | --- | --- | | **Relationship** | **"Uses a"** / **"Has access to"** | **"Consists of"** | | **Rust Syntax** | `&'a T` (Reference) | `T` (Direct Value) | | **Ownership** | **Borrowed** (Parent does not own) | **Owned** (Parent owns Child) | | **Lifecycle** | **Independent** (Child survives Parent) | **Dependent** (Child dies with Parent) | | **Drop Rule** | Dropping Parent **does nothing** to Child. | Dropping Parent **drops** Child. | --- ## 📚 New Terminology | Term | Detailed Explanation | | --- | --- | | **Lifetime (`'a`)** | A generic parameter that restricts how long a Reference is valid. It ensures a struct never points to dead memory. | | **Borrow Checker** | The part of the Rust compiler that enforces Aggregation rules. It ensures the "Child" lives longer than the "Parent". | | **Dangling Pointer** | A pointer that points to invalid memory. Rust's Aggregation rules exist specifically to prevent this. | | **`Vec<&T>`** | A Vector that stores *addresses* of objects, not the objects themselves. | ================================================ FILE: oop/rust/aggregation/main.rs ================================================ /* * AGGREGATION IN RUST * * Goal: Demonstrate Independent Lifecycles using References and Lifetimes. * Scenario: A Library (Container) holds references to Books (Independent Objects). */ #[derive(Debug)] struct Book { title: String, author: String, } impl Book { fn new(title: &str, author: &str) -> Self { Book { title: title.to_string(), author: author.to_string(), } } fn read(&self) { println!(" Reading '{}' by {}...", self.title, self.author); } } // THE CONTAINER (AGGREGATION) // <'a> ensures Library cannot outlive the Books it holds. struct Library<'a> { name: String, // Aggregation: Library 'has' books, but does not 'own' them. collection: Vec<&'a Book>, } impl<'a> Library<'a> { fn new(name: &str) -> Self { Library { name: name.to_string(), collection: Vec::new(), } } // We take a reference with lifetime 'a fn add_book(&mut self, book: &'a Book) { self.collection.push(book); } fn list_books(&self) { println!("Library '{}' contains:", self.name); for book in &self.collection { book.read(); } } } // ADVANCED: SHARED AGGREGATION (Rc) use std::rc::Rc; struct Reader { name: String, // Multiple readers can hold the SAME book favorite_book: Rc, } fn main() { println!("--- 1. Standard Aggregation (References & Lifetimes) ---"); // STEP A: Create the Independent Objects (Books) // These live in the 'main' scope. let book1 = Book::new("The Rust Book", "Steve Klabnik"); let book2 = Book::new("Clean Code", "Robert C. Martin"); { // STEP B: Create the Container (Library) inside a smaller scope let mut my_library = Library::new("City Central Lib"); // STEP C: Aggregate (Borrow the books) my_library.add_book(&book1); my_library.add_book(&book2); my_library.list_books(); println!("--- Library is closing (Variable 'my_library' dropped) ---"); } // 'my_library' dies here. // STEP D: Verify Independence // The library is gone, but the books are still here! println!("Verification: '{}' is still on my shelf at home.", book1.title); println!("\n--- 2. Shared Aggregation (Rc Smart Pointer) ---"); // We wrap a book in Rc (Reference Counted) let shared_book = Rc::new(Book::new("Design Patterns", "Gang of Four")); let reader1 = Reader { name: "Alice".into(), favorite_book: Rc::clone(&shared_book) }; let reader2 = Reader { name: "Bob".into(), favorite_book: Rc::clone(&shared_book) }; println!("{} loves {}.", reader1.name, reader1.favorite_book.title); println!("{} also loves {}.", reader2.name, reader2.favorite_book.title); // The book stays alive as long as EITHER Alice OR Bob (or the original var) holds it. } ================================================ FILE: oop/rust/association/README.md ================================================ # Association in Rust (Shared Ownership & Weak Pointers) ## Introduction **Association** represents a **"Knows-a"** or **"Uses-a"** relationship. Unlike Composition (where objects die together) or Aggregation (where one borrows the other), Association often implies that multiple objects interact as peers. **The Rust Challenge:** In Java, a `Teacher` can hold a list of `Student` objects, and those same `Student` objects can be held by another `Teacher`. In Rust, a value can strictly have **only one owner**. To allow multiple Teachers to "know" the same Student, we must use **Shared Ownership**. --- ## **1. Unidirectional Association (Shared Ownership)** When multiple parents need to access the same child, we use **`Rc` (Reference Counting)**. * `Rc` keeps track of how many things are pointing to the data. * The data is only deleted when the count hits 0. ### **Example: Many Teachers, One Student** Teacher A and Teacher B both teach "Alice". They both need to point to the *same* Alice in memory. ```rust use std::rc::Rc; struct Student { name: String } struct Teacher { name: String, // Rc allows multiple teachers to own the same student students: Vec>, } ``` --- ## **2. Bidirectional Association (The "Cycle" Problem)** This is the hardest concept in Rust OOP. If a `Library` owns a `Book` (`Rc`), and the `Book` owns the `Library` (`Rc`), the Reference Count for both will **never reach zero**. 1. Library waits for Book to die. 2. Book waits for Library to die. 3. **Result:** Memory Leak. ### **The Solution: Weak Pointers (`Weak`)** To fix this, the Child (Book) must hold a **Weak Reference** to the Parent (Library). * **Strong Reference (`Rc`)**: "I own this. Don't delete it." * **Weak Reference (`Weak`)**: "I point to this, but I don't own it. If it gets deleted, I'll just point to nothing." --- ## **3. Implementation Details (RefCell)** In Association, we often need to modify an object (like adding a student to a teacher) even though it is shared. Rust doesn't allow mutating `Rc` data directly. We use **`RefCell`** for interior mutability. It enforces borrowing rules at **runtime**, which allows mutation through shared references but can panic if you violate the rules. ### **The Pattern for Bidirectional Association** * **Parent:** Holds `Rc>` (Strong ownership, Mutable). * **Child:** Holds `Weak>` (Weak link, Mutable). --- ## 📚 New Terminology (Advanced) | Term | Java Equivalent | Detailed Explanation | | --- | --- | --- | | **`Rc`** | Shared Reference | "Reference Counted". Allows multiple parts of code to own the same data in the Heap. | | **`Weak`** | Weak Reference | A pointer that does *not* increase the reference count. Used to break infinite loops (cycles) in bidirectional relationships. | | **`RefCell`** | N/A (Magic) | "Interior Mutability". Allows you to modify data even if you only have an immutable reference to it. Essential for linked data structures. | | **`upgrade()`** | Checking for null | The method used to convert a `Weak` pointer into a real `Rc`. It returns `None` if the parent object has already been destroyed. | ================================================ FILE: oop/rust/association/main.rs ================================================ /* * ASSOCIATION IN RUST * * Scenario 1: Unidirectional (One-to-Many) using Rc. * Scenario 2: Bidirectional (Many-to-Many) using Rc, Weak, and RefCell. * * NOTE: This uses advanced smart pointers to replicate Java's flexible references. */ use std::rc::{Rc, Weak}; use std::cell::RefCell; // ========================================== // SCENARIO 1: UNIDIRECTIONAL (Teacher -> Student) // Multiple Teachers share the SAME Students. // ========================================== #[derive(Debug)] struct Student { name: String, } struct Teacher { name: String, // We use Rc so multiple teachers can refer to the SAME student instance students: Vec>, } impl Teacher { fn new(name: &str) -> Self { Teacher { name: name.to_string(), students: Vec::new(), } } fn add_student(&mut self, student: Rc) { self.students.push(student); } fn show_students(&self) { println!("{} teaches:", self.name); for s in &self.students { // Rc auto-dereferences to the inner Student println!(" - {}", s.name); } } } // ========================================== // SCENARIO 2: BIDIRECTIONAL (Library <-> Book) // Library owns Books. Books know their Library. // ========================================== // We need RefCell to allow mutation (adding books) after creation struct Library { name: String, books: RefCell>>, // Library owns Books (Strong) } struct Book { title: String, // Book holds a WEAK reference to Library to prevent memory leaks (Cycles) library: Weak, } impl Library { // Returns Rc so it can be shared with Books fn new(name: &str) -> Rc { Rc::new(Library { name: name.to_string(), books: RefCell::new(Vec::new()), }) } fn add_book(library: &Rc, title: &str) { // Create the book with a Weak pointer back to the Library let book = Rc::new(Book { title: title.to_string(), library: Rc::downgrade(library), // Convert Strong Rc to Weak }); // Add to library's list (using borrow_mut because of RefCell) library.books.borrow_mut().push(book); } fn show_books(&self) { println!("Books in {}:", self.name); for book in self.books.borrow().iter() { println!(" - {}", book.title); } } } impl Book { fn show_library(&self) { // We must attempt to "upgrade" the weak pointer to see if the Library still exists match self.library.upgrade() { Some(lib) => println!("'{}' belongs to library: {}", self.title, lib.name), None => println!("'{}' belongs to a library that no longer exists!", self.title), } } } fn main() { println!("--- 1. Unidirectional Association (Shared Ownership) ---"); // 1. Create Students (Wrapped in Rc for sharing) let s1 = Rc::new(Student { name: "Alice".into() }); let s2 = Rc::new(Student { name: "Bob".into() }); // 2. Create Teachers let mut t1 = Teacher::new("Mr. Smith"); let mut t2 = Teacher::new("Mrs. Johnson"); // 3. Associate (Cloning Rc just increases the reference count, not memory) t1.add_student(Rc::clone(&s1)); // Alice -> Smith t1.add_student(Rc::clone(&s2)); // Bob -> Smith t2.add_student(Rc::clone(&s2)); // Bob -> Johnson (Shared!) t1.show_students(); t2.show_students(); // Proof of shared memory: // Rc::strong_count(&s2) would be 3 (Original + Teacher1 + Teacher2) println!("\n--- 2. Bidirectional Association (Weak Pointers) ---"); // 1. Create the Library let city_lib = Library::new("City Library"); // 2. Add Books (Internally links Book -> Library) Library::add_book(&city_lib, "1984"); Library::add_book(&city_lib, "Brave New World"); // 3. Show relations city_lib.show_books(); // Accessing the books to show their library let books = city_lib.books.borrow(); for b in books.iter() { b.show_library(); } println!("\n--- 3. Testing Lifecycle (Weak Pointer Safety) ---"); // Create a temporary library scope let floating_book = { let temp_lib = Library::new("Temporary Pop-up Library"); Library::add_book(&temp_lib, "Temporary Manual"); // We clone the book out of the library let book_ref = Rc::clone(&temp_lib.books.borrow()[0]); book_ref // Return the book, but the Library gets dropped here }; println!("The book '{}' still exists...", floating_book.title); // This should fail gracefully because the Library is dead floating_book.show_library(); } ================================================ FILE: oop/rust/classes_and_objects/README.md ================================================ # Classes and Objects Classes and objects form the foundation of Object-Oriented Programming (OOP). ## What is a Class? In traditional OOP languages (like Java/C++), a **Class** is a blueprint that bundles data (attributes) and behavior (methods) together. **Rust is different.** It separates these two concepts: 1. **Data** is defined in a `struct`. 2. **Behavior** is defined in an `impl` (implementation) block. ### Defining a Class (Struct + Impl) in Rust To define the equivalent of a class in Rust, we use the `struct` keyword for the data layout and the `impl` keyword to define methods. Here's the `Car` example translated to idiomatic Rust: ```rust // 1. The Blueprint (Data only) // We use 'pub' to make the struct and fields accessible to other modules. pub struct Car { // Attributes pub color: String, pub make: String, pub model: String, pub year: u32, } // 2. The Behavior (Methods) impl Car { // Constructor-like function (Associated Function) // Rust does not have a 'new' keyword. We create a static function typically named 'new'. pub fn new(color: String, make: String, model: String, year: u32) -> Self { Car { color, // Shorthand initialization (same as color: color) make, model, year, } } // Method to display car details // '&self' is a reference to the current object instance (like 'this' in Java) pub fn display_info(&self) { println!("Car Make: {}", self.make); println!("Car Model: {}", self.model); println!("Car Year: {}", self.year); println!("Car Color: {}", self.color); } } ``` ### 🧠 New Rust Terminology * **`struct`**: Defines the "shape" of the object (the fields). * **`impl`**: A block where we define functions and methods for a specific struct. * **`&self`**: A reference to the instance itself. It means "read-only access to my own data". It is equivalent to `this` in Java. * **Associated Function (`new`)**: Functions defined inside `impl` that do **not** take `self`. They are like `static` methods in Java. We use them as constructors. --- ## What is an Object? An object is an **instance** of a struct. When you create an instance, you are allocating memory for that specific blueprint and filling it with real data. ### Creating Objects in Rust In Rust, we don't use the `new` keyword to instantiate. Instead, we call the associated function we created (`Car::new`) or initialize the struct directly. Here's how you can instantiate objects from the `Car` struct: ```rust fn main() { // Creating an object (Instance) of the Car struct // We use "::" to call static methods (associated functions) // Note: We use .to_string() because "Red" is a string slice (&str), // but our Struct expects an owned String. let car1 = Car::new( "Red".to_string(), "Toyota".to_string(), "Corolla".to_string(), 2020 ); let car2 = Car::new( "Blue".to_string(), "Ford".to_string(), "Mustang".to_string(), 2021 ); // Displaying information of each car // We use "." to call instance methods car1.display_info(); println!("-----------------"); car2.display_info(); } ``` ### Key Differences from Java/Go 1. **Instantiation**: No `new Car(...)`. We call `Car::new(...)` which is just a normal function we wrote. 2. **Reference**: Variables (`car1`) **own** the data by default. In Java, variables are just references (pointers). 3. **Strings**: We use `.to_string()` because string literals (`"Red"`) are string slices (`&str`), but our struct wants an owned `String`. --- ## 💡 Why Rust prefers Structs over Classes? If you are coming from Java or C++, you might wonder: *"Why didn't Rust just add Classes?"* The answer lies in **Composition over Inheritance**. ### 1. The "Banana in the Jungle" Problem In traditional OOP (Classes), you often create deep inheritance hierarchies (`Animal` -> `Mammal` -> `Dog`). Joe Armstrong (creator of Erlang) famously said: > "The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. **You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.**" In Rust: * **Structs** are just data (The Banana). * **Traits** are just behavior (Eating). * You don't inherit the "Gorilla" just to get the "Banana." ### 2. No "Diamond Problem" In languages like C++, allowing a class to inherit from two parents leads to conflicts (The Diamond Problem). Rust avoids this entirely because **Structs cannot inherit from other Structs**. You strictly use **Traits** (Interfaces) to share behavior, which is much cleaner and safer. ### 3. Better Memory Control * **Classes** (in Java/Python) are usually references (pointers) to memory on the Heap. This is slower and causes "Garbage Collection" pauses. * **Structs** in Rust are values; they can live on the stack or heap depending on how you store them (`Box`, `Rc`, etc.). Some fields (like `String`) include heap pointers, so layout depends on the data you put inside. ### Summary Rust replaces **"Is-A"** relationships (Inheritance) with **"Has-A"** and **"Can-Do"** relationships (Composition and Traits). * **Bad (OOP):** A `Car` **is a** `Vehicle`. (Forces rigid hierarchy) * **Good (Rust):** A `Car` **has** `Engine` data (Struct) and **can** `drive` (Trait). ================================================ FILE: oop/rust/classes_and_objects/main.rs ================================================ /* * CLASSES AND OBJECTS IN RUST * * Goal: Demonstrate how Rust replaces the "Class" keyword with: * 1. Struct (for Data) * 2. Impl (for Behavior) */ // 1. THE CLASS BLUEPRINT (Data Only) // In Java, this would be the fields inside 'public class Car'. // In Rust, we use a Struct to define the "shape" of the data. pub struct Car { pub color: String, pub make: String, pub model: String, pub year: u32, } // 2. THE CLASS BEHAVIOR (Methods) // In Java, these methods would be inside the class curly braces {}. // In Rust, we use an 'impl' block to attach functions to the Struct. impl Car { // A. CONSTRUCTOR // Rust has no 'new' keyword for objects. We create a static function // (Associated Function) that returns a new instance of Self. pub fn new(color: String, make: String, model: String, year: u32) -> Self { Car { color: color, make: make, model: model, year: year, } } // B. INSTANCE METHOD // '&self' allows this function to read the data of the specific object calling it. // It is exactly like 'this' in Java/C++. pub fn display_info(&self) { println!("----------------------------"); println!("Car Details:"); println!("Make: {}", self.make); println!("Model: {}", self.model); println!("Year: {}", self.year); println!("Color: {}", self.color); println!("----------------------------"); } } // 3. CREATING OBJECTS (Instances) fn main() { // Instantiation // We call the associated function 'Car::new' to create an object. // 'car1' is now the Owner of this data. let car1 = Car::new( "Red".to_string(), "Toyota".to_string(), "Corolla".to_string(), 2020 ); let car2 = Car::new( "Blue".to_string(), "Ford".to_string(), "Mustang".to_string(), 2021 ); // Usage // We access methods using the dot operator, just like Java. car1.display_info(); car2.display_info(); } ================================================ FILE: oop/rust/composition/README.md ================================================ # Composition in Rust (Ownership & Embedding) ## Introduction **Composition** is a fundamental Object-Oriented Programming (OOP) principle that represents a **"Has-A"** relationship. It allows complex objects to be built from simpler ones. In Rust, Composition is not just a design choice; it is the **primary way** to build data structures since Rust does not support Inheritance (`extends`). **The Core Rule of Composition in Rust:** When Struct A contains Struct B, **A owns B**. * They share the same lifecycle. * They share the same memory region. * When A is dropped (freed), B is automatically dropped. ## **What is Composition?** Composition is when one struct embeds another struct as a field. ### **Example: A Car and its Components** In this example, a `Car` is composed of an `Engine`, `Wheels`, and `Transmission`. Unlike Aggregation (where we used references `&`), here we use the concrete types directly. This means the `Car` takes full **ownership** of these components. ```rust struct Engine { horsepower: u32 } struct Car { // Direct Composition (Ownership) // The Engine actually lives INSIDE the Car struct in memory. engine: Engine, model: String, } ``` ### **Memory Layout Difference** * **Java (Reference):** `Car` -> (pointer) -> `Engine` (Heap) * **Rust (Composition):** `Car` [ `Engine` data ... `model` data ] (Stack or Heap, but contiguous) --- ## **Why Prefer Composition Over Inheritance?** Since Rust does not have Inheritance, Composition is the standard. However, even in languages that do have Inheritance, Composition is preferred because: 1. **Flexibility:** You can swap components (e.g., change a `GasEngine` to an `ElectricEngine`) without changing the `Car` class hierarchy. 2. **Encapsulation:** The wrapper (`Car`) controls exactly how the inner objects (`Engine`) are accessed. It can hide dangerous methods. 3. **Loose Coupling:** The `Car` doesn't need to know the internal details of how `Engine` works; it just calls public methods. --- ## **Composition with Traits (Polymorphism)** To achieve the flexibility of Java interfaces (e.g., swapping different engine types), Rust uses **Trait Objects** inside `Box`. Since different engines (Petrol vs Diesel) might have different sizes in memory, we cannot compose them directly on the stack if we want to swap them dynamically. We must put them in a `Box` (Pointer). ```rust trait Engine { fn start(&self); } struct PetrolEngine; impl Engine for PetrolEngine { ... } struct Car { // Box allows us to hold ANY struct that implements Engine engine: Box, } ``` --- ## **Composition vs Aggregation (The "Drop" Difference)** The most important detail in Rust is **Lifecycle**. | Feature | Composition (Strong) | Aggregation (Weak) | | --- | --- | --- | | **Rust Syntax** | `struct A { b: B }` | `struct A<'a> { b: &'a B }` | | **Ownership** | **Owned** (A owns B) | **Borrowed** (A borrows B) | | **Memory** | B is stored *inside* A. | B is stored elsewhere; A points to it. | | **Destruction** | If A dies, **B dies too.** | If A dies, **B lives on.** | --- ## 📚 New Terminology | Term | Explanation | | --- | --- | | **Ownership** | The Rust rule that says a value can only have one owner. In composition, the container is the owner. | | **`Box`** | A smart pointer that stores data on the Heap. Required when composing Dynamic Trait Objects (`dyn Trait`) because their size is unknown at compile time. | | **Contiguous Memory** | In Rust composition, fields are stored side-by-side in memory. This improves CPU cache performance compared to Java's scattered pointers. | | **Delegate** | A pattern where the wrapper struct (Car) calls a method on the inner struct (Engine). `car.start()` simply calls `self.engine.start()`. | ================================================ FILE: oop/rust/composition/main.rs ================================================ /* * COMPOSITION IN RUST * * Concept: "Has-a" relationship with Strong Ownership. * Pattern: Structs embedding other Structs. */ // --- 1. COMPONENT STRUCTS --- struct Engine { horsepower: u32, } impl Engine { fn new(horsepower: u32) -> Self { Engine { horsepower } } fn start(&self) { println!(" -> Engine started with {} HP.", self.horsepower); } } struct Wheel { wheel_type: String, } impl Wheel { fn new(wheel_type: &str) -> Self { Wheel { wheel_type: wheel_type.to_string(), } } fn rotate(&self) { println!(" -> The {} wheel is rotating.", self.wheel_type); } } struct Transmission { trans_type: String, } impl Transmission { fn new(trans_type: &str) -> Self { Transmission { trans_type: trans_type.to_string(), } } fn shift(&self) { println!(" -> Transmission shifted: {}", self.trans_type); } } // --- 2. THE COMPOSITE STRUCT (Strong Ownership) --- struct Car { // The Car OWNS these objects. // If Car is dropped, these are dropped. engine: Engine, wheels: Wheel, // Simplified to 1 wheel for demo transmission: Transmission, } impl Car { fn new(hp: u32, wheel_type: &str, trans_type: &str) -> Self { Car { engine: Engine::new(hp), wheels: Wheel::new(wheel_type), transmission: Transmission::new(trans_type), } } fn drive(&self) { println!("Driving Car..."); self.engine.start(); self.wheels.rotate(); self.transmission.shift(); println!("Car is moving!\n"); } } // --- 3. COMPOSITION WITH TRAITS (Dynamic Swapping) --- trait PowerSource { fn power_up(&self); } struct ElectricMotor; impl PowerSource for ElectricMotor { fn power_up(&self) { println!(" -> Electric motor humming silently... ⚡"); } } struct DieselMotor; impl PowerSource for DieselMotor { fn power_up(&self) { println!(" -> Diesel motor rumbling... ⛽"); } } struct HybridVehicle { // We use Box to hold any type of engine power_source: Box, } impl HybridVehicle { fn new(source: Box) -> Self { HybridVehicle { power_source: source } } fn start(&self) { self.power_source.power_up(); } } fn main() { println!("--- 1. Direct Composition (Static) ---"); // We create the parts INSIDE the constructor call let my_car = Car::new(150, "Alloy", "Automatic"); my_car.drive(); println!("--- 2. Composition with Interfaces (Dynamic) ---"); // We can inject dependencies dynamically let ev = HybridVehicle::new(Box::new(ElectricMotor)); print!("EV: "); ev.start(); let truck = HybridVehicle::new(Box::new(DieselMotor)); print!("Truck: "); truck.start(); // PROOF OF OWNERSHIP // Unlike Aggregation, we cannot access the 'ElectricMotor' independently // after passing it to HybridVehicle. It has been moved inside. println!("\n(Note: The motors are now owned by the vehicles and cannot be accessed separately.)"); } ================================================ FILE: oop/rust/encapsulation/README.md ================================================ # Encapsulation in Rust (Modules & Visibility) ## Introduction **Encapsulation** is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the practice of **bundling data (variables) and methods** into a single unit while restricting direct access to the internal details. **Does Rust support Encapsulation?** Yes, but it works differently than Java. 1. **Java:** Uses classes and access modifiers (`private`, `protected`, `public`) to hide data. 2. **Rust:** Uses **Modules** (`mod`) and the `pub` keyword. Encapsulation boundaries are set at the *Module* level, not the *Struct* level. ## **What is Encapsulation?** Encapsulation means **wrapping** data and code together and restricting access. ### **Key Benefits of Encapsulation** - **Data Protection**: Prevents external code from corrupting internal state (e.g., negative bank balance). - **Modularity**: Changes to internal logic (like how interest is calculated) don't break the code that uses it. - **Interface Clarity**: Users only interact with `pub` methods, ignoring the complex details inside. --- ## **Encapsulation Using Visibility Modifiers (`pub`)** In Java, you have `private`, `protected`, `public`, and package-private. In Rust, everything is **private by default**. - **Private (Default):** Accessible only within the current module (and its sub-modules). - **`pub`:** Accessible from outside the module. - **`pub(crate)`:** Accessible anywhere inside the same project (crate), but not by external users. ### **Example: Encapsulation with Modules** ```rust // We define a module to create a privacy boundary mod bank { pub struct BankAccount { pub owner: String, // Public: Anyone can read/write balance: f64, // Private: Only this 'bank' module can see it } impl BankAccount { pub fn new(owner: &str, balance: f64) -> Self { BankAccount { owner: owner.to_string(), balance, } } pub fn get_balance(&self) -> f64 { self.balance } } } fn main() { let account = bank::BankAccount::new("Alice", 1000.0); // Allowed: 'owner' is pub println!("{}", account.owner); // ERROR: 'balance' is private! // println!("{}", account.balance); } ``` **Why Use Encapsulation?** * It ensures you cannot accidentally set `balance = -500.0`. You *must* go through a method that validates the input. --- ## **Encapsulation Using Getters and Setters** Since Rust fields are often private, we access them using methods. **Rust Idiom:** * **Getter:** naming convention is `field_name()`, not `get_field_name()`. * **Setter:** naming convention is `set_field_name()`. ### **Example: Getters and Setters in Rust** ```rust pub struct Employee { name: String, age: u8, } impl Employee { // Setter pub fn set_age(&mut self, age: u8) { if age > 18 { self.age = age; } else { println!("Age must be greater than 18"); } } // Getter (Note: no 'get_' prefix) pub fn age(&self) -> u8 { self.age } } ``` --- ## **Encapsulation and Data Hiding** We hide implementation details so the user doesn't need to worry about complex validation logic. ### **Example: Hiding Implementation Details** ```rust mod finance { pub struct Account { balance: f64, } impl Account { pub fn new(balance: f64) -> Self { Account { balance } } // Private helper method (Not 'pub', so invisible outside) fn validate(&self, amount: f64) -> bool { amount > 0.0 && amount <= self.balance } // Public API pub fn withdraw(&mut self, amount: f64) { if self.validate(amount) { self.balance -= amount; println!("Withdrawal Successful: {}", amount); } else { println!("Invalid transaction"); } } } } ``` **Why Hide Data?** * **Safety:** The `validate` logic cannot be bypassed by external code. * **Simplicity:** The user just calls `withdraw`; they don't need to know *how* validation works. --- ## **Real-World Example: Payment System** A common real-world use case is processing payments where sensitive data (like card numbers) should never be exposed directly. ```rust mod payment_system { pub struct CreditCard { number: String, // Private! amount: f64, } impl CreditCard { pub fn new(number: &str, amount: f64) -> Self { CreditCard { number: CreditCard::mask(number), // Internal logic amount, } } // Private utility function fn mask(real_number: &str) -> String { let last_4 = &real_number[real_number.len()-4..]; format!("****-****-****-{}", last_4) } pub fn process(&self) { println!("Charging {} to card {}", self.amount, self.number); } } } ``` --- ## 📚 New Terminology (Java vs. Rust) | Term | Java Equivalent | Detailed Explanation | | --- | --- | --- | | **Module (`mod`)** | Package / Class | In Rust, the boundary for privacy is the **Module**, not the Class. Private items in a struct are visible to everything in the same `mod`. | | **`pub`** | `public` | Makes an item visible to other modules. | | **(No modifier)** | `private` / package-private | By default, everything in Rust is private. It is only visible within the current module and its children. | | **`pub(crate)`** | N/A | Visible to the entire project (crate), but hidden from anyone who uses your project as a library. | | **`&mut self`** | `this` (implicitly mutable) | In Java, you can always modify `this`. In Rust, you must explicitly say `&mut self` if a method changes data (like a Setter). | | **Getter convention** | `getName()` | In Rust, we simply use the field name: `name()`. | ================================================ FILE: oop/rust/encapsulation/main.rs ================================================ /* * ENCAPSULATION IN RUST * * Goal: Demonstrate Access Control, Data Hiding, and Modularity using Modules. */ // 1. ENCAPSULATION WITH MODULES (Access Modifiers) // We define a module to simulate a separate file/package mod bank { pub struct BankAccount { pub owner: String, // Public: Accessible everywhere balance: f64, // Private: Accessible only inside 'mod bank' } impl BankAccount { pub fn new(owner: &str, balance: f64) -> Self { BankAccount { owner: owner.to_string(), balance, } } // Getter pub fn balance(&self) -> f64 { self.balance } // Setter (Mutating method) pub fn deposit(&mut self, amount: f64) { if amount > 0.0 { self.balance += amount; println!("Deposited: {:.2}", amount); } else { println!("Invalid deposit amount"); } } } } // 2. GETTERS AND SETTERS (Idiomatic Rust) mod hr { pub struct Employee { name: String, age: u8, } impl Employee { pub fn new(name: &str, age: u8) -> Self { Employee { name: name.to_string(), age, } } // Getter (Rust style: no 'get_' prefix) pub fn name(&self) -> &str { &self.name } // Setter pub fn set_age(&mut self, age: u8) { if age > 18 { self.age = age; } else { println!("Error: Age must be greater than 18"); } } pub fn age(&self) -> u8 { self.age } } } // 3. REAL WORLD: PAYMENT PROCESSING (Data Hiding) mod payment { pub struct Processor { card_number: String, // Private to keep secure amount: f64, } impl Processor { pub fn new(card_number: &str, amount: f64) -> Self { Processor { // We mask the data immediately upon creation card_number: Processor::mask_card(card_number), amount, } } // Private helper method (Data Hiding) fn mask_card(real_no: &str) -> String { if real_no.len() > 4 { let last_4 = &real_no[real_no.len() - 4..]; format!("****-****-****-{}", last_4) } else { "****".to_string() } } pub fn process(&self) { println!("Processing payment of ${:.2} for card {}", self.amount, self.card_number); } } } fn main() { println!("--- 1. Access Modifiers ---"); // We use the full path 'bank::BankAccount' let mut account = bank::BankAccount::new("Alice", 1000.0); // Valid: 'owner' is pub println!("Account Holder: {}", account.owner); // Valid: Accessing private data via public method println!("Current Balance: {:.2}", account.balance()); // Invalid: Direct access would cause compile error // println!("{}", account.balance); // ERROR: field `balance` is private account.deposit(500.0); println!("Updated Balance: {:.2}", account.balance()); println!("\n--- 2. Getters & Setters ---"); let mut emp = hr::Employee::new("John Doe", 25); emp.set_age(30); // emp.name = "Jane".to_string(); // ERROR: 'name' is private println!("Employee: {}, Age: {}", emp.name(), emp.age()); println!("\n--- 3. Real World: Data Hiding ---"); let p = payment::Processor::new("1234567812345678", 250.00); // The internal logic hid the real card number automatically p.process(); } ================================================ FILE: oop/rust/inheritance/README.md ================================================ # Inheritance in Rust (Traits & Composition) ## Introduction **Inheritance** is one of the core principles of Object-Oriented Programming (OOP). It allows a class (subclass or child class) to acquire the properties and behaviors of another class (superclass or parent class). This promotes **code reuse**, **scalability**, and **maintainability**. **Does Rust support Inheritance?** No, Rust does **not** support classical inheritance (e.g., `class Dog extends Animal`). Rust takes a different approach called **Composition over Inheritance**. Instead of inheriting fields and methods from a parent class, Rust uses: 1. **Traits:** To share behavior (methods). 2. **Composition:** To share state (data/fields). ## **What is Inheritance?** In traditional OOP (Java), **Inheritance** is a mechanism where a child class derives properties and behaviors from a parent class. In Rust, since we cannot use `extends`, we achieve the same functionality by: - **Implementing Traits:** A struct implements a specific trait to gain its behavior. - **Embedding Structs:** A struct contains another struct as a field to reuse its data. ### **Key Benefits of the Rust Approach** - **Avoids the "Diamond Problem":** Multiple inheritance of state is impossible, preventing complex conflicts. - **Explicit Dependencies:** You clearly see what data a struct depends on (it's listed in the fields). - **Flexible Behavior:** You can implement many traits for a single struct, offering more flexibility than single inheritance. --- ## **How to Implement "Inheritance" in Rust** Since Rust does not have `extends`, we use **Traits** for behavior and **Composition** for data. ### **Step 1: Create a Parent Behavior (Trait)** The parent trait contains common method signatures and default implementations. ```rust // Parent Trait (Behavior) pub trait Animal { fn name(&self) -> &String; // Abstract method (getter) // Default implementation (Shared Behavior) fn eat(&self) { println!("{} is eating...", self.name()); } } ``` ### **Step 2: Create a Child Struct using `impl`** The child struct implements the properties and methods of the parent trait. ```rust // Child Struct (Data) pub struct Dog { pub name: String, pub breed: String, } // Implementing the Trait (The "Inheritance" link) impl Animal for Dog { fn name(&self) -> &String { &self.name } // 'eat()' is inherited automatically from the Trait } impl Dog { // Dog-specific method fn bark(&self) { println!("{} is barking...", self.name); } } ``` ### **Step 3: Use the Child Struct** Now, let's create an object and use the inherited methods. ```rust fn main() { let my_dog = Dog { name: "Buddy".to_string(), breed: "Golden Retriever".to_string(), }; // Inherited from Animal trait my_dog.eat(); // Defined in Dog impl block my_dog.bark(); } ``` ### **Output:** ``` Buddy is eating... Buddy is barking... ``` --- ## **Types of "Inheritance" Patterns in Rust** Although Rust lacks class inheritance, we can replicate standard OOP patterns. ### **1. Single Inheritance (Trait Implementation)** A struct implements a single trait. ```rust trait Parent { fn show(&self) { println!("This is the parent behavior"); } } struct Child; impl Parent for Child {} // Inherits 'show' ``` ### **2. Multilevel Inheritance (Supertraits)** A trait inherits from another trait. This is called a **Supertrait**. ```rust trait Grandparent { fn show_grand(&self); } // Parent requires Grandparent to be implemented first trait Parent: Grandparent { fn show_parent(&self); } struct Child; // You must implement both impl Grandparent for Child { fn show_grand(&self) { println!("Grandparent"); } } impl Parent for Child { fn show_parent(&self) { println!("Parent"); } } ``` ### **3. Hierarchical Inheritance** A single parent trait is implemented by multiple different structs. ```rust trait Entity { fn id(&self) -> u32; } struct User { id: u32 } impl Entity for User { fn id(&self) -> u32 { self.id } } struct Product { id: u32 } impl Entity for Product { fn id(&self) -> u32 { self.id } } ``` --- ## **Method Overriding in Rust** Method overriding allows a struct to **redefine** a default method provided by a Trait. ```rust trait Animal { fn make_sound(&self) { println!("Generic Animal Sound"); } } struct Dog; impl Animal for Dog { // Overriding the default method fn make_sound(&self) { println!("Dog barks! 🐶"); } } ``` ### **Usage** ```rust fn main() { let my_animal = Dog; my_animal.make_sound(); // Runs overridden version } ``` ### **Output:** ``` Dog barks! 🐶 ``` --- ## **The `super` Concept in Rust (Accessing Parent)** In Java, `super` calls the parent class. In Rust, we use **Composition** to access "parent" data explicitly. 1. **Composition:** Embedding one struct inside another. 2. **Delegation:** Calling the inner struct's methods. ```rust // The "Parent" Data struct Organism { age: u8, } impl Organism { fn breathe(&self) { println!("Breathing..."); } } // The "Child" Struct struct Dog { organism: Organism, // Composition (Has-a) } impl Dog { fn breathe(&self) { // Explicitly calling the "Parent" (inner struct) self.organism.breathe(); println!("...and panting!"); } } ``` ### **Summary Table** | Concept | Java (Inheritance) | Rust (Idiomatic) | | --- | --- | --- | | **Relationship** | `Dog extends Animal` | `Dog implements Animal` (Trait) | | **Data Sharing** | Inherited automatically | Composition (`dog.animal.field`) | | **Method Sharing** | Inherited from Parent Class | Default Trait Methods | | **Overriding** | `@Override` | `impl Trait` block | | **Philosophy** | **Is-a** relationship | **Has-a** & **Can-do** relationship | ================================================ FILE: oop/rust/inheritance/main.rs ================================================ /* * INHERITANCE IN RUST (TRAITS & COMPOSITION) * * Goal: Demonstrate how to achieve OOP Inheritance patterns using Rust. * * 1. Behavior Inheritance -> Traits * 2. Data Inheritance -> Composition */ // --- 1. BASIC INHERITANCE (TRAITS) --- // Parent Trait trait Animal { fn name(&self) -> &String; // Default method (Acts like a Parent Class method) fn eat(&self) { println!("{} is eating...", self.name()); } } // Child Struct struct Dog { name: String, breed: String, } // Implement the Trait impl Animal for Dog { fn name(&self) -> &String { &self.name } } impl Dog { fn bark(&self) { println!("{} (a {}) is barking!", self.name, self.breed); } } // --- 2. MULTILEVEL INHERITANCE (SUPERTRAITS) --- trait Living { fn live(&self) { println!("I am alive."); } } // 'Mammal' requires 'Living' to be implemented trait Mammal: Living { fn walk(&self) { println!("I can walk."); } } struct Cat; // Must implement the base trait impl Living for Cat {} // Can now implement the sub-trait impl Mammal for Cat {} // --- 3. METHOD OVERRIDING --- trait SoundMaker { fn make_sound(&self) { println!("(Generic Sound)"); } } struct Cow; impl SoundMaker for Cow { // Override the default implementation fn make_sound(&self) { println!("Moo! 🐮"); } } // --- 4. COMPOSITION (THE 'SUPER' REPLACEMENT) --- // The "Parent" Data struct BaseEntity { id: u32, } impl BaseEntity { fn save(&self) { println!("Saving Entity ID: {} to database...", self.id); } } // The "Child" Data struct User { base: BaseEntity, // Composition: User HAS-A BaseEntity username: String, } impl User { fn new(id: u32, username: &str) -> Self { User { base: BaseEntity { id }, username: username.to_string(), } } fn save_user(&self) { println!("Preparing user {}...", self.username); self.base.save(); // Call "super" method explicitly } } fn main() { println!("--- 1. Basic Inheritance (Traits) ---"); let dog = Dog { name: "Buddy".to_string(), breed: "Golden Retriever".to_string() }; dog.eat(); // Inherited behavior dog.bark(); // Specific behavior println!("\n--- 2. Multilevel Inheritance ---"); let cat = Cat; cat.live(); // From Base Trait cat.walk(); // From Sub Trait println!("\n--- 3. Method Overriding ---"); let cow = Cow; cow.make_sound(); // Overridden behavior println!("\n--- 4. Composition (Data Inheritance) ---"); let user = User::new(101, "Alice"); user.save_user(); } ================================================ FILE: oop/rust/interfaces/README.md ================================================ # Interfaces in Rust (Traits) ## Introduction In Object-Oriented Programming (OOP), an **Interface** is a crucial concept that defines a contract for types to follow. It allows multiple types to share a common structure while enforcing certain behaviors. Interfaces are widely used in Java to achieve **abstraction, polymorphism, and loose coupling**. In Rust, this concept is called a **Trait**. A Trait defines functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. ## What is a Trait? A **Trait** in Rust is a collection of method signatures that a type can implement. It defines a contract that the implementing types must adhere to. ### **Key Characteristics of Traits** - Defines a **contract** of behavior (methods) that implementing types must fulfill. - **Strict Separation:** Unlike Java where you write `class Car implements Vehicle`, in Rust, you define the `struct Car` (data) in one block and the `impl Vehicle for Car` (logic) in a completely separate block. - **Explicit Context:** Rust methods require you to explicitly say if they use the object's data by passing `&self` as the first argument. - Supports **Multiple Trait Implementation** (Rust's version of multiple inheritance). - Can contain **Default Implementations** (methods with code) and **Associated Functions** (static methods). --- ## **Defining and Implementing a Trait** ### **Step 1: Define the Trait** To define a trait (interface), use the `trait` keyword. ```rust // Defining a trait 'Vehicle' // This is the "Contract" pub trait Vehicle { fn start(&self); // Abstract method (no body) fn stop(&self); // Abstract method (no body) } ``` ### **Step 2: Implement the Trait** In Java, you implement the interface inside the class. In Rust, you use the `impl [Trait] for [Type]` syntax. ```rust // 1. Define the Data (Struct) pub struct Car { pub brand: String, } // 2. Implement the Behavior (Trait) separately // "Implement the Vehicle Trait FOR the Car Struct" impl Vehicle for Car { fn start(&self) { println!("{} is starting... 🚗", self.brand); } fn stop(&self) { println!("{} is stopping... 🛑", self.brand); } } ``` ### **Step 3: Using the Implemented Struct** We create an instance of the struct and call the trait methods. ```rust fn main() { let my_car = Car { brand: "Toyota".to_string() }; // We can call methods just like in Java my_car.start(); my_car.stop(); } ``` **Output:** ```text Toyota is starting... 🚗 Toyota is stopping... 🛑 ``` --- ## **Multiple Traits (Composition)** Java uses interfaces to solve the "Multiple Inheritance" problem. Rust does the same. A single struct can implement as many traits as necessary. ```rust // First Trait trait Flyable { fn fly(&self); } // Second Trait trait Drivable { fn drive(&self); } // The Struct struct FlyingCar; // Implement Trait 1 impl Flyable for FlyingCar { fn fly(&self) { println!("FlyingCar is flying... ✈️"); } } // Implement Trait 2 impl Drivable for FlyingCar { fn drive(&self) { println!("FlyingCar is driving... 🚙"); } } ``` ### **Usage** ```rust fn main() { let my_vehicle = FlyingCar; // The same object can do both actions my_vehicle.fly(); my_vehicle.drive(); } ``` **Output:** ```text FlyingCar is flying... ✈️ FlyingCar is driving... 🚙 ``` --- ## **Default and Associated Functions** Rust traits are powerful. They can have **Default Implementations** (pre-written logic) and **Associated Functions** (static utility methods). ### **Default Implementations** Just like Java's `default` keyword, Rust allows you to provide a method body in the trait itself. If a struct doesn't override it, the default logic is used. ```rust trait Animal { fn sound(&self); // Abstract method (Must be implemented) // Default method (Optional to implement) fn sleep(&self) { println!("Sleeping... 💤"); } } struct Dog; impl Animal for Dog { fn sound(&self) { println!("Dog barks! 🐶"); } // We don't implement sleep(), so Dog gets the default behavior. } ``` ### **Associated Functions (Static Methods)** If a function inside a trait does **not** take `&self`, it acts like a Java `static` method. It belongs to the *Type*, not the *Instance*. ```rust trait MathOperations { // No '&self' here, so this is a "Static Method" fn add(a: i32, b: i32) -> i32 { a + b } } // We need a dummy struct to attach this trait to struct Calculator; impl MathOperations for Calculator {} ``` ### **Usage** ```rust fn main() { let my_dog = Dog; my_dog.sound(); my_dog.sleep(); // Calls default implementation // Call static method using the Type name (::) let result = Calculator::add(5, 10); println!("Sum: {}", result); } ``` **Output:** ```text Dog barks! 🐶 Sleeping... 💤 Sum: 15 ``` --- ## **Real-World Example: Payment System** This example demonstrates **Polymorphism**. We want to write a function that can accept *any* payment method, whether it's a Credit Card or PayPal. ```rust // The Contract trait Payment { fn pay(&self, amount: f64); } // Struct 1: Credit Card struct CreditCard; impl Payment for CreditCard { fn pay(&self, amount: f64) { println!("Paid ${:.2} using Credit Card 💳", amount); } } // Struct 2: PayPal struct PayPal; impl Payment for PayPal { fn pay(&self, amount: f64) { println!("Paid ${:.2} using PayPal 🅿️", amount); } } ``` ### **Usage** ```rust fn main() { let card = CreditCard; let paypal = PayPal; // The same function works for different types! // We can use references to the trait object let payments: Vec<&dyn Payment> = vec![&card, &paypal]; for payment in payments { payment.pay(100.50); } } ``` **Output:** ```text Paid $100.50 using Credit Card 💳 Paid $100.50 using PayPal 🅿️ ``` --- ## 📚 New Terminology (Detailed Explanation) Since you are moving from Java to Rust, here are the specific new terms introduced in this topic: | Term | Java Equivalent | Detailed Explanation | | --- | --- | --- | | **Trait** | `Interface` | A set of method signatures. It defines *what* an object can do, but not *how* it does it. | | **`impl Trait for Type`** | `implements` | In Rust, you don't declare implementations inside the struct definition. You use a separate `impl` block to bind the Trait to the Struct. This allows you to add traits to types you didn't even create! | | **`&self`** | `this` | In Java, `this` is hidden/implicit. In Rust, you must **explicitly** pass `&self` as the first argument to any method that works on an instance. If you forget `&self`, Rust thinks it is a static method. | | **Associated Function** | `static` method | A function defined inside a trait/struct that does **not** have `&self`. It is called using `::` (e.g., `Calculator::add`) instead of `.` (dot). | | **`dyn Trait`** | Polymorphism | Short for "Dynamic Dispatch". It tells the compiler: "I don't know the exact size of this object at compile time, but I know it implements this Trait." Used when storing different types in the same list (like `Vec<&dyn Payment>`). | ================================================ FILE: oop/rust/interfaces/main.rs ================================================ /* * INTERFACES IN RUST (TRAITS) * * Goal: Demonstrate how Traits act as contracts (Java Interface equivalent). */ // 1. BASIC INTERFACE // The Contract pub trait Vehicle { fn start(&self); fn stop(&self); } // The Data pub struct Car { pub brand: String, } // The Implementation (Binding Trait to Struct) impl Vehicle for Car { fn start(&self) { println!("{} is starting... 🚗", self.brand); } fn stop(&self) { println!("{} is stopping... 🛑", self.brand); } } // 2. MULTIPLE INTERFACES (Composition) trait Flyable { fn fly(&self); } trait Drivable { fn drive(&self); } struct FlyingCar; impl Flyable for FlyingCar { fn fly(&self) { println!("FlyingCar is flying... ✈️"); } } impl Drivable for FlyingCar { fn drive(&self) { println!("FlyingCar is driving... 🚙"); } } // 3. DEFAULT & STATIC METHODS trait Animal { fn sound(&self); // Default method (Optional to override) fn sleep(&self) { println!("Sleeping... 💤"); } } struct Dog; impl Animal for Dog { fn sound(&self) { println!("Dog barks! 🐶"); } } trait MathOperations { // Associated Function (Static Method) - No '&self' fn add(a: i32, b: i32) -> i32 { a + b } } struct Calculator; impl MathOperations for Calculator {} // 4. REAL WORLD PAYMENT (POLYMORPHISM) trait Payment { fn pay(&self, amount: f64); } struct CreditCard; impl Payment for CreditCard { fn pay(&self, amount: f64) { println!("Paid ${:.2} using Credit Card 💳", amount); } } struct PayPal; impl Payment for PayPal { fn pay(&self, amount: f64) { println!("Paid ${:.2} using PayPal 🅿️", amount); } } fn main() { println!("--- 1. Basic Interface ---"); let my_car = Car { brand: "Toyota".to_string() }; my_car.start(); my_car.stop(); println!("\n--- 2. Multiple Interfaces ---"); let fly_car = FlyingCar; fly_car.fly(); fly_car.drive(); println!("\n--- 3. Default & Static Methods ---"); let dog = Dog; dog.sound(); dog.sleep(); // Uses default implementation // Call static method using the Type name let sum = Calculator::add(5, 10); println!("Sum: {}", sum); println!("\n--- 4. Real World Polymorphism ---"); let cc = CreditCard; let pp = PayPal; // Using explicit loop to simulate processing different payments // '&dyn Payment' allows us to store different types in one list let payments: Vec<&dyn Payment> = vec![&cc, &pp]; for p in payments { p.pay(100.0); } } ================================================ FILE: oop/rust/polymorphism/README.md ================================================ # Polymorphism in Rust (Generics & Trait Objects) ## Introduction **Polymorphism** is one of the four fundamental principles of Object-Oriented Programming (OOP). It allows a single interface to be used for different types of objects, enabling **flexibility**, **scalability**, and **code reuse**. In Java, polymorphism is often divided into "Overloading" and "Overriding." In Rust, we classify it based on **when** the decision is made: 1. **Compile-time Polymorphism (Static Dispatch):** Using **Generics**. fast, zero-cost. 2. **Run-time Polymorphism (Dynamic Dispatch):** Using **Trait Objects** (`dyn`). Flexible, like Java. ## **What is Polymorphism?** **Polymorphism** means "many forms." It allows a function or method to operate on different types. ### **Key Benefits of Polymorphism** - **Code Reusability**: Write a single function that works for multiple types. - **Scalability**: Add new types with minimal code changes. - **Maintainability**: Reduce complexity and improve code clarity. --- ## **1. Compile-Time Polymorphism (Static Dispatch)** In Java, this is Method Overloading. Rust **does not** support traditional Method Overloading (same name, different args). Instead, Rust uses **Generics**. When you write a generic function, the compiler generates a unique copy of that function for *every concrete type* you use. This is called **Monomorphization**. ### **Example of Generics (Static Dispatch)** ```rust trait Addable { fn add(&self, other: i32) -> i32; } struct Number { value: i32 } impl Addable for Number { fn add(&self, other: i32) -> i32 { self.value + other } } // GENERIC FUNCTION: // The compiler creates separate machine code for every type 'T' used. // It effectively converts 'static_add(num)' into 'static_add_Number(num)'. fn static_add(item: T, extra: i32) -> i32 { item.add(extra) } ``` **Why Use Generics?** * **Zero Runtime Cost:** The decision of which function to call happens during compilation. * **Type Safety:** Errors are caught at compile time. --- ## **2. Run-Time Polymorphism (Dynamic Dispatch)** This corresponds to Java's Method Overriding. The exact method to be called is determined **at runtime**. In Rust, we achieve this using **Trait Objects**. A Trait Object involves a pointer (like `&` or `Box`) combined with the `dyn` keyword (e.g., `Box`). This tells Rust: *"I don't know the exact size of this object, so look up its methods in a vtable (virtual table) at runtime."* ### **Example of Trait Objects** ```rust trait Animal { fn make_sound(&self); } struct Dog; impl Animal for Dog { fn make_sound(&self) { println!("Bark"); } } struct Cat; impl Animal for Cat { fn make_sound(&self) { println!("Meow"); } } fn main() { // We store different types in the same list using Box let animals: Vec> = vec![ Box::new(Dog), Box::new(Cat), ]; for animal in animals { // The specific method is decided dynamically at runtime via vtable lookup animal.make_sound(); } } ``` **Why Use Trait Objects?** * Enables **heterogeneous collections** (storing different types in one list). * Supports **polymorphic behavior** where the type isn't known until runtime. --- ## **Real-World Example: Payment System** A common real-world use case is **payment processing**, where we want to process payments regardless of the method (Credit Card, PayPal, etc.). ```rust trait Payment { fn pay(&self, amount: f64); } struct CreditCard; impl Payment for CreditCard { fn pay(&self, amount: f64) { println!("Paid with Card: {}", amount); } } struct PayPal; impl Payment for PayPal { fn pay(&self, amount: f64) { println!("Paid with PayPal: {}", amount); } } // Accepts any type that implements Payment at runtime fn process(method: &dyn Payment, amount: f64) { method.pay(amount); } ``` --- ## 📚 New Terminology (Detailed Explanation) Since you are moving from Java to Rust, here are the specific new terms introduced in this topic: | Term | Java Equivalent | Detailed Explanation | | --- | --- | --- | | **Generics (``)** | Generics | In Java, generics are "erased" at runtime (Type Erasure). In Rust, they are "filled in" at compile time (Monomorphization), making them much faster. | | **Trait Bounds (`T: Animal`)** | `extends Interface` | A rule that says "I will accept any Type T, *as long as* it implements the Animal Trait." | | **`dyn` Keyword** | Runtime Type | Short for "Dynamic". It tells the compiler: "I don't know the exact size of this object right now, so treat it as a generic object implementing this trait." | | **Trait Object** | Interface Reference | A combination of a pointer to data and a pointer to methods (vtable). Example: `Box` or `&dyn Animal`. | | **Static Dispatch** | N/A (Optimization) | The compiler decides *exactly* which function to call while compiling. This is the default in Rust. | | **Dynamic Dispatch** | Method Overriding | The program decides which function to call while running. This is the default in Java. | | **Monomorphization** | N/A | The fancy word for the compiler copying your generic code for every concrete type you use. | | **VTable** | Virtual Method Table | A hidden table of function pointers used to look up methods at runtime for dynamic dispatch. | --- ================================================ FILE: oop/rust/polymorphism/main.rs ================================================ /* * POLYMORPHISM IN RUST * * Goal: Demonstrate Static Dispatch (Generics) and Dynamic Dispatch (Trait Objects). */ // --- 1. COMPILE-TIME POLYMORPHISM (GENERICS) --- // Define a trait trait Addable { fn add(&self, other: i32) -> i32; } // Implement for a struct struct Number { value: i32, } impl Addable for Number { fn add(&self, other: i32) -> i32 { self.value + other } } // Generic Function (Static Dispatch) // T: Addable means "Any type T that implements Addable" // Compiler creates a specific version of this function for 'Number' fn static_add(item: T, extra: i32) -> i32 { item.add(extra) } // --- 2. RUN-TIME POLYMORPHISM (TRAIT OBJECTS) --- trait Animal { fn make_sound(&self); } struct Dog; impl Animal for Dog { fn make_sound(&self) { println!("Dog barks 🐶"); } } struct Cat; impl Animal for Cat { fn make_sound(&self) { println!("Cat meows 🐱"); } } // --- 3. POLYMORPHISM WITH TRAITS (INTERFACES) --- trait Vehicle { fn start(&self); } struct Car; impl Vehicle for Car { fn start(&self) { println!("Car is starting... 🚗"); } } struct Bike; impl Vehicle for Bike { fn start(&self) { println!("Bike is starting... 🏍️"); } } // --- 4. REAL WORLD EXAMPLE: PAYMENT SYSTEM --- trait Payment { fn pay(&self, amount: f64); } struct CreditCardPayment; impl Payment for CreditCardPayment { fn pay(&self, amount: f64) { println!("Paid ${:.2} using Credit Card 💳", amount); } } struct PayPalPayment; impl Payment for PayPalPayment { fn pay(&self, amount: f64) { println!("Paid ${:.2} using PayPal 🅿️", amount); } } // Helper function accepting a Trait Object (Dynamic Dispatch) fn process(payment_method: &dyn Payment, amount: f64) { payment_method.pay(amount); } fn main() { println!("--- 1. Compile-Time Polymorphism (Generics) ---"); let num = Number { value: 10 }; // The compiler generates a specific version of static_add for 'Number' let result = static_add(num, 5); println!("Result: {}", result); println!("\n--- 2. Run-Time Polymorphism (Dynamic Dispatch) ---"); // We use Box to store different types in one Vec // This requires a vtable lookup at runtime let animals: Vec> = vec![ Box::new(Dog), Box::new(Cat), ]; for animal in animals { // Method called is determined at runtime animal.make_sound(); } println!("\n--- 3. Using Polymorphism with Traits ---"); let my_car = Car; let my_bike = Bike; // References (&dyn Vehicle) are also Trait Objects let vehicles: Vec<&dyn Vehicle> = vec![&my_car, &my_bike]; for v in vehicles { v.start(); } println!("\n--- 4. Real-World Example: Payment System ---"); let cc = CreditCardPayment; let pp = PayPalPayment; // We can swap implementations easily process(&cc, 100.50); process(&pp, 200.75); } ================================================ FILE: problems/airline-management-system.md ================================================ # Designing an Airline Management System ## Requirements 1. The airline management system should allow users to search for flights based on source, destination, and date. 2. Users should be able to book flights, select seats, and make payments. 3. The system should manage flight schedules, aircraft assignments, and crew assignments. 4. The system should handle passenger information, including personal details and baggage information. 5. The system should support different types of users, such as passengers, airline staff, and administrators. 6. The system should be able to handle cancellations, refunds, and flight changes. 7. The system should ensure data consistency and handle concurrent access to shared resources. 8. The system should be scalable and extensible to accommodate future enhancements and new features. ## UML Class Diagram ![](../class-diagrams/airlinemanagementsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/airlinemanagementsystem/) #### [Python Implementation](../solutions/python/airlinemanagementsystem/) #### [C++ Implementation](../solutions/cpp/airlinemanagementsystem/) #### [C# Implementation](../solutions/csharp/airlinemanagementsystem/) #### [Go Implementation](../solutions/golang/airlinemanagementsystem/) ## Classes, Interfaces and Enumerations 1. The **Flight** class represents a flight in the airline management system, with properties such as flight number, source, destination, departure time, arrival time, and available seats. 2. The **Aircraft** class represents an aircraft, with properties like tail number, model, and total seats. 3. The **Passenger** class represents a passenger, with properties such as ID, name, email, and phone number. 4. The **Booking** class represents a booking made by a passenger for a specific flight and seat, with properties such as booking number, flight, passenger, seat, price, and booking status. 5. The **Seat** class represents a seat on a flight, with properties like seat number, seat type, and seat status. 6. The **Payment** class represents a payment made for a booking, with properties such as payment ID, payment method, amount, and payment status. 7. The **FlightSearch** class provides functionality to search for flights based on source, destination, and date. 8. The **BookingManager** class manages the creation and cancellation of bookings. It follows the Singleton pattern to ensure a single instance of the booking manager. 9. The **PaymentProcessor** class handles the processing of payments. It follows the Singleton pattern to ensure a single instance of the payment processor. 10. The **AirlineManagementSystem** class serves as the main entry point of the system, combining all the components and providing methods for flight management, booking, payment processing, and other operations. ================================================ FILE: problems/atm.md ================================================ # Designing an ATM System ## Requirements 1. The ATM system should support basic operations such as balance inquiry, cash withdrawal, and cash deposit. 2. Users should be able to authenticate themselves using a card and a PIN (Personal Identification Number). 3. The system should interact with a bank's backend system to validate user accounts and perform transactions. 4. The ATM should have a cash dispenser to dispense cash to users. 5. The system should handle concurrent access and ensure data consistency. 6. The ATM should have a user-friendly interface for users to interact with. ## UML Class Diagram ![](../class-diagrams/atm-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/atm/) #### [Python Implementation](../solutions/python/atm/) #### [C++ Implementation](../solutions/cpp/atm/) #### [C# Implementation](../solutions/csharp/atm/) #### [Go Implementation](../solutions/golang/atm/) ## Classes, Interfaces and Enumerations 1. The **Card** class represents an ATM card with a card number and PIN. 2. The **Account** class represents a bank account with an account number and balance. It provides methods to debit and credit the account balance. 3. The **Transaction** class is an abstract base class for different types of transactions, such as withdrawal and deposit. It is extended by WithdrawalTransaction and DepositTransaction classes. 4. The **BankingService** class manages the bank accounts and processes transactions. It uses a thread-safe ConcurrentHashMap to store and retrieve account information. 5. The **CashDispenser** class represents the ATM's cash dispenser and handles the dispensing of cash. It uses synchronization to ensure thread safety when dispensing cash. 6. The **ATM** class serves as the main interface for ATM operations. It interacts with the BankingService and CashDispenser to perform user authentication, balance inquiry, cash withdrawal, and cash deposit. 7. The **ATMDriver** class demonstrates the usage of the ATM system by creating sample accounts and performing ATM operations. ================================================ FILE: problems/car-rental-system.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## UML Class Diagram ![](../class-diagrams/carrentalsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/carrentalsystem/) #### [Python Implementation](../solutions/python/carrentalsystem/) #### [C++ Implementation](../solutions/cpp/carrentalsystem/) #### [C# Implementation](../solutions/csharp/carrentalsystem/) #### [Go Implementation](../solutions/golang/carrentalsystem/) ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: problems/chess-game.md ================================================ # Designing a Chess Game ## Requirements 1. The chess game should follow the standard rules of chess. 2. The game should support two players, each controlling their own set of pieces. 3. The game board should be represented as an 8x8 grid, with alternating black and white squares. 4. Each player should have 16 pieces: 1 king, 1 queen, 2 rooks, 2 bishops, 2 knights, and 8 pawns. 5. The game should validate legal moves for each piece and prevent illegal moves. 6. The game should detect checkmate and stalemate conditions. 7. The game should handle player turns and allow players to make moves alternately. 8. The game should provide a user interface for players to interact with the game. ## UML Class Diagram ![](../class-diagrams/chessgame-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/chessgame/) #### [Python Implementation](../solutions/python/chessgame/) #### [C++ Implementation](../solutions/cpp/chessgame/) #### [C# Implementation](../solutions/csharp/chessgame/) #### [Go Implementation](../solutions/golang/chessgame/) ## Classes, Interfaces and Enumerations 1. The **Piece** class is an abstract base class representing a chess piece. It contains common attributes such as color, row, and column, and declares an abstract method canMove to be implemented by each specific piece class. 2. The **King**, **Queen**, **Rook**, **Bishop**, **Knight**, and **Pawn** classes extend the Piece class and implement their respective movement logic in the canMove method. 3. The **Board** class represents the chess board and manages the placement of pieces. It provides methods to get and set pieces on the board, check the validity of moves, and determine checkmate and stalemate conditions. 4. The **Player** class represents a player in the game and has a method to make a move on the board. 5. The Move class represents a move made by a player, containing the piece being moved and the destination coordinates. 6. The **Game** class orchestrates the overall game flow. It initializes the board, handles player turns, and determines the game result. 7. The **ChessGame** class is the entry point of the application and starts the game. ================================================ FILE: problems/coffee-vending-machine.md ================================================ # Designing a Coffee Vending Machine ## Requirements 1. The coffee vending machine should support different types of coffee, such as espresso, cappuccino, and latte. 2. Each type of coffee should have a specific price and recipe (ingredients and their quantities). 3. The machine should have a menu to display the available coffee options and their prices. 4. Users should be able to select a coffee type and make a payment. 5. The machine should dispense the selected coffee and provide change if necessary. 6. The machine should track the inventory of ingredients and notify when they are running low. 7. The machine should handle multiple user requests concurrently and ensure thread safety. ## UML Class Diagram ![](../class-diagrams/coffeevendingmachine-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/coffeevendingmachine/) #### [Python Implementation](../solutions/python/coffeevendingmachine/) #### [C++ Implementation](../solutions/cpp/coffeevendingmachine/) #### [C# Implementation](../solutions/csharp/coffeevendingmachine/) #### [Go Implementation](../solutions/golang/coffeevendingmachine/) #### [TypeScript Implementation](../solutions/typescript/src/CoffeeVendingMachine/) ## Classes, Interfaces and Enumerations 1. The **Coffee** class represents a coffee type with its name, price, and recipe (ingredients and their quantities). 2. The **Ingredient** class represents an ingredient used in making coffee, with its name and quantity. It provides a synchronized method to update the quantity. 3. The **Payment** class represents a payment made by a user, with the amount paid. 4. The **CoffeeMachine** class is the main class that manages the coffee vending machine. It follows the Singleton pattern to ensure a single instance of the machine. 5. The **CoffeeMachine** class initializes the coffee menu and ingredients in its constructor. It provides methods to display the menu, select a coffee, dispense coffee, and update ingredient quantities. 6. The hasEnoughIngredients method checks if there are sufficient ingredients to make a selected coffee, while the updateIngredients method updates the ingredient quantities after dispensing a coffee. 7. The **CoffeeVendingMachine** class is the entry point of the application and demonstrates the usage of the coffee vending machine. It creates an instance of the machine, displays the menu, and simulates concurrent user requests using an ExecutorService. ================================================ FILE: problems/concert-ticket-booking-system.md ================================================ # Designing a Concert Ticket Booking System ## Requirements 1. The concert ticket booking system should allow users to view available concerts and their seating arrangements. 2. Users should be able to search for concerts based on various criteria such as artist, venue, date, and time. 3. Users should be able to select seats and purchase tickets for a specific concert. 4. The system should handle concurrent booking requests to avoid double-booking of seats. 5. The system should ensure fair booking opportunities for all users. 6. The system should handle payment processing securely. 7. The system should generate booking confirmations and send them to users via email or SMS. 8. The system should provide a waiting list functionality for sold-out concerts. ## UML Class Diagram ![](../class-diagrams/concertticketbookingsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/concertticketbookingsystem/) #### [Python Implementation](../solutions/python/concertticketbookingsystem/) #### [C++ Implementation](../solutions/cpp/concertticketbookingsystem/) #### [C# Implementation](../solutions/csharp/concertticketbookingsystem/) #### [Go Implementation](../solutions/golang/concertticketbookingsystem/) ## Classes, Interfaces and Enumerations 1. The **Concert** class represents a concert event, with properties such as ID, artist, venue, date and time, and a list of seats. 2. The **Seat** class represents a seat in a concert, with properties like ID, seat number, seat type, price, and status. It provides methods to book and release a seat. 3. The **SeatType** enum represents the different types of seats available, such as regular, premium, and VIP. 4. The **SeatStatus** enum represents the status of a seat, which can be available, booked, or reserved. 5. The **Booking** class represents a booking made by a user for a specific concert and seats. It contains properties such as ID, user, concert, seats, total price, and status. It provides methods to confirm and cancel a booking. 6. The **BookingStatus** enum represents the status of a booking, which can be pending, confirmed, or cancelled. 7. The **User** class represents a user of the concert ticket booking system, with properties like ID, name, and email. 8. The **ConcertTicketBookingSystem** class is the central component of the system. It follows the Singleton pattern to ensure a single instance of the system. It manages concerts, bookings, and provides methods to add concerts, search concerts, book tickets, and cancel bookings. 9. The **SeatNotAvailableException** is a custom exception used to handle cases where a seat is not available for booking. ================================================ FILE: problems/course-registration-system.md ================================================ # Designing a University Course Registration System ## Requirements 1. The course registration system should allow students to register for courses and view their registered courses. 2. Each course should have a course code, name, instructor, and maximum enrollment capacity. 3. Students should be able to search for courses based on course code or name. 4. The system should prevent students from registering for courses that have reached their maximum enrollment capacity. 5. The system should handle concurrent registration requests from multiple students. 6. The system should ensure data consistency and prevent race conditions. 7. The system should be extensible to accommodate future enhancements and new features. ## UML Class Diagram ![](../class-diagrams/courseregistrationsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/courseregistrationsystem/) #### [Python Implementation](../solutions/python/courseregistrationsystem/) #### [C++ Implementation](../solutions/cpp/courseregistrationsystem/) #### [C# Implementation](../solutions/csharp/courseregistrationsystem/) #### [Go Implementation](../solutions/golang/courseregistrationsystem/) ## Classes, Interfaces and Enumerations 1. The **Student** class represents a student in the course registration system, with properties such as ID, name, email, and a list of registered courses. 2. The **Course** class represents a course offered in the system, with properties such as code, name, instructor, maximum capacity, and the number of enrolled students. 3. The **Registration** class represents a registration record, associating a student with a course and capturing the registration timestamp. 4. The **CourseRegistrationSystem** class is the main class that manages the course registration system. It follows the Singleton pattern to ensure only one instance of the system exists. 5. The CourseRegistrationSystem class provides methods for adding courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. 6. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as courses and registrations. 7. The registerCourse method is synchronized to ensure thread safety when multiple students are registering for courses simultaneously. 8. The notifyObservers method is a placeholder for notifying observers (e.g., UI components) about updates to course enrollment. 9. The **CourseRegistrationDemo** class demonstrates the usage of the course registration system by creating courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. ================================================ FILE: problems/cricinfo.md ================================================ # Designing a Cricket Information System like CricInfo ## Requirements 1. The Cricinfo system should provide information about cricket matches, teams, players, and live scores. 2. Users should be able to view the schedule of upcoming matches and the results of completed matches. 3. The system should allow users to search for specific matches, teams, or players. 4. Users should be able to view detailed information about a particular match, including the scorecard, commentary, and statistics. 5. The system should support real-time updates of live scores and match information. 6. The system should handle concurrent access to match data and ensure data consistency. 7. The system should be scalable and able to handle a large volume of user requests. 8. The system should be extensible to accommodate new features and enhancements in the future. ## UML Class Diagram ![](../class-diagrams/cricinfo-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/cricinfo/) #### [Python Implementation](../solutions/python/cricinfo/) #### [C++ Implementation](../solutions/cpp/cricinfo/) #### [C# Implementation](../solutions/csharp/cricinfo/) #### [Go Implementation](../solutions/golang/cricinfo/) ## Classes, Interfaces and Enumerations 1. The **Match** class represents a cricket match, with properties such as ID, title, venue, start time, teams, status, and scorecard. 2. The **Team** class represents a cricket team, with properties like ID, name, and a list of players. 3. The **Player** class represents a cricket player, with properties such as ID, name, and role. 4. The **Scorecard** class represents the scorecard of a match, containing team scores and a list of innings. 5. The **Innings** class represents an innings in a match, with properties like ID, batting team, bowling team, and a list of overs. 6. The **Over** class represents an over in an innings, containing a list of balls. 7. The **Ball** class represents a ball bowled in an over, with properties such as ball number, bowler, batsman, and result. 8. The **MatchStatus** enum represents the different statuses of a match, such as scheduled, in progress, completed, or abandoned. 9. The **MatchService** class manages the matches in the system, providing methods to add, retrieve, and update match information. It follows the Singleton pattern to ensure a single instance of the service. 10. The **ScorecardService** class manages the scorecards of matches, allowing the creation, retrieval, and update of scorecards and their associated data, such as innings and scores. It also follows the Singleton pattern. 11. The **CricinfoSystem** class serves as the main entry point of the system, integrating the match and scorecard services and providing high-level methods for interacting with the system. ================================================ FILE: problems/digital-wallet-service.md ================================================ # Designing a Digital Wallet Service ## Requirements 1. The digital wallet should allow users to create an account and manage their personal information. 2. Users should be able to add and remove payment methods, such as credit cards or bank accounts. 3. The digital wallet should support fund transfers between users and to external accounts. 4. The system should handle transaction history and provide a statement of transactions. 5. The digital wallet should support multiple currencies and perform currency conversions. 6. The system should ensure the security of user information and transactions. 7. The digital wallet should handle concurrent transactions and ensure data consistency. 8. The system should be scalable to handle a large number of users and transactions. ## UML Class Diagram ![](../class-diagrams/digitalwalletservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/digitalwalletservice/) #### [Python Implementation](../solutions/python/digitalwalletservice/) #### [C++ Implementation](../solutions/cpp/digitalwalletservice/) #### [C# Implementation](../solutions/csharp/digitalwalletservice/) #### [Go Implementation](../solutions/golang/digitalwalletservice/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the digital wallet, with properties such as ID, name, email, password, and a list of accounts. 2. The **Account** class represents a user's account within the digital wallet, with properties like ID, user, account number, currency, balance, and a list of transactions. It provides methods to deposit and withdraw funds. 3. The **Transaction** class represents a financial transaction between two accounts, containing properties such as ID, source account, destination account, amount, currency, and timestamp. 4. The **PaymentMethod** class is an abstract base class for different payment methods, such as credit cards and bank accounts. It defines the common properties and methods for processing payments. 5. The **CreditCard** and **BankAccount** classes are concrete implementations of the PaymentMethod class, representing specific payment methods. 6. The **Currency** enum represents different currencies supported by the digital wallet. 7. The **CurrencyConverter** class provides a static method to convert amounts between different currencies based on predefined exchange rates. 8. The **DigitalWallet** class is the central component of the digital wallet system. It follows the Singleton pattern to ensure only one instance of the digital wallet exists. It provides methods to create users, accounts, add payment methods, transfer funds, and retrieve transaction history. It handles concurrent access to shared resources using synchronization. 9. The **DigitalWalletDemo** class demonstrates the usage of the digital wallet system by creating users, accounts, adding payment methods, depositing funds, transferring funds, and retrieving transaction history. ================================================ FILE: problems/elevator-system.md ================================================ # Designing an Elevator System ## Requirements 1. The elevator system should consist of multiple elevators serving multiple floors. 2. Each elevator should have a capacity limit and should not exceed it. 3. Users should be able to request an elevator from any floor and select a destination floor. 4. The elevator system should efficiently handle user requests and optimize the movement of elevators to minimize waiting time. 5. The system should prioritize requests based on the direction of travel and the proximity of the elevators to the requested floor. 6. The elevators should be able to handle multiple requests concurrently and process them in an optimal order. 7. The system should ensure thread safety and prevent race conditions when multiple threads interact with the elevators. ## UML Class Diagram ![](../class-diagrams/elevatorsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/elevatorsystem/) #### [Python Implementation](../solutions/python/elevatorsystem/) #### [C++ Implementation](../solutions/cpp/elevatorsystem/) #### [C# Implementation](../solutions/csharp/elevatorsystem/) #### [Go Implementation](../solutions/golang/elevatorsystem/) ## Classes, Interfaces and Enumerations 1. The **Direction** enum represents the possible directions of elevator movement (UP or DOWN). 2. The **Request** class represents a user request for an elevator, containing the source floor and destination floor. 3. The **Elevator** class represents an individual elevator in the system. It has a capacity limit and maintains a list of 4. requests. The elevator processes requests concurrently and moves between floors based on the requests. 4. The **ElevatorController** class manages multiple elevators and handles user requests. It finds the optimal elevator to serve a request based on the proximity of the elevators to the requested floor. 5. The **ElevatorSystem** class is the entry point of the application and demonstrates the usage of the elevator system. ================================================ FILE: problems/food-delivery-service.md ================================================ # Designing an Online Food Delivery Service Like Swiggy ## Requirements 1. The food delivery service should allow customers to browse restaurants, view menus, and place orders. 2. Restaurants should be able to manage their menus, prices, and availability. 3. Delivery agents should be able to accept and fulfill orders. 4. The system should handle order tracking and status updates. 5. The system should support multiple payment methods. 6. The system should handle concurrent orders and ensure data consistency. 7. The system should be scalable and handle a high volume of orders. 8. The system should provide real-time notifications to customers, restaurants, and delivery agents. ## UML Class Diagram ![](../class-diagrams/fooddeliveryservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/fooddeliveryservice/) #### [Python Implementation](../solutions/python/fooddeliveryservice/) #### [C++ Implementation](../solutions/cpp/fooddeliveryservice/) #### [C# Implementation](../solutions/csharp/fooddeliveryservice/) #### [Go Implementation](../solutions/golang/fooddeliveryservice/) ## Classes, Interfaces and Enumerations 1. The **Customer** class represents a customer who can place orders. It contains customer details such as ID, name, email, and phone number. 2. The **Restaurant** class represents a restaurant that offers menu items. It contains restaurant details such as ID, name, address, and a list of menu items. It provides methods to add and remove menu items. 3. The **MenuItem** class represents an item on a restaurant's menu. It contains details such as ID, name, description, price, and availability status. 4. The **Order** class represents an order placed by a customer. It contains order details such as ID, customer, restaurant, list of order items, status, and assigned delivery agent. It provides methods to add and remove order items, update order status, and assign a delivery agent. 5. The **OrderItem** class represents an item within an order. It contains the selected menu item and the quantity ordered. 6. The **OrderStatus** enum represents the different statuses an order can have, such as PENDING, CONFIRMED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, and CANCELLED. 7. The **DeliveryAgent** class represents a delivery agent who fulfills orders. It contains details such as ID, name, phone number, and availability status. 8. The **FoodDeliveryService** class is the main class that manages the food delivery service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register customers, restaurants, and delivery agents, retrieve available restaurants and menus, place orders, update order status, cancel orders, and assign delivery agents to orders. It also handles notifications to customers, restaurants, and delivery agents. ================================================ FILE: problems/hotel-management-system.md ================================================ # Designing a Hotel Management System ## Requirements 1. The hotel management system should allow guests to book rooms, check-in, and check-out. 2. The system should manage different types of rooms, such as single, double, deluxe, and suite. 3. The system should handle room availability and reservation status. 4. The system should allow the hotel staff to manage guest information, room assignments, and billing. 5. The system should support multiple payment methods, such as cash, credit card, and online payment. 6. The system should handle concurrent bookings and ensure data consistency. 7. The system should provide reporting and analytics features for hotel management. 8. The system should be scalable and handle a large number of rooms and guests. ## UML Class Diagram ![](../class-diagrams/hotelmanagementsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/hotelmanagementsystem/) #### [Python Implementation](../solutions/python/hotelmanagementsystem/) #### [C++ Implementation](../solutions/cpp/hotelmanagementsystem/) #### [C# Implementation](../solutions/csharp/hotelmanagementsystem/) #### [Go Implementation](../solutions/golang/hotelmanagementsystem/) ## Classes, Interfaces and Enumerations 1. The **Guest** class represents a guest of the hotel, with properties such as ID, name, email, and phone number. 2. The **Room** class represents a room in the hotel, with properties like ID, room type, price, and status. It provides methods to book, check-in, and check-out a room. 3. The **RoomType** enum represents the different types of rooms available in the hotel. 4. The **RoomStatus** enum represents the status of a room, which can be available, booked, or occupied. 5. The **Reservation** class represents a reservation made by a guest for a specific room and date range. It contains properties such as ID, guest, room, check-in date, check-out date, and status. It provides a method to cancel a reservation. 6. The **ReservationStatus** enum represents the status of a reservation, which can be confirmed or cancelled. 7. The **Payment** interface defines the contract for processing payments. It is implemented by concrete payment classes like CashPayment and CreditCardPayment. 8. The **HotelManagementSystem** class is the central component of the hotel management system. It follows the Singleton pattern to ensure only one instance of the system exists. It provides methods to add guests and rooms, book rooms, cancel reservations, check-in, check-out, and process payments. It also handles concurrent access to shared resources using synchronization. 9. The **HotelManagementSystemDemo** class demonstrates the usage of the hotel management system by creating guests, rooms, booking a room, checking in, checking out, and cancelling a reservation. ================================================ FILE: problems/library-management-system.md ================================================ # Designing a Library Management System ## Requirements 1. The library management system should allow librarians to manage books, members, and borrowing activities. 2. The system should support adding, updating, and removing books from the library catalog. 3. Each book should have details such as title, author, ISBN, publication year, and availability status. 4. The system should allow members to borrow and return books. 5. Each member should have details such as name, member ID, contact information, and borrowing history. 6. The system should enforce borrowing rules, such as a maximum number of books that can be borrowed at a time and loan duration. 7. The system should handle concurrent access to the library catalog and member records. 8. The system should be extensible to accommodate future enhancements and new features. ## UML Class Diagram ![](../class-diagrams/librarymanagementsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/librarymanagementsystem/) #### [Python Implementation](../solutions/python/librarymanagementsystem/) #### [C++ Implementation](../solutions/cpp/librarymanagementsystem/) #### [C# Implementation](../solutions/csharp/librarymanagementsystem/) #### [Go Implementation](../solutions/golang/librarymanagementsystem/) ## Classes, Interfaces and Enumerations 1. The **Book** class represents a book in the library catalog, with properties such as ISBN, title, author, publication year, and availability status. 2. The **Member** class represents a library member, with properties like member ID, name, contact information, and a list of borrowed books. 3. The **LibraryManager** class is the core of the library management system and follows the Singleton pattern to ensure a single instance of the library manager. 4. The LibraryManager class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to the library catalog and member records. 5. The LibraryManager class provides methods for adding and removing books, registering and unregistering members, borrowing and returning books, and searching for books based on keywords. 6. The **LibraryManagementSystemDemo** class serves as the entry point of the application and demonstrates the usage of the library management system. ================================================ FILE: problems/linkedin.md ================================================ # Designing a Professional Networking Platform like LinkedIn ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their professional information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their professional information, such as profile picture, headline, summary, experience, education, and skills. - Users should be able to update their profile information. #### Connections: - Users should be able to send connection requests to other users. - Users should be able to accept or decline connection requests. - Users should be able to view their list of connections. #### Messaging: - Users should be able to send messages to their connections. - Users should be able to view their inbox and sent messages. #### Job Postings: - Employers should be able to post job listings with details such as title, description, requirements, and location. - Users should be able to view and apply for job postings. #### Search Functionality: - Users should be able to search for other users, companies, and job postings based on relevant criteria. - Search results should be ranked based on relevance and user preferences. #### Notifications: - Users should receive notifications for events such as connection requests, messages, and job postings. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## UML Class Diagram ![](../class-diagrams/linkedin-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/linkedin/) #### [Python Implementation](../solutions/python/linkedin/) #### [C++ Implementation](../solutions/cpp/linkedin/) #### [C# Implementation](../solutions/csharp/linkedin/) #### [Go Implementation](../solutions/golang/linkedin/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the LinkedIn system, containing properties such as ID, name, email, password, profile, connections, inbox, and sent messages. 2. The **Profile** class represents a user's profile, containing properties such as profile picture, headline, summary, experiences, educations, and skills. 3. The **Experience**, **Education**, and **Skill** classes represent different components of a user's profile. 4. The **Connection** class represents a connection between two users, containing the user and the connection date. 5. The **Message** class represents a message sent between users, containing properties such as ID, sender, receiver, content, and timestamp. 6. The **JobPosting** class represents a job listing posted by an employer, containing properties such as ID, title, description, requirements, location, and post date. 7. The **Notification** class represents a notification generated for a user, containing properties such as ID, user, notification type, content, and timestamp. 8. The **NotificationType** enum defines the different types of notifications, such as connection request, message, and job posting. 9. The **LinkedInService** class is the main class that manages the LinkedIn system. It follows the Singleton pattern to ensure only one instance of the service exists. 10. The **LinkedInService** class provides methods for user registration, login, profile updates, connection requests, job postings, user and job search, messaging, and notifications. 11. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 12. The **LinkedInDemo** class demonstrates the usage of the LinkedIn system by registering users, logging in, updating profiles, sending connection requests, posting job listings, searching for users and jobs, sending messages, and retrieving notifications. ================================================ FILE: problems/logging-framework.md ================================================ # Designing a Logging Framework ## Requirements 1. The logging framework should support different log levels, such as DEBUG, INFO, WARNING, ERROR, and FATAL. 2. It should allow logging messages with a timestamp, log level, and message content. 3. The framework should support multiple output destinations, such as console, file, and database. 4. It should provide a configuration mechanism to set the log level and output destination. 5. The logging framework should be thread-safe to handle concurrent logging from multiple threads. 6. It should be extensible to accommodate new log levels and output destinations in the future. ## UML Class Diagram ![](../class-diagrams/loggingframework-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/loggingframework/) #### [Python Implementation](../solutions/python/loggingframework/) #### [C++ Implementation](../solutions/cpp/loggingframework/) #### [C# Implementation](../solutions/csharp/loggingframework/) #### [Go Implementation](../solutions/golang/loggingframework/) #### [TypeScript Implementation](../solutions/typescript/src/LoggingFramework/) ## Classes, Interfaces and Enumerations 1. The **LogLevel** enum defines the different log levels supported by the logging framework. 2. The **LogMessage** class represents a log message with a timestamp, log level, and message content. 3. The **LogAppender** interface defines the contract for appending log messages to different output destinations. 4. The **ConsoleAppender**, **FileAppender**, and **DatabaseAppender** classes are concrete implementations of the LogAppender interface, supporting logging to the console, file, and database, respectively. 5. The **LoggerConfig** class holds the configuration settings for the logger, including the log level and the selected log appender. 6. The **Logger** class is a singleton that provides the main logging functionality. It allows setting the configuration, logging messages at different levels, and provides convenience methods for each log level. 7. The **LoggingExample** class demonstrates the usage of the logging framework, showcasing different log levels, changing the configuration, and logging from multiple threads. ================================================ FILE: problems/lru-cache.md ================================================ # Designing a LRU Cache ## Requirements 1. The LRU cache should support the following operations: - put(key, value): Insert a key-value pair into the cache. If the cache is at capacity, remove the least recently used item before inserting the new item. - get(key): Get the value associated with the given key. If the key exists in the cache, move it to the front of the cache (most recently used) and return its value. If the key does not exist, return -1. 2. The cache should have a fixed capacity, specified during initialization. 3. The cache should be thread-safe, allowing concurrent access from multiple threads. 4. The cache should be efficient in terms of time complexity for both put and get operations, ideally O(1). ## UML Class Diagram ![](../class-diagrams/lrucache-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/lrucache/) #### [Python Implementation](../solutions/python/lrucache/) #### [C++ Implementation](../solutions/cpp/lrucache/) #### [C# Implementation](../solutions/csharp/lrucache/) #### [Go Implementation](../solutions/golang/lrucache/) ## Classes, Interfaces and Enumerations 1. The **Node** class represents a node in the doubly linked list, containing the key, value, and references to the previous and next nodes. 2. The **LRUCache** class implements the LRU cache functionality using a combination of a hash map (cache) and a doubly linked list (head and tail). 3. The get method retrieves the value associated with a given key. If the key exists in the cache, it is moved to the head of the linked list (most recently used) and its value is returned. If the key does not exist, null is returned. 4. The put method inserts a key-value pair into the cache. If the key already exists, its value is updated, and the node is moved to the head of the linked list. If the key does not exist and the cache is at capacity, the least recently used item (at the tail of the linked list) is removed, and the new item is inserted at the head. 5. The addToHead, removeNode, moveToHead, and removeTail methods are helper methods to manipulate the doubly linked list. 6. The synchronized keyword is used on the get and put methods to ensure thread safety, allowing concurrent access from multiple threads. 7. The **LRUCacheDemo** class demonstrates the usage of the LRU cache by creating an instance of LRUCache with a capacity of 3, performing various put and get operations, and printing the results. ================================================ FILE: problems/movie-ticket-booking-system.md ================================================ # Designing a Movie Ticket Booking System like BookMyShow ## Requirements 1. The system should allow users to view the list of movies playing in different theaters. 2. Users should be able to select a movie, theater, and show timing to book tickets. 3. The system should display the seating arrangement of the selected show and allow users to choose seats. 4. Users should be able to make payments and confirm their booking. 5. The system should handle concurrent bookings and ensure seat availability is updated in real-time. 6. The system should support different types of seats (e.g., normal, premium) and pricing. 7. The system should allow theater administrators to add, update, and remove movies, shows, and seating arrangements. 8. The system should be scalable to handle a large number of concurrent users and bookings. ## UML Class Diagram ![](../class-diagrams/movieticketbookingsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/movieticketbookingsystem/) #### [Python Implementation](../solutions/python/movieticketbookingsystem/) #### [C++ Implementation](../solutions/cpp/movieticketbookingsystem/) #### [C# Implementation](../solutions/csharp/movieticketbookingsystem/) #### [Go Implementation](../solutions/golang/movieticketbookingsystem/) ## Classes, Interfaces and Enumerations 1. The **Movie** class represents a movie with properties such as ID, title, description, and duration. 2. The **Theater** class represents a theater with properties such as ID, name, location, and a list of shows. 3. The **Show** class represents a movie show in a theater, with properties such as ID, movie, theater, start time, end time, and a map of seats. 4. The **Seat** class represents a seat in a show, with properties such as ID, row, column, type, price, and status. 5. The **SeatType** enum defines the different types of seats (normal or premium). 6. The **SeatStatus** enum defines the different statuses of a seat (available or booked). 7. The **Booking** class represents a booking made by a user, with properties such as ID, user, show, selected seats, total price, and status. 8. The **BookingStatus** enum defines the different statuses of a booking (pending, confirmed, or cancelled). 9. The **User** class represents a user of the booking system, with properties such as ID, name, and email. 10. The **MovieTicketBookingSystem** class is the main class that manages the movie ticket booking system. It follows the Singleton pattern to ensure only one instance of the system exists. 11. The MovieTicketBookingSystem class provides methods for adding movies, theaters, and shows, as well as booking tickets, confirming bookings, and cancelling bookings. 12. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap to handle concurrent access to shared resources like shows and bookings. 13. The **MovieTicketBookingDemo** class demonstrates the usage of the movie ticket booking system by adding movies, theaters, shows, booking tickets, and confirming or cancelling bookings. ================================================ FILE: problems/music-streaming-service.md ================================================ # Designing an Online Music Streaming Service Like Spotify ## Requirements 1. The music streaming service should allow users to browse and search for songs, albums, and artists. 2. Users should be able to create and manage playlists. 3. The system should support user authentication and authorization. 4. Users should be able to play, pause, skip, and seek within songs. 5. The system should recommend songs and playlists based on user preferences and listening history. 6. The system should handle concurrent requests and ensure smooth streaming experience for multiple users. 7. The system should be scalable and handle a large volume of songs and users. 8. The system should be extensible to support additional features such as social sharing and offline playback. ## UML Class Diagram ![](../class-diagrams/musicstreamingservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/musicstreamingservice/) #### [Python Implementation](../solutions/python/musicstreamingservice/) #### [C++ Implementation](../solutions/cpp/musicstreamingservice/) #### [C# Implementation](../solutions/csharp/musicstreamingservice/) #### [Go Implementation](../solutions/golang/musicstreamingservice/) ## Classes, Interfaces and Enumerations 1. The **Song**, **Album**, and **Artist** classes represent the basic entities in the music streaming service, with properties such as ID, title, artist, album, duration, and relationships between them. 2. The **User** class represents a user of the music streaming service, with properties like ID, username, password, and a list of playlists. 3. The **Playlist** class represents a user-created playlist, containing a list of songs. 4. The **MusicLibrary** class serves as a central repository for storing and managing songs, albums, and artists. It follows the Singleton pattern to ensure a single instance of the music library. 5. The **UserManager** class handles user registration, login, and other user-related operations. It also follows the Singleton pattern. 6. The **MusicPlayer** class represents the music playback functionality, allowing users to play, pause, skip, and seek within songs. 7. The **MusicRecommender** class generates song recommendations based on user preferences and listening history. It follows the Singleton pattern. 8. The **MusicStreamingService** class is the main entry point of the music streaming service. It initializes the necessary components, handles user requests, and manages the overall functionality of the service. ================================================ FILE: problems/online-auction-system.md ================================================ # Designing an Online Auction System In this article, we delve into the object-oriented design and implementation of an Online Auction System using Java. This system allows for the creation and management of auctions, user participation in bidding, and handling transactions. ## Requirements 1. The online auction system should allow users to register and log in to their accounts. 2. Users should be able to create new auction listings with details such as item name, description, starting price, and auction duration. 3. Users should be able to browse and search for auction listings based on various criteria (e.g., item name, category, price range). 4. Users should be able to place bids on active auction listings. 5. The system should automatically update the current highest bid and notify the bidders accordingly. 6. The auction should end when the specified duration is reached, and the highest bidder should be declared the winner. 7. The system should handle concurrent access to auction listings and ensure data consistency. 8. The system should be extensible to accommodate future enhancements and new features. ## UML Class Diagram ![](../class-diagrams/onlineauctionsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/onlineauctionsystem/) #### [Python Implementation](../solutions/python/onlineauctionsystem/) #### [C++ Implementation](../solutions/cpp/onlineauctionsystem/) #### [C# Implementation](../solutions/csharp/onlineauctionsystem/) #### [Go Implementation](../solutions/golang/onlineauctionsystem/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online auction system, with properties such as id, username, and email. 2. The **AuctionStatus** enum defines the possible states of an auction listing, such as active and closed. 3. The **AuctionListing** class represents an auction listing in the system, with properties like id, item name, description, starting price, duration, seller, current highest bid, and a list of bids. 4. The **Bid** class represents a bid placed by a user on an auction listing, with properties such as id, bidder, amount, and timestamp. 5. The **AuctionSystem** class is the core of the online auction system and follows the Singleton pattern to ensure a single instance of the auction system. 6. The AuctionSystem class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to auction listings and ensure thread safety. 7. The AuctionSystem class provides methods for registering users, creating auction listings, searching auction listings, and placing bids. 8. The **AuctionSystemDemo** class serves as the entry point of the application and demonstrates the usage of the online auction system. ================================================ FILE: problems/online-shopping-service.md ================================================ # Designing an Online Shopping System Like Amazon ## Requirements 1. The online shopping service should allow users to browse products, add them to the shopping cart, and place orders. 2. The system should support multiple product categories and provide search functionality. 3. Users should be able to manage their profiles, view order history, and track order status. 4. The system should handle inventory management and update product availability accordingly. 5. The system should support multiple payment methods and ensure secure transactions. 6. The system should handle concurrent user requests and ensure data consistency. 7. The system should be scalable to handle a large number of products and users. 8. The system should provide a user-friendly interface for a seamless shopping experience. ## UML Class Diagram ![](../class-diagrams/onlineshoppingservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/onlineshoppingservice/) #### [Python Implementation](../solutions/python/onlineshoppingservice/) #### [C++ Implementation](../solutions/cpp/onlineshoppingservice/) #### [C# Implementation](../solutions/csharp/onlineshoppingservice/) #### [Go Implementation](../solutions/golang/onlineshoppingservice/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online shopping service, with properties such as ID, name, email, password, and a list of orders. 2. The **Product** class represents a product available for purchase, with properties like ID, name, description, price, and quantity. It provides methods to update the quantity and check product availability. 3. The **Order** class represents an order placed by a user, containing properties such as ID, user, order items, total amount, and order status. It calculates the total amount based on the order items. 4. The **OrderItem** class represents an item within an order, consisting of the product and the quantity ordered. 5. The **OrderStatus** enum represents the different statuses an order can have, such as pending, processing, shipped, delivered, or cancelled. 6. The **ShoppingCart** class represents the user's shopping cart, allowing them to add, remove, and update item quantities. It maintains a map of product IDs and order items. 7. The **Payment** interface defines the contract for processing payments, with a concrete implementation CreditCardPayment. 8. The **OnlineShoppingService** class is the central component of the online shopping service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register users, add products, search products, place orders, and retrieve order information. It handles concurrent access to shared resources using synchronization. 9. The **OnlineShoppingServiceDemo** class demonstrates the usage of the online shopping service by registering users, adding products, searching for products, placing orders, and viewing order history. ================================================ FILE: problems/online-stock-brokerage-system.md ================================================ # Designing an Online Stock Brokerage System ## Requirements 1. The online stock brokerage system should allow users to create and manage their trading accounts. 2. Users should be able to buy and sell stocks, as well as view their portfolio and transaction history. 3. The system should provide real-time stock quotes and market data to users. 4. The system should handle order placement, execution, and settlement processes. 5. The system should enforce various business rules and validations, such as checking account balances and stock availability. 6. The system should handle concurrent user requests and ensure data consistency and integrity. 7. The system should be scalable and able to handle a large number of users and transactions. 8. The system should be secure and protect sensitive user information. ## UML Class Diagram ![](../class-diagrams/onlinestockbrokeragesystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/onlinestockbrokeragesystem/) #### [Python Implementation](../solutions/python/onlinestockbrokeragesystem/) #### [C++ Implementation](../solutions/cpp/onlinestockbrokeragesystem/) #### [C# Implementation](../solutions/csharp/onlinestockbrokeragesystem/) #### [Go Implementation](../solutions/golang/onlinestockbrokeragesystem/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the stock brokerage system, with properties such as user ID, name, and email. 2. The **Account** class represents a user's trading account, with properties like account ID, associated user, and balance. It provides methods for depositing and withdrawing funds. 3. The **Stock** class represents a stock that can be traded, with properties such as symbol, name, and price. It provides a method for updating the stock price. 4. The **Order** class is an abstract base class representing an order placed by a user. It contains common properties such as order ID, associated account, stock, quantity, price, and order status. The execute() method is declared as abstract, to be implemented by concrete order classes. 5. The **BuyOrder** and **SellOrder** classes are concrete implementations of the Order class, representing buy and sell orders respectively. They provide the implementation for the execute() method specific to each order type. 6. The **OrderStatus** enum represents the possible statuses of an order, such as PENDING, EXECUTED, or REJECTED. 7. The **Portfolio** class represents a user's portfolio, which holds the stocks owned by the user. It provides methods for adding and removing stocks from the portfolio. 8. The **StockBroker** class is the central component of the stock brokerage system. It follows the Singleton pattern to ensure a single instance of the stock broker. It manages user accounts, stocks, and order processing. It provides methods for creating accounts, adding stocks, placing orders, and processing orders. 9. The **InsufficientFundsException** and **InsufficientStockException** classes are custom exceptions used to handle insufficient funds and insufficient stock scenarios respectively. 10. The **StockBrokerageSystem** class serves as the entry point of the application and demonstrates the usage of the stock brokerage system. ================================================ FILE: problems/parking-lot.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot should have multiple levels, each level with a certain number of parking spots. 2. The parking lot should support different types of vehicles, such as cars, motorcycles, and trucks. 3. Each parking spot should be able to accommodate a specific type of vehicle. 4. The system should assign a parking spot to a vehicle upon entry and release it when the vehicle exits. 5. The system should track the availability of parking spots and provide real-time information to customers. 6. The system should handle multiple entry and exit points and support concurrent access. ## UML Class Diagram ![](../class-diagrams/parkinglot-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/parkinglot/) #### [Python Implementation](../solutions/python/parkinglot/) #### [C++ Implementation](../solutions/cpp/parkinglot/) #### [C# Implementation](../solutions/csharp/parkinglot/) #### [Go Implementation](../solutions/golang/parkinglot/) #### [TypeScript Implementation](../solutions/typescript/src/ParkingLot/) ## Classes, Interfaces and Enumerations 1. The **ParkingLot** class follows the Singleton pattern to ensure only one instance of the parking lot exists. It maintains a list of levels and provides methods to park and unpark vehicles. 2. The **ParkingFloor** class represents a level in the parking lot and contains a list of parking spots. It handles parking and unparking of vehicles within the level. 3. The **ParkingSpot** class represents an individual parking spot and tracks the availability and the parked vehicle. 4. The **Vehicle** class is an abstract base class for different types of vehicles. It is extended by Car, Motorcycle, and Truck classes. 5. The **VehicleSize** enum defines the different types of vehicles supported by the parking lot. 6. Multi-threading is achieved through the use of synchronized keyword on critical sections to ensure thread safety. 7. The **Main** class demonstrates the usage of the parking lot system. ## Design Patterns Used: 1. Singleton Pattern: Ensures only one instance of the ParkingLot class. 2. Factory Pattern (optional extension): Could be used for creating vehicles based on input. 3. Observer Pattern (optional extension): Could notify customers about available spots. ================================================ FILE: problems/pub-sub-system.md ================================================ # Designing a Pub-Sub System in Java ## Requirements 1. The Pub-Sub system should allow publishers to publish messages to specific topics. 2. Subscribers should be able to subscribe to topics of interest and receive messages published to those topics. 3. The system should support multiple publishers and subscribers. 4. Messages should be delivered to all subscribers of a topic in real-time. 5. The system should handle concurrent access and ensure thread safety. 6. The Pub-Sub system should be scalable and efficient in terms of message delivery. ## UML Class Diagram ![](../class-diagrams/pubsubsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/pubsubsystem/) #### [Python Implementation](../solutions/python/pubsubsystem/) #### [C++ Implementation](../solutions/cpp/pubsubsystem/) #### [C# Implementation](../solutions/csharp/pubsubsystem/) #### [Go Implementation](../solutions/golang/pubsubsystem/) ## Classes, Interfaces and Enumerations 1. The **Message** class represents a message that can be published and received by subscribers. It contains the message content. 2. The **Topic** class represents a topic to which messages can be published. It maintains a set of subscribers and provides methods to add and remove subscribers, as well as publish messages to all subscribers. 3. The **Subscriber** interface defines the contract for subscribers. It declares the onMessage method that is invoked when a subscriber receives a message. 4. The **PrintSubscriber** class is a concrete implementation of the Subscriber interface. It receives messages and prints them to the console. 5. The **Publisher** class represents a publisher that publishes messages to a specific topic. 6. The **PubSubSystem** class is the main class that manages topics, subscribers, and message publishing. It uses a ConcurrentHashMap to store topics and an ExecutorService to handle concurrent message publishing. 7. The **PubSubDemo** class demonstrates the usage of the Pub-Sub system by creating topics, subscribers, and publishers, and publishing messages. ================================================ FILE: problems/restaurant-management-system.md ================================================ # Designing Restaurant Management System ## Requirements 1. The restaurant management system should allow customers to place orders, view the menu, and make reservations. 2. The system should manage the restaurant's inventory, including ingredients and menu items. 3. The system should handle order processing, including order preparation, billing, and payment. 4. The system should support multiple payment methods, such as cash, credit card, and mobile payments. 5. The system should manage staff information, including roles, schedules, and performance tracking. 6. The system should generate reports and analytics for management, such as sales reports and inventory analysis. 7. The system should handle concurrent access and ensure data consistency. ## UML Class Diagram ![](../class-diagrams/restaurantmanagementsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/restaurantmanagementsystem/) #### [Python Implementation](../solutions/python/restaurantmanagementsystem/) #### [C++ Implementation](../solutions/cpp/restaurantmanagementsystem/) #### [C# Implementation](../solutions/csharp/restaurantmanagementsystem/) #### [Go Implementation](../solutions/golang/restaurantmanagementsystem/) ## Classes, Interfaces and Enumerations 1. The **MenuItem** class represents a menu item in the restaurant, with properties such as ID, name, description, price, and availability. 2. The **Order** class represents an order placed by a customer, with properties such as ID, list of menu items, total amount, order status, and timestamp. 3. The **OrderStatus** enum represents the different statuses an order can have, such as pending, preparing, ready, completed, or cancelled. 4. The **Reservation** class represents a reservation made by a customer, with properties such as ID, customer name, contact number, party size, and reservation time. 5. The **Payment** class represents a payment made for an order, with properties such as ID, amount, payment method, and payment status. 6. The **PaymentMethod** enum represents the different payment methods supported by the restaurant, such as cash, credit card, or mobile payment. 7. The **PaymentStatus** enum represents the status of a payment, which can be pending, completed, or failed. 8. The Staff class represents a staff member of the restaurant, with properties such as ID, name, role, and contact number. 9. The **Restaurant** class is the main class that manages the restaurant operations. It follows the Singleton pattern to ensure only one instance of the restaurant exists. 10. The Restaurant class provides methods for managing menu items, placing orders, updating order status, making reservations, processing payments, and managing staff. 11. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as orders and reservations. 12. The notifyKitchen and notifyStaff methods are placeholders for notifying relevant staff about order updates and status changes. 13. The **RestaurantManagementDemo** class demonstrates the usage of the restaurant management system by adding menu items, placing an order, making a reservation, processing a payment, updating order status, adding staff, and retrieving the menu. ================================================ FILE: problems/ride-sharing-service.md ================================================ # Designing a Ride-Sharing Service Like Uber ## Requirements 1. The ride sharing service should allow passengers to request rides and drivers to accept and fulfill those ride requests. 2. Passengers should be able to specify their pickup location, destination, and desired ride type (e.g., regular, premium). 3. Drivers should be able to see available ride requests and choose to accept or decline them. 4. The system should match ride requests with available drivers based on proximity and other factors. 5. The system should calculate the fare for each ride based on distance, time, and ride type. 6. The system should handle payments and process transactions between passengers and drivers. 7. The system should provide real-time tracking of ongoing rides and notify passengers and drivers about ride status updates. 8. The system should handle concurrent requests and ensure data consistency. ## UML Class Diagram ![](../class-diagrams/ridesharingservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/ridesharingservice/) #### [Python Implementation](../solutions/python/ridesharingservice/) #### [C++ Implementation](../solutions/cpp/ridesharingservice/) #### [C# Implementation](../solutions/csharp/ridesharingservice/) #### [Go Implementation](../solutions/golang/ridesharingservice/) ## Classes, Interfaces and Enumerations 1. The **Passenger** class represents a passenger in the ride sharing service, with properties such as ID, name, contact information, and location. 2. The **Driver** class represents a driver in the ride sharing service, with properties such as ID, name, contact information, license plate, location, and status (available or busy). 3. The **Ride** class represents a ride requested by a passenger and accepted by a driver, with properties such as ID, passenger, driver, source location, destination location, status, and fare. 4. The **Location** class represents a geographical location with latitude and longitude coordinates. 5. The **Payment** class represents a payment made for a ride, with properties such as ID, ride, amount, and payment status. 6. The **RideService** class is the main class that manages the ride sharing service. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The RideService class provides methods for adding passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. 8. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and ConcurrentLinkedQueue) to handle concurrent access to shared data, such as ride requests and driver availability. 9. The notifyDrivers, notifyPassenger, and notifyDriver methods are placeholders for notifying relevant parties about ride status updates. 10. The calculateFare and processPayment methods are placeholders for calculating ride fares and processing payments, respectively. 11. The **RideSharingDemo** class demonstrates the usage of the ride sharing service by creating passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. ================================================ FILE: problems/snake-and-ladder.md ================================================ # Designing Snake and Ladder Game ## Requirements 1. The game should be played on a board with numbered cells, typically with 100 cells. 2. The board should have a predefined set of snakes and ladders, connecting certain cells. 3. The game should support multiple players, each represented by a unique game piece. 4. Players should take turns rolling a dice to determine the number of cells to move forward. 5. If a player lands on a cell with the head of a snake, they should slide down to the cell with the tail of the snake. 6. If a player lands on a cell with the base of a ladder, they should climb up to the cell at the top of the ladder. 7. The game should continue until one of the players reaches the final cell on the board. 8. The game should handle multiple game sessions concurrently, allowing different groups of players to play independently. ## UML Class Diagram ![](../class-diagrams/snakeandladdergame-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/snakeandladdergame/) #### [Python Implementation](../solutions/python/snakeandladdergame/) #### [C++ Implementation](../solutions/cpp/snakeandladdergame/) #### [C# Implementation](../solutions/csharp/snakeandladdergame/) #### [Go Implementation](../solutions/golang/snakeandladdergame/) ## Classes, Interfaces and Enumerations 1. The **Board** class represents the game board with a fixed size (e.g., 100 cells). It contains the positions of snakes and ladders and provides methods to initialize them and retrieve the new position after encountering a snake or ladder. 2. The **Player** class represents a player in the game, with properties such as name and current position on the board. 3. The **Snake** class represents a snake on the board, with properties for the start and end positions. 4. The **Ladder** class represents a ladder on the board, with properties for the start and end positions. 5. The **Dice** class represents a dice used in the game, with a method to roll the dice and return a random value between 1 and 6. 6. The **SnakeAndLadderGame** class represents a single game session. It initializes the game with a board, a list of players, and a dice. The play method handles the game loop, where players take turns rolling the dice and moving their positions on the board. It checks for snakes and ladders and updates the player's position accordingly. The game continues until a player reaches the final position on the board. 7. The **GameManager** class is a singleton that manages multiple game sessions. It maintains a list of active games and provides a method to start a new game with a list of player names. Each game is started in a separate thread to allow concurrent game sessions. 8. The **SnakeAndLadderDemo** class demonstrates the usage of the game by creating an instance of the GameManager and starting two separate game sessions with different sets of players. ================================================ FILE: problems/social-networking-service.md ================================================ # Designing a Social Network Like Facebook ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their personal information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their information, such as profile picture, bio, and interests. - Users should be able to update their profile information. #### Friend Connections: - Users should be able to send friend requests to other users. - Users should be able to accept or decline friend requests. - Users should be able to view their list of friends. #### Posts and Newsfeed: - Users should be able to create posts with text, images, or videos. - Users should be able to view a newsfeed consisting of posts from their friends and their own posts. - The newsfeed should be sorted in reverse chronological order. #### Likes and Comments: - Users should be able to like and comment on posts. - Users should be able to view the list of likes and comments on a post. #### Privacy and Security: - Users should be able to control the visibility of their posts and profile information. - The system should enforce secure access control to ensure data privacy. #### Notifications: - Users should receive notifications for events such as friend requests, likes, comments, and mentions. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## UML Class Diagram ![](../class-diagrams/socialnetworkingservice-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/socialnetworkingservice/) #### [Python Implementation](../solutions/python/socialnetworkingservice/) #### [C++ Implementation](../solutions/cpp/socialnetworkingservice/) #### [C# Implementation](../solutions/csharp/socialnetworkingservice/) #### [Go Implementation](../solutions/golang/socialnetworkingservice/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the social networking system, containing properties such as ID, name, email, password, profile picture, bio, list of friends, and list of posts. 2. The **Post** class represents a post created by a user, containing properties such as ID, user ID, content, image URLs, video URLs, timestamp, likes, and comments. 3. The **Comment** class represents a comment made by a user on a post, containing properties such as ID, user ID, post ID, content, and timestamp. 4. The **Notification** class represents a notification generated for a user, containing properties such as ID, user ID, notification type, content, and timestamp. 5. The **NotificationType** enum defines the different types of notifications, such as friend request, friend request accepted, like, comment, and mention. 6. The **SocialNetworkingService** class is the main class that manages the social networking system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SocialNetworkingService class provides methods for user registration, login, profile updates, friend requests, post creation, newsfeed generation, likes, comments, and notifications. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SocialNetworkingDemo** class demonstrates the usage of the social networking system by registering users, logging in, sending friend requests, creating posts, liking posts, commenting on posts, and retrieving newsfeed and notifications. ================================================ FILE: problems/splitwise.md ================================================ # Designing Splitwise ## Requirements 1. The system should allow users to create accounts and manage their profile information. 2. Users should be able to create groups and add other users to the groups. 3. Users should be able to add expenses within a group, specifying the amount, description, and participants. 4. The system should automatically split the expenses among the participants based on their share. 5. Users should be able to view their individual balances with other users and settle up the balances. 6. The system should support different split methods, such as equal split, percentage split, and exact amounts. 7. Users should be able to view their transaction history and group expenses. 8. The system should handle concurrent transactions and ensure data consistency. ## UML Class Diagram ![](../class-diagrams/splitwise-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/splitwise/) #### [Python Implementation](../solutions/python/splitwise/) #### [C++ Implementation](../solutions/cpp/splitwise/) #### [C# Implementation](../solutions/csharp/splitwise/) #### [Go Implementation](../solutions/golang/splitwise/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the Splitwise system, with properties such as ID, name, email, and a map to store balances with other users. 2. The **Group** class represents a group in Splitwise, containing a list of member users and a list of expenses. 3. The **Expense** class represents an expense within a group, with properties such as ID, amount, description, the user who paid, and a list of splits. 4. The **Split** class is an abstract class representing the split of an expense. It is extended by EqualSplit, PercentSplit, and ExactSplit classes to handle different split methods. 5. The **Transaction** class represents a transaction between two users, with properties such as ID, sender, receiver, and amount. 6. The **SplitwiseService** class is the main class that manages the Splitwise system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SplitwiseService class provides methods for adding users, groups, and expenses, splitting expenses, updating balances, settling balances, and creating transactions. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SplitwiseDemo** class demonstrates the usage of the Splitwise system by creating users, a group, adding an expense, settling balances, and printing user balances. ================================================ FILE: problems/stack-overflow.md ================================================ # Designing Stack Overflow ## Requirements 1. Users can post questions, answer questions, and comment on questions and answers. 2. Users can vote on questions and answers. 3. Questions should have tags associated with them. 4. Users can search for questions based on keywords, tags, or user profiles. 5. The system should assign reputation score to users based on their activity and the quality of their contributions. 6. The system should handle concurrent access and ensure data consistency. ## UML Class Diagram ![](../class-diagrams/stackoverflow-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/stackoverflow/) #### [Python Implementation](../solutions/python/stackoverflow/) #### [C++ Implementation](../solutions/cpp/stackoverflow/) #### [C# Implementation](../solutions/csharp/stackoverflow/) #### [Go Implementation](../solutions/golang/stackoverflow/) #### [TypeScript Implementation](../solutions/typescript/src/StackOverflow/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the Stack Overflow system, with properties such as id, username, email, and reputation. 2. The **Question** class represents a question posted by a user, with properties such as id, title, content, author, answers, comments, tags, votes and creation date. 3. The **Answer** class represents an answer to a question, with properties such as id, content, author, associated question, comments, votes and creation date. 4. The **Comment** class represents a comment on a question or an answer, with properties such as id, content, author, and creation date. 5. The **Tag** class represents a tag associated with a question, with properties such as id and name. 6. The **Vote** class represents vote associated with a question/answer. 7. The **StackOverflow** class is the main class that manages the Stack Overflow system. It provides methods for creating user, posting questions, answers, and comments, voting on questions and answers, searching for questions, and retrieving questions by tags and users. 8. The **StackOverflowDemo** class demonstrates the usage of the Stack Overflow system by creating users, posting questions and answers, voting, searching for questions, and retrieving questions by tags and users. ================================================ FILE: problems/task-management-system.md ================================================ # Designing a Task Management System ## Requirements 1. The task management system should allow users to create, update, and delete tasks. 2. Each task should have a title, description, due date, priority, and status (e.g., pending, in progress, completed). 3. Users should be able to assign tasks to other users and set reminders for tasks. 4. The system should support searching and filtering tasks based on various criteria (e.g., priority, due date, assigned user). 5. Users should be able to mark tasks as completed and view their task history. 6. The system should handle concurrent access to tasks and ensure data consistency. 7. The system should be extensible to accommodate future enhancements and new features. ## UML Class Diagram ![](../class-diagrams/taskmanagementsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/taskmanagementsystem/) #### [Python Implementation](../solutions/python/taskmanagementsystem/) #### [C++ Implementation](../solutions/cpp/taskmanagementsystem/) #### [C# Implementation](../solutions/csharp/taskmanagementsystem/) #### [Go Implementation](../solutions/golang/taskmanagementsystem/) #### [TypeScript Implementation](../solutions/typescript/src/TaskManagement/) ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the task management system, with properties such as id, name, and email. 2. The **TaskStatus** enum defines the possible states of a task, such as pending, in progress, and completed. 3. The **Task** class represents a task in the system, with properties like id, title, description, due date, priority, status, and assigned user. 4. The **TaskManager** class is the core of the task management system and follows the Singleton pattern to ensure a single instance of the task manager. 5. The TaskManager class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to tasks and ensure thread safety. 6. The TaskManager class provides methods for creating, updating, deleting, searching, and filtering tasks, as well as marking tasks as completed and retrieving task history for a user. 7. The **TaskManagementSystem** class serves as the entry point of the application and demonstrates the usage of the task management system. ================================================ FILE: problems/tic-tac-toe.md ================================================ # Designing a Tic Tac Toe Game ## Requirements 1. The Tic-Tac-Toe game should be played on a 3x3 grid. 2. Two players take turns marking their symbols (X or O) on the grid. 3. The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins the game. 4. If all the cells on the grid are filled and no player has won, the game ends in a draw. 5. The game should have a user interface to display the grid and allow players to make their moves. 6. The game should handle player turns and validate moves to ensure they are legal. 7. The game should detect and announce the winner or a draw at the end of the game. ## UML Class Diagram ![](../class-diagrams/tictactoe-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/tictactoe/) #### [Python Implementation](../solutions/python/tictactoe/) #### [C++ Implementation](../solutions/cpp/tictactoe/) #### [C# Implementation](../solutions/csharp/tictactoe/) #### [Go Implementation](../solutions/golang/tictactoe/) ## Classes, Interfaces and Enumerations 1. The **Player** class represents a player in the game, with a name and a symbol (X or O). 2. The **Board** class represents the game board, which is a 3x3 grid. It provides methods to make moves, check for a winner, and check if the board is full. 3. The **Game** class manages the game flow and player interactions. It handles player turns, validates moves, and determines the winner or a draw. 4. The **TicTacToe** class is the entry point of the application and creates instances of the players and the game. ================================================ FILE: problems/traffic-signal.md ================================================ # Designing a Traffic Signal Control System ## Requirements 1. The traffic signal system should control the flow of traffic at an intersection with multiple roads. 2. The system should support different types of signals, such as red, yellow, and green. 3. The duration of each signal should be configurable and adjustable based on traffic conditions. 4. The system should handle the transition between signals smoothly, ensuring safe and efficient traffic flow. 5. The system should be able to detect and handle emergency situations, such as an ambulance or fire truck approaching the intersection. 6. The system should be scalable and extensible to support additional features and functionality. ## UML Class Diagram ![](../class-diagrams/trafficsignalsystem-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/trafficsignalcontrolsystem/) #### [Python Implementation](../solutions/python/trafficsignalsystem/) #### [C++ Implementation](../solutions/cpp/trafficsignalsystem/) #### [C# Implementation](../solutions/csharp/trafficsignalsystem/) #### [Go Implementation](../solutions/golang/trafficsignalsystem/) #### [TypeScript Implementation](../solutions/typescript/src/TrafficSignalSystem/) ## Classes, Interfaces and Enumerations 1. The **Signal** enum represents the different states of a traffic light: red, yellow, and green. 2. The **Road** class represents a road in the traffic signal system, with properties such as ID, name, and an associated traffic light. 3. The **TrafficLight** class represents a traffic light, with properties such as ID, current signal, and durations for each signal state. It provides methods to change the signal and notify observers (e.g., roads) about signal changes. 4. The **TrafficController** class serves as the central controller for the traffic signal system. It follows the Singleton pattern to ensure a single instance of the controller. It manages the roads and their associated traffic lights, starts the traffic control process, and handles emergency situations. 5. The **TrafficSignalSystemDemo** class is the main entry point of the application. It demonstrates the usage of the traffic signal system by creating roads, traffic lights, assigning traffic lights to roads, and starting the traffic control process. ================================================ FILE: problems/vending-machine.md ================================================ # Designing a Vending Machine ## Requirements 1. The vending machine should support multiple products with different prices and quantities. 1. The machine should accept coins and notes of different denominations. 1. The machine should dispense the selected product and return change if necessary. 1. The machine should keep track of the available products and their quantities. 1. The machine should handle multiple transactions concurrently and ensure data consistency. 1. The machine should provide an interface for restocking products and collecting money. 1. The machine should handle exceptional scenarios, such as insufficient funds or out-of-stock products. ## UML Class Diagram ![](../class-diagrams/vendingmachine-class-diagram.png) ## Implementations #### [Java Implementation](../solutions/java/src/vendingmachine/) #### [Python Implementation](../solutions/python/vendingmachine/) #### [C++ Implementation](../solutions/cpp/vendingmachine/) #### [C# Implementation](../solutions/csharp/vendingmachine/) #### [Go Implementation](../solutions/golang/vending_machine/) #### [TypeScript Implementation](../solutions/typescript/src/VendingMachine/) ## Classes, Interfaces and Enumerations 1. The **Product** class represents a product in the vending machine, with properties such as name and price. 2. The **Coin** and **Note** enums represent the different denominations of coins and notes accepted by the vending machine. 3. The **Inventory** class manages the available products and their quantities in the vending machine. It uses a concurrent hash map to ensure thread safety. 4. The **VendingMachineState** interface defines the behavior of the vending machine in different states, such as idle, ready, and dispense. 5. The **IdleState**, **ReadyState**, and **DispenseState** classes implement the VendingMachineState interface and define the specific behaviors for each state. 6. The **VendingMachine** class is the main class that represents the vending machine. It follows the Singleton pattern to ensure only one instance of the vending machine exists. 7. The VendingMachine class maintains the current state, selected product, total payment, and provides methods for state transitions and payment handling. 8. The **VendingMachineDemo** class demonstrates the usage of the vending machine by adding products to the inventory, selecting products, inserting coins and notes, dispensing products, and returning change. ================================================ FILE: solutions/cpp/airlinemanagementsystem/AirlineManagementSystem.cpp ================================================ #include "AirlineManagementSystem.hpp" #include AirlineManagementSystem::AirlineManagementSystem() : bookingIdCounter(1) {} AirlineManagementSystem::~AirlineManagementSystem() { for (auto flight : flights) delete flight; for (auto passenger : passengers) delete passenger; for (auto booking : bookings) delete booking; } void AirlineManagementSystem::addFlight(Flight* flight) { flights.push_back(flight); } void AirlineManagementSystem::addPassenger(Passenger* passenger) { passengers.push_back(passenger); } std::string AirlineManagementSystem::createBooking(Flight* flight, Passenger* passenger, int seatNumber) { if (!flight->bookSeat(seatNumber)) { return ""; } std::string bookingId = "B" + std::to_string(bookingIdCounter++); Booking* booking = new Booking(bookingId, flight, passenger, seatNumber); bookings.push_back(booking); return bookingId; } bool AirlineManagementSystem::cancelBooking(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking) return false; booking->getFlight()->cancelSeat(booking->getSeatNumber()); auto it = std::find(bookings.begin(), bookings.end(), booking); if (it != bookings.end()) { bookings.erase(it); delete booking; return true; } return false; } void AirlineManagementSystem::displayAllFlights() const { std::cout << "\nAll Flights:" << std::endl; for (const auto& flight : flights) { flight->displayFlightInfo(); std::cout << "------------------------" << std::endl; } } void AirlineManagementSystem::displayAllPassengers() const { std::cout << "\nAll Passengers:" << std::endl; for (const auto& passenger : passengers) { passenger->displayInfo(); std::cout << "------------------------" << std::endl; } } void AirlineManagementSystem::displayAllBookings() const { std::cout << "\nAll Bookings:" << std::endl; for (const auto& booking : bookings) { booking->displayBookingInfo(); std::cout << "------------------------" << std::endl; } } Flight* AirlineManagementSystem::findFlight(std::string flightNumber) const { for (auto flight : flights) { if (flight->getFlightNumber() == flightNumber) return flight; } return nullptr; } Passenger* AirlineManagementSystem::findPassenger(std::string passportNumber) const { for (auto passenger : passengers) { if (passenger->getPassportNumber() == passportNumber) return passenger; } return nullptr; } Booking* AirlineManagementSystem::findBooking(std::string bookingId) const { for (auto booking : bookings) { if (booking->getBookingId() == bookingId) return booking; } return nullptr; } ================================================ FILE: solutions/cpp/airlinemanagementsystem/AirlineManagementSystem.hpp ================================================ #ifndef AIRLINE_MANAGEMENT_SYSTEM_HPP #define AIRLINE_MANAGEMENT_SYSTEM_HPP #include #include #include "Flight.hpp" #include "Passenger.hpp" #include "Booking.hpp" class AirlineManagementSystem { private: std::vector flights; std::vector passengers; std::vector bookings; int bookingIdCounter; public: AirlineManagementSystem(); ~AirlineManagementSystem(); void addFlight(Flight* flight); void addPassenger(Passenger* passenger); std::string createBooking(Flight* flight, Passenger* passenger, int seatNumber); bool cancelBooking(std::string bookingId); void displayAllFlights() const; void displayAllPassengers() const; void displayAllBookings() const; Flight* findFlight(std::string flightNumber) const; Passenger* findPassenger(std::string passportNumber) const; Booking* findBooking(std::string bookingId) const; }; #endif ================================================ FILE: solutions/cpp/airlinemanagementsystem/AirlineManagementSystemDemo.cpp ================================================ #include "AirlineManagementSystem.hpp" #include int main() { AirlineManagementSystem ams; // Create flights Flight* flight1 = new Flight("FL001", "New York", "London", "2024-03-20 10:00", 100); Flight* flight2 = new Flight("FL002", "London", "Paris", "2024-03-21 15:30", 80); ams.addFlight(flight1); ams.addFlight(flight2); // Create passengers Passenger* passenger1 = new Passenger("John Doe", "P123456", "+1-555-0123"); Passenger* passenger2 = new Passenger("Jane Smith", "P789012", "+1-555-0124"); ams.addPassenger(passenger1); ams.addPassenger(passenger2); // Display all flights and passengers ams.displayAllFlights(); ams.displayAllPassengers(); // Create bookings std::string booking1 = ams.createBooking(flight1, passenger1, 1); std::string booking2 = ams.createBooking(flight2, passenger2, 1); if (!booking1.empty()) { std::cout << "\nBooking created successfully: " << booking1 << std::endl; } if (!booking2.empty()) { std::cout << "Booking created successfully: " << booking2 << std::endl; } // Display all bookings ams.displayAllBookings(); // Cancel a booking if (ams.cancelBooking(booking1)) { std::cout << "\nBooking " << booking1 << " cancelled successfully" << std::endl; } // Display updated bookings ams.displayAllBookings(); return 0; } ================================================ FILE: solutions/cpp/airlinemanagementsystem/Booking.cpp ================================================ #include "Booking.hpp" #include Booking::Booking(std::string bookingId, Flight* flight, Passenger* passenger, int seatNumber) : bookingId(bookingId), flight(flight), passenger(passenger), seatNumber(seatNumber) {} std::string Booking::getBookingId() const { return bookingId; } Flight* Booking::getFlight() const { return flight; } Passenger* Booking::getPassenger() const { return passenger; } int Booking::getSeatNumber() const { return seatNumber; } void Booking::displayBookingInfo() const { std::cout << "\nBooking Details:" << std::endl; std::cout << "Booking ID: " << bookingId << std::endl; std::cout << "Seat Number: " << seatNumber << std::endl; passenger->displayInfo(); flight->displayFlightInfo(); } ================================================ FILE: solutions/cpp/airlinemanagementsystem/Booking.hpp ================================================ #ifndef BOOKING_HPP #define BOOKING_HPP #include "Flight.hpp" #include "Passenger.hpp" #include class Booking { private: std::string bookingId; Flight* flight; Passenger* passenger; int seatNumber; public: Booking(std::string bookingId, Flight* flight, Passenger* passenger, int seatNumber); std::string getBookingId() const; Flight* getFlight() const; Passenger* getPassenger() const; int getSeatNumber() const; void displayBookingInfo() const; }; #endif ================================================ FILE: solutions/cpp/airlinemanagementsystem/Flight.cpp ================================================ #include "Flight.hpp" #include Flight::Flight(std::string flightNumber, std::string origin, std::string destination, std::string departureTime, int capacity) : flightNumber(flightNumber), origin(origin), destination(destination), departureTime(departureTime), capacity(capacity) { // Initialize seats for (int i = 1; i <= capacity; i++) { seats.push_back(Seat(i, false)); } } std::string Flight::getFlightNumber() const { return flightNumber; } std::string Flight::getOrigin() const { return origin; } std::string Flight::getDestination() const { return destination; } std::string Flight::getDepartureTime() const { return departureTime; } int Flight::getCapacity() const { return capacity; } std::vector& Flight::getSeats() { return seats; } void Flight::displayFlightInfo() const { std::cout << "Flight " << flightNumber << std::endl; std::cout << "From: " << origin << " To: " << destination << std::endl; std::cout << "Departure Time: " << departureTime << std::endl; std::cout << "Capacity: " << capacity << " seats" << std::endl; } bool Flight::bookSeat(int seatNumber) { if (seatNumber < 1 || seatNumber > capacity) return false; if (seats[seatNumber - 1].isBooked()) return false; seats[seatNumber - 1].book(); return true; } bool Flight::cancelSeat(int seatNumber) { if (seatNumber < 1 || seatNumber > capacity) return false; if (!seats[seatNumber - 1].isBooked()) return false; seats[seatNumber - 1].cancel(); return true; } ================================================ FILE: solutions/cpp/airlinemanagementsystem/Flight.hpp ================================================ #ifndef FLIGHT_HPP #define FLIGHT_HPP #include #include #include "Seat.hpp" class Flight { private: std::string flightNumber; std::string origin; std::string destination; std::string departureTime; int capacity; std::vector seats; public: Flight(std::string flightNumber, std::string origin, std::string destination, std::string departureTime, int capacity); std::string getFlightNumber() const; std::string getOrigin() const; std::string getDestination() const; std::string getDepartureTime() const; int getCapacity() const; std::vector& getSeats(); void displayFlightInfo() const; bool bookSeat(int seatNumber); bool cancelSeat(int seatNumber); }; #endif ================================================ FILE: solutions/cpp/airlinemanagementsystem/Passenger.cpp ================================================ #include "Passenger.hpp" #include Passenger::Passenger(std::string name, std::string passportNumber, std::string contactNumber) : name(name), passportNumber(passportNumber), contactNumber(contactNumber) {} std::string Passenger::getName() const { return name; } std::string Passenger::getPassportNumber() const { return passportNumber; } std::string Passenger::getContactNumber() const { return contactNumber; } void Passenger::displayInfo() const { std::cout << "Passenger Details:" << std::endl; std::cout << "Name: " << name << std::endl; std::cout << "Passport Number: " << passportNumber << std::endl; std::cout << "Contact Number: " << contactNumber << std::endl; } ================================================ FILE: solutions/cpp/airlinemanagementsystem/Passenger.hpp ================================================ #ifndef PASSENGER_HPP #define PASSENGER_HPP #include class Passenger { private: std::string name; std::string passportNumber; std::string contactNumber; public: Passenger(std::string name, std::string passportNumber, std::string contactNumber); std::string getName() const; std::string getPassportNumber() const; std::string getContactNumber() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/airlinemanagementsystem/README.md ================================================ # Designing an Airline Management System ## Requirements 1. The airline management system should allow users to search for flights based on source, destination, and date. 2. Users should be able to book flights, select seats, and make payments. 3. The system should manage flight schedules, aircraft assignments, and crew assignments. 4. The system should handle passenger information, including personal details and baggage information. 5. The system should support different types of users, such as passengers, airline staff, and administrators. 6. The system should be able to handle cancellations, refunds, and flight changes. 7. The system should ensure data consistency and handle concurrent access to shared resources. 8. The system should be scalable and extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Flight** class represents a flight in the airline management system, with properties such as flight number, source, destination, departure time, arrival time, and available seats. 2. The **Aircraft** class represents an aircraft, with properties like tail number, model, and total seats. 3. The **Passenger** class represents a passenger, with properties such as ID, name, email, and phone number. 4. The **Booking** class represents a booking made by a passenger for a specific flight and seat, with properties such as booking number, flight, passenger, seat, price, and booking status. 5. The **Seat** class represents a seat on a flight, with properties like seat number, seat type, and seat status. 6. The **Payment** class represents a payment made for a booking, with properties such as payment ID, payment method, amount, and payment status. 7. The **FlightSearch** class provides functionality to search for flights based on source, destination, and date. 8. The **BookingManager** class manages the creation and cancellation of bookings. It follows the Singleton pattern to ensure a single instance of the booking manager. 9. The **PaymentProcessor** class handles the processing of payments. It follows the Singleton pattern to ensure a single instance of the payment processor. 10. The **AirlineManagementSystem** class serves as the main entry point of the system, combining all the components and providing methods for flight management, booking, payment processing, and other operations. ================================================ FILE: solutions/cpp/airlinemanagementsystem/Seat.cpp ================================================ #include "Seat.hpp" Seat::Seat(int number, bool isBooked) : seatNumber(number), booked(isBooked) {} int Seat::getSeatNumber() const { return seatNumber; } bool Seat::isBooked() const { return booked; } void Seat::book() { booked = true; } void Seat::cancel() { booked = false; } ================================================ FILE: solutions/cpp/airlinemanagementsystem/Seat.hpp ================================================ #ifndef SEAT_HPP #define SEAT_HPP class Seat { private: int seatNumber; bool booked; public: Seat(int number, bool isBooked = false); int getSeatNumber() const; bool isBooked() const; void book(); void cancel(); }; #endif ================================================ FILE: solutions/cpp/atm/ATM.cpp ================================================ #include "ATM.hpp" #include #include ATM::ATM() : currentAccount(nullptr), isAuthenticated(false) {} ATM::~ATM() { for (auto account : accounts) { delete account; } } void ATM::addAccount(Account* account) { accounts.push_back(account); } bool ATM::authenticate(const std::string& accountNumber, const std::string& pin) { for (auto account : accounts) { if (account->getAccountNumber() == accountNumber && account->validatePin(pin)) { currentAccount = account; isAuthenticated = true; return true; } } return false; } void ATM::logout() { currentAccount = nullptr; isAuthenticated = false; } bool ATM::deposit(double amount) { if (!isAuthenticated || !currentAccount) return false; return currentAccount->deposit(amount); } bool ATM::withdraw(double amount) { if (!isAuthenticated || !currentAccount) return false; return currentAccount->withdraw(amount); } void ATM::checkBalance() const { if (!isAuthenticated || !currentAccount) return; currentAccount->displayBalance(); } void ATM::displayMenu() const { std::cout << "\nATM Menu:" << std::endl; std::cout << "1. Check Balance" << std::endl; std::cout << "2. Deposit" << std::endl; std::cout << "3. Withdraw" << std::endl; std::cout << "4. Logout" << std::endl; std::cout << "5. Exit" << std::endl; std::cout << "Enter your choice: "; } void ATM::start() { std::string accountNumber, pin; int choice; double amount; while (true) { if (!isAuthenticated) { std::cout << "\nWelcome to ATM" << std::endl; std::cout << "Enter account number: "; std::cin >> accountNumber; std::cout << "Enter PIN: "; std::cin >> pin; if (!authenticate(accountNumber, pin)) { std::cout << "Invalid account number or PIN" << std::endl; continue; } std::cout << "Authentication successful!" << std::endl; } displayMenu(); std::cin >> choice; std::cin.ignore(std::numeric_limits::max(), '\n'); switch (choice) { case 1: checkBalance(); break; case 2: std::cout << "Enter amount to deposit: $"; std::cin >> amount; if (deposit(amount)) { std::cout << "Deposit successful" << std::endl; checkBalance(); } else { std::cout << "Invalid amount" << std::endl; } break; case 3: std::cout << "Enter amount to withdraw: $"; std::cin >> amount; if (withdraw(amount)) { std::cout << "Withdrawal successful" << std::endl; checkBalance(); } else { std::cout << "Invalid amount or insufficient funds" << std::endl; } break; case 4: logout(); std::cout << "Logged out successfully" << std::endl; break; case 5: std::cout << "Thank you for using ATM. Goodbye!" << std::endl; return; default: std::cout << "Invalid choice" << std::endl; } } } ================================================ FILE: solutions/cpp/atm/ATM.hpp ================================================ #ifndef ATM_HPP #define ATM_HPP #include "Account.hpp" #include #include class ATM { private: std::vector accounts; Account* currentAccount; bool isAuthenticated; public: ATM(); ~ATM(); void addAccount(Account* account); bool authenticate(const std::string& accountNumber, const std::string& pin); void logout(); bool deposit(double amount); bool withdraw(double amount); void checkBalance() const; void displayMenu() const; void start(); }; #endif ================================================ FILE: solutions/cpp/atm/ATMDemo.cpp ================================================ #include "ATM.hpp" #include int main() { ATM atm; // Create some test accounts Account* account1 = new Account("1234", "5678", 1000.0); Account* account2 = new Account("4321", "8765", 2000.0); // Add accounts to ATM atm.addAccount(account1); atm.addAccount(account2); // Start the ATM atm.start(); return 0; } ================================================ FILE: solutions/cpp/atm/Account.cpp ================================================ #include "Account.hpp" #include #include Account::Account(std::string accountNumber, std::string pin, double initialBalance) : accountNumber(accountNumber), pin(pin), balance(initialBalance) {} std::string Account::getAccountNumber() const { return accountNumber; } bool Account::validatePin(const std::string& inputPin) const { return pin == inputPin; } double Account::getBalance() const { return balance; } bool Account::deposit(double amount) { if (amount <= 0) return false; balance += amount; return true; } bool Account::withdraw(double amount) { if (amount <= 0 || amount > balance) return false; balance -= amount; return true; } void Account::displayBalance() const { std::cout << "Current balance: $" << std::fixed << std::setprecision(2) << balance << std::endl; } ================================================ FILE: solutions/cpp/atm/Account.hpp ================================================ #ifndef ACCOUNT_HPP #define ACCOUNT_HPP #include class Account { private: std::string accountNumber; std::string pin; double balance; public: Account(std::string accountNumber, std::string pin, double initialBalance = 0.0); std::string getAccountNumber() const; bool validatePin(const std::string& inputPin) const; double getBalance() const; bool deposit(double amount); bool withdraw(double amount); void displayBalance() const; }; #endif ================================================ FILE: solutions/cpp/atm/README.md ================================================ # Designing an ATM System ## Requirements 1. The ATM system should support basic operations such as balance inquiry, cash withdrawal, and cash deposit. 2. Users should be able to authenticate themselves using a card and a PIN (Personal Identification Number). 3. The system should interact with a bank's backend system to validate user accounts and perform transactions. 4. The ATM should have a cash dispenser to dispense cash to users. 5. The system should handle concurrent access and ensure data consistency. 6. The ATM should have a user-friendly interface for users to interact with. ## Classes, Interfaces and Enumerations 1. The **Card** class represents an ATM card with a card number and PIN. 2. The **Account** class represents a bank account with an account number and balance. It provides methods to debit and credit the account balance. 3. The **Transaction** class is an abstract base class for different types of transactions, such as withdrawal and deposit. It is extended by WithdrawalTransaction and DepositTransaction classes. 4. The **BankingService** class manages the bank accounts and processes transactions. It uses a thread-safe ConcurrentHashMap to store and retrieve account information. 5. The **CashDispenser** class represents the ATM's cash dispenser and handles the dispensing of cash. It uses synchronization to ensure thread safety when dispensing cash. 6. The **ATM** class serves as the main interface for ATM operations. It interacts with the BankingService and CashDispenser to perform user authentication, balance inquiry, cash withdrawal, and cash deposit. 7. The **ATMDriver** class demonstrates the usage of the ATM system by creating sample accounts and performing ATM operations. ================================================ FILE: solutions/cpp/carrentalsystem/Car.cpp ================================================ #include "Car.hpp" #include #include Car::Car(std::string carId, std::string brand, std::string model, double basePrice) : carId(carId), brand(brand), model(model), basePrice(basePrice), available(true) {} std::string Car::getCarId() const { return carId; } std::string Car::getBrand() const { return brand; } std::string Car::getModel() const { return model; } double Car::getBasePrice() const { return basePrice; } bool Car::isAvailable() const { return available; } void Car::setAvailable(bool status) { available = status; } void Car::displayInfo() const { std::cout << "Car ID: " << carId << std::endl; std::cout << "Brand: " << brand << std::endl; std::cout << "Model: " << model << std::endl; std::cout << "Base Price per Day: $" << std::fixed << std::setprecision(2) << basePrice << std::endl; std::cout << "Status: " << (available ? "Available" : "Rented") << std::endl; } ================================================ FILE: solutions/cpp/carrentalsystem/Car.hpp ================================================ #ifndef CAR_HPP #define CAR_HPP #include class Car { private: std::string carId; std::string brand; std::string model; double basePrice; bool available; public: Car(std::string carId, std::string brand, std::string model, double basePrice); std::string getCarId() const; std::string getBrand() const; std::string getModel() const; double getBasePrice() const; bool isAvailable() const; void setAvailable(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/carrentalsystem/CarRentalSystem.cpp ================================================ #include "CarRentalSystem.hpp" #include #include CarRentalSystem::CarRentalSystem() : rentalIdCounter(1) {} CarRentalSystem::~CarRentalSystem() { for (auto car : cars) delete car; for (auto customer : customers) delete customer; for (auto rental : rentals) delete rental; } void CarRentalSystem::addCar(Car* car) { cars.push_back(car); } void CarRentalSystem::addCustomer(Customer* customer) { customers.push_back(customer); } std::string CarRentalSystem::rentCar(Car* car, Customer* customer, std::string startDate, int days) { if (!car->isAvailable()) return ""; std::string rentalId = "R" + std::to_string(rentalIdCounter++); Rental* rental = new Rental(rentalId, car, customer, startDate, days); rentals.push_back(rental); car->setAvailable(false); return rentalId; } bool CarRentalSystem::returnCar(std::string rentalId) { Rental* rental = findRental(rentalId); if (!rental) return false; rental->getCar()->setAvailable(true); auto it = std::find(rentals.begin(), rentals.end(), rental); if (it != rentals.end()) { rentals.erase(it); delete rental; return true; } return false; } void CarRentalSystem::displayAvailableCars() const { std::cout << "\nAvailable Cars:" << std::endl; for (const auto& car : cars) { if (car->isAvailable()) { car->displayInfo(); std::cout << "------------------------" << std::endl; } } } void CarRentalSystem::displayRentals() const { std::cout << "\nCurrent Rentals:" << std::endl; for (const auto& rental : rentals) { rental->displayInfo(); std::cout << "------------------------" << std::endl; } } void CarRentalSystem::displayCustomers() const { std::cout << "\nRegistered Customers:" << std::endl; for (const auto& customer : customers) { customer->displayInfo(); std::cout << "------------------------" << std::endl; } } Car* CarRentalSystem::findCar(std::string carId) const { for (auto car : cars) { if (car->getCarId() == carId) return car; } return nullptr; } Customer* CarRentalSystem::findCustomer(std::string customerId) const { for (auto customer : customers) { if (customer->getCustomerId() == customerId) return customer; } return nullptr; } Rental* CarRentalSystem::findRental(std::string rentalId) const { for (auto rental : rentals) { if (rental->getRentalId() == rentalId) return rental; } return nullptr; } ================================================ FILE: solutions/cpp/carrentalsystem/CarRentalSystem.hpp ================================================ #ifndef CAR_RENTAL_SYSTEM_HPP #define CAR_RENTAL_SYSTEM_HPP #include #include #include "Car.hpp" #include "Customer.hpp" #include "Rental.hpp" class CarRentalSystem { private: std::vector cars; std::vector customers; std::vector rentals; int rentalIdCounter; public: CarRentalSystem(); ~CarRentalSystem(); void addCar(Car* car); void addCustomer(Customer* customer); std::string rentCar(Car* car, Customer* customer, std::string startDate, int days); bool returnCar(std::string rentalId); void displayAvailableCars() const; void displayRentals() const; void displayCustomers() const; Car* findCar(std::string carId) const; Customer* findCustomer(std::string customerId) const; Rental* findRental(std::string rentalId) const; }; #endif ================================================ FILE: solutions/cpp/carrentalsystem/CarRentalSystemDemo.cpp ================================================ #include "CarRentalSystem.hpp" #include int main() { CarRentalSystem rentalSystem; // Add some cars Car* car1 = new Car("C001", "Toyota", "Camry", 60.0); Car* car2 = new Car("C002", "Honda", "Accord", 70.0); Car* car3 = new Car("C003", "BMW", "3 Series", 100.0); rentalSystem.addCar(car1); rentalSystem.addCar(car2); rentalSystem.addCar(car3); // Add some customers Customer* customer1 = new Customer("CUST001", "John Doe", "+1-555-0123"); Customer* customer2 = new Customer("CUST002", "Jane Smith", "+1-555-0124"); rentalSystem.addCustomer(customer1); rentalSystem.addCustomer(customer2); // Display available cars rentalSystem.displayAvailableCars(); // Rent some cars std::string rental1 = rentalSystem.rentCar(car1, customer1, "2024-03-20", 3); std::string rental2 = rentalSystem.rentCar(car2, customer2, "2024-03-21", 5); if (!rental1.empty()) { std::cout << "\nRental created successfully: " << rental1 << std::endl; } if (!rental2.empty()) { std::cout << "Rental created successfully: " << rental2 << std::endl; } // Display all rentals rentalSystem.displayRentals(); // Display available cars after rentals rentalSystem.displayAvailableCars(); // Return a car if (rentalSystem.returnCar(rental1)) { std::cout << "\nCar returned successfully for rental: " << rental1 << std::endl; } // Display available cars after return rentalSystem.displayAvailableCars(); return 0; } ================================================ FILE: solutions/cpp/carrentalsystem/Customer.cpp ================================================ #include "Customer.hpp" #include Customer::Customer(std::string customerId, std::string name, std::string contactNumber) : customerId(customerId), name(name), contactNumber(contactNumber) {} std::string Customer::getCustomerId() const { return customerId; } std::string Customer::getName() const { return name; } std::string Customer::getContactNumber() const { return contactNumber; } void Customer::displayInfo() const { std::cout << "Customer ID: " << customerId << std::endl; std::cout << "Name: " << name << std::endl; std::cout << "Contact Number: " << contactNumber << std::endl; } ================================================ FILE: solutions/cpp/carrentalsystem/Customer.hpp ================================================ #ifndef CUSTOMER_HPP #define CUSTOMER_HPP #include class Customer { private: std::string customerId; std::string name; std::string contactNumber; public: Customer(std::string customerId, std::string name, std::string contactNumber); std::string getCustomerId() const; std::string getName() const; std::string getContactNumber() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/carrentalsystem/README.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: solutions/cpp/carrentalsystem/Rental.cpp ================================================ #include "Rental.hpp" #include #include Rental::Rental(std::string rentalId, Car* car, Customer* customer, std::string startDate, int days) : rentalId(rentalId), car(car), customer(customer), startDate(startDate), days(days) { totalPrice = car->getBasePrice() * days; } std::string Rental::getRentalId() const { return rentalId; } Car* Rental::getCar() const { return car; } Customer* Rental::getCustomer() const { return customer; } std::string Rental::getStartDate() const { return startDate; } int Rental::getDays() const { return days; } double Rental::getTotalPrice() const { return totalPrice; } void Rental::displayInfo() const { std::cout << "\nRental Details:" << std::endl; std::cout << "Rental ID: " << rentalId << std::endl; std::cout << "Start Date: " << startDate << std::endl; std::cout << "Duration: " << days << " days" << std::endl; std::cout << "Total Price: $" << std::fixed << std::setprecision(2) << totalPrice << std::endl; std::cout << "\nCustomer Information:" << std::endl; customer->displayInfo(); std::cout << "\nCar Information:" << std::endl; car->displayInfo(); } ================================================ FILE: solutions/cpp/carrentalsystem/Rental.hpp ================================================ #ifndef RENTAL_HPP #define RENTAL_HPP #include "Car.hpp" #include "Customer.hpp" #include class Rental { private: std::string rentalId; Car* car; Customer* customer; std::string startDate; int days; double totalPrice; public: Rental(std::string rentalId, Car* car, Customer* customer, std::string startDate, int days); std::string getRentalId() const; Car* getCar() const; Customer* getCustomer() const; std::string getStartDate() const; int getDays() const; double getTotalPrice() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/chessgame/Board.hpp ================================================ #ifndef BOARD_HPP #define BOARD_HPP #include "Piece.hpp" #include class Board { private: Piece* squares[8][8]; std::vector capturedPieces; public: Board(); ~Board(); void initialize(); bool movePiece(Position from, Position to); Piece* getPiece(Position position) const; void displayBoard() const; private: void placePiece(Piece* piece); void setupInitialPosition(); }; #endif ================================================ FILE: solutions/cpp/chessgame/ChessDemo.cpp ================================================ #include "Game.hpp" #include int main() { Game chess; std::cout << "Welcome to Chess!" << std::endl; chess.start(); return 0; } ================================================ FILE: solutions/cpp/chessgame/Game.cpp ================================================ #include "Game.hpp" #include Game::Game() : currentTurn(Color::WHITE), gameOver(false) { board.initialize(); } void Game::start() { while (!gameOver) { displayBoard(); std::cout << (currentTurn == Color::WHITE ? "White" : "Black") << "'s turn" << std::endl; int fromX, fromY, toX, toY; std::cout << "Enter move (fromX fromY toX toY): "; std::cin >> fromX >> fromY >> toX >> toY; Position from(fromX, fromY); Position to(toX, toY); if (makeMove(from, to)) { switchTurn(); } else { std::cout << "Invalid move! Try again." << std::endl; } } } bool Game::makeMove(Position from, Position to) { Piece* piece = board.getPiece(from); if (!piece || piece->getColor() != currentTurn) return false; return board.movePiece(from, to); } void Game::switchTurn() { currentTurn = (currentTurn == Color::WHITE) ? Color::BLACK : Color::WHITE; } Color Game::getCurrentTurn() const { return currentTurn; } bool Game::isGameOver() const { return gameOver; } void Game::displayBoard() const { board.displayBoard(); } ================================================ FILE: solutions/cpp/chessgame/Game.hpp ================================================ #ifndef GAME_HPP #define GAME_HPP #include "Board.hpp" class Game { private: Board board; Color currentTurn; bool gameOver; public: Game(); void start(); bool makeMove(Position from, Position to); void switchTurn(); Color getCurrentTurn() const; bool isGameOver() const; void displayBoard() const; }; #endif ================================================ FILE: solutions/cpp/chessgame/Piece.cpp ================================================ #include "Piece.hpp" #include Piece::Piece(PieceType type, Color color, Position position) : type(type), color(color), position(position), captured(false) {} PieceType Piece::getType() const { return type; } Color Piece::getColor() const { return color; } Position Piece::getPosition() const { return position; } bool Piece::isCaptured() const { return captured; } void Piece::setPosition(Position newPosition) { position = newPosition; } void Piece::setCaptured(bool status) { captured = status; } std::string Piece::getSymbol() const { char symbol; switch (type) { case PieceType::KING: symbol = 'K'; break; case PieceType::QUEEN: symbol = 'Q'; break; case PieceType::BISHOP: symbol = 'B'; break; case PieceType::KNIGHT: symbol = 'N'; break; case PieceType::ROOK: symbol = 'R'; break; case PieceType::PAWN: symbol = 'P'; break; default: symbol = '?'; } return std::string(1, color == Color::WHITE ? symbol : tolower(symbol)); } ================================================ FILE: solutions/cpp/chessgame/Piece.hpp ================================================ #ifndef PIECE_HPP #define PIECE_HPP #include #include "Position.hpp" enum class PieceType { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN }; enum class Color { WHITE, BLACK }; class Piece { private: PieceType type; Color color; Position position; bool captured; public: Piece(PieceType type, Color color, Position position) : type(type), color(color), position(position), captured(false) {} virtual ~Piece() = default; PieceType getType() const { return type; } Color getColor() const { return color; } Position getPosition() const { return position; } bool isCaptured() const { return captured; } void setPosition(Position newPosition) { position = newPosition; } void setCaptured(bool status) { captured = status; } virtual bool isValidMove(Position newPosition, Piece* board[8][8]) const = 0; std::string getSymbol() const { char symbol; switch (type) { case PieceType::KING: symbol = 'K'; break; case PieceType::QUEEN: symbol = 'Q'; break; case PieceType::BISHOP: symbol = 'B'; break; case PieceType::KNIGHT: symbol = 'N'; break; case PieceType::ROOK: symbol = 'R'; break; case PieceType::PAWN: symbol = 'P'; break; default: symbol = '?'; } return std::string(1, color == Color::WHITE ? symbol : tolower(symbol)); } }; #endif ================================================ FILE: solutions/cpp/chessgame/Position.hpp ================================================ #ifndef POSITION_HPP #define POSITION_HPP class Position { private: int x; int y; public: Position(int x, int y); int getX() const; int getY() const; bool isValid() const; bool operator==(const Position& other) const; }; #endif ================================================ FILE: solutions/cpp/chessgame/README.md ================================================ # Designing a Chess Game ## Requirements 1. The chess game should follow the standard rules of chess. 2. The game should support two players, each controlling their own set of pieces. 3. The game board should be represented as an 8x8 grid, with alternating black and white squares. 4. Each player should have 16 pieces: 1 king, 1 queen, 2 rooks, 2 bishops, 2 knights, and 8 pawns. 5. The game should validate legal moves for each piece and prevent illegal moves. 6. The game should detect checkmate and stalemate conditions. 7. The game should handle player turns and allow players to make moves alternately. 8. The game should provide a user interface for players to interact with the game. ## Classes, Interfaces and Enumerations 1. The **Piece** class is an abstract base class representing a chess piece. It contains common attributes such as color, row, and column, and declares an abstract method canMove to be implemented by each specific piece class. 2. The **King**, **Queen**, **Rook**, **Bishop**, **Knight**, and **Pawn** classes extend the Piece class and implement their respective movement logic in the canMove method. 3. The **Board** class represents the chess board and manages the placement of pieces. It provides methods to get and set pieces on the board, check the validity of moves, and determine checkmate and stalemate conditions. 4. The **Player** class represents a player in the game and has a method to make a move on the board. 5. The Move class represents a move made by a player, containing the piece being moved and the destination coordinates. 6. The **Game** class orchestrates the overall game flow. It initializes the board, handles player turns, and determines the game result. 7. The **ChessGame** class is the entry point of the application and starts the game. ================================================ FILE: solutions/cpp/chessgame/pieces/Bishop.cpp ================================================ #include "Bishop.hpp" #include Bishop::Bishop(Color color, Position position) : Piece(PieceType::BISHOP, color, position) {} bool Bishop::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int dx = newPosition.getX() - currentPos.getX(); int dy = newPosition.getY() - currentPos.getY(); // Bishop can only move diagonally if (abs(dx) == abs(dy)) { // Check if path is clear int xStep = dx / abs(dx); int yStep = dy / abs(dy); int x = currentPos.getX() + xStep; int y = currentPos.getY() + yStep; while (x != newPosition.getX()) { if (board[x][y] != nullptr) return false; x += xStep; y += yStep; } Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return !targetPiece || targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/Bishop.hpp ================================================ #ifndef BISHOP_HPP #define BISHOP_HPP #include "../Piece.hpp" class Bishop : public Piece { public: Bishop(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/chessgame/pieces/King.cpp ================================================ #include "King.hpp" #include King::King(Color color, Position position) : Piece(PieceType::KING, color, position) {} bool King::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int dx = abs(newPosition.getX() - currentPos.getX()); int dy = abs(newPosition.getY() - currentPos.getY()); // King can move one square in any direction if (dx <= 1 && dy <= 1) { Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return !targetPiece || targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/King.hpp ================================================ #ifndef KING_HPP #define KING_HPP #include "../Piece.hpp" class King : public Piece { public: King(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/chessgame/pieces/Knight.cpp ================================================ #include "Knight.hpp" #include Knight::Knight(Color color, Position position) : Piece(PieceType::KNIGHT, color, position) {} bool Knight::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int dx = abs(newPosition.getX() - currentPos.getX()); int dy = abs(newPosition.getY() - currentPos.getY()); // Knight moves in L-shape: 2 squares in one direction and 1 square perpendicular if ((dx == 2 && dy == 1) || (dx == 1 && dy == 2)) { Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return !targetPiece || targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/Knight.hpp ================================================ #ifndef KNIGHT_HPP #define KNIGHT_HPP #include "../Piece.hpp" class Knight : public Piece { public: Knight(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/chessgame/pieces/Pawn.cpp ================================================ #include "Pawn.hpp" Pawn::Pawn(Color color, Position position) : Piece(PieceType::PAWN, color, position) {} bool Pawn::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int direction = (getColor() == Color::WHITE) ? 1 : -1; int dx = newPosition.getX() - currentPos.getX(); int dy = newPosition.getY() - currentPos.getY(); // Normal move forward if (dy == 0 && dx == direction) { return board[newPosition.getX()][newPosition.getY()] == nullptr; } // Initial two-square move if (dy == 0 && dx == 2 * direction && ((getColor() == Color::WHITE && currentPos.getX() == 1) || (getColor() == Color::BLACK && currentPos.getX() == 6))) { return board[currentPos.getX() + direction][currentPos.getY()] == nullptr && board[newPosition.getX()][newPosition.getY()] == nullptr; } // Capture diagonally if (abs(dy) == 1 && dx == direction) { Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return targetPiece && targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/Pawn.hpp ================================================ #ifndef PAWN_HPP #define PAWN_HPP #include "../Piece.hpp" class Pawn : public Piece { public: Pawn(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/chessgame/pieces/Queen.cpp ================================================ #include "Queen.hpp" #include Queen::Queen(Color color, Position position) : Piece(PieceType::QUEEN, color, position) {} bool Queen::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int dx = newPosition.getX() - currentPos.getX(); int dy = newPosition.getY() - currentPos.getY(); // Queen can move diagonally, horizontally, or vertically if (abs(dx) == abs(dy) || dx == 0 || dy == 0) { // Check if path is clear int xStep = (dx == 0) ? 0 : dx / abs(dx); int yStep = (dy == 0) ? 0 : dy / abs(dy); int x = currentPos.getX() + xStep; int y = currentPos.getY() + yStep; while (x != newPosition.getX() || y != newPosition.getY()) { if (board[x][y] != nullptr) return false; x += xStep; y += yStep; } Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return !targetPiece || targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/Queen.hpp ================================================ #ifndef QUEEN_HPP #define QUEEN_HPP #include "../Piece.hpp" class Queen : public Piece { public: Queen(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/chessgame/pieces/Rook.cpp ================================================ #include "Rook.hpp" #include Rook::Rook(Color color, Position position) : Piece(PieceType::ROOK, color, position) {} bool Rook::isValidMove(Position newPosition, Piece* board[8][8]) const { if (!newPosition.isValid()) return false; Position currentPos = getPosition(); int dx = newPosition.getX() - currentPos.getX(); int dy = newPosition.getY() - currentPos.getY(); // Rook can only move horizontally or vertically if (dx == 0 || dy == 0) { // Check if path is clear int xStep = (dx == 0) ? 0 : dx / abs(dx); int yStep = (dy == 0) ? 0 : dy / abs(dy); int x = currentPos.getX() + xStep; int y = currentPos.getY() + yStep; while (x != newPosition.getX() || y != newPosition.getY()) { if (board[x][y] != nullptr) return false; x += xStep; y += yStep; } Piece* targetPiece = board[newPosition.getX()][newPosition.getY()]; return !targetPiece || targetPiece->getColor() != getColor(); } return false; } ================================================ FILE: solutions/cpp/chessgame/pieces/Rook.hpp ================================================ #ifndef ROOK_HPP #define ROOK_HPP #include "../Piece.hpp" class Rook : public Piece { public: Rook(Color color, Position position); bool isValidMove(Position newPosition, Piece* board[8][8]) const override; }; #endif ================================================ FILE: solutions/cpp/coffeevendingmachine/Coffee.cpp ================================================ #include "Coffee.hpp" Coffee::Coffee(CoffeeType type, double price, std::string description) : type(type), price(price), description(description) {} CoffeeType Coffee::getType() const { return type; } double Coffee::getPrice() const { return price; } std::string Coffee::getDescription() const { return description; } ================================================ FILE: solutions/cpp/coffeevendingmachine/Coffee.hpp ================================================ #ifndef COFFEE_HPP #define COFFEE_HPP #include #include "CoffeeType.hpp" class Coffee { private: CoffeeType type; double price; std::string description; public: Coffee(CoffeeType type, double price, std::string description); CoffeeType getType() const; double getPrice() const; std::string getDescription() const; }; #endif ================================================ FILE: solutions/cpp/coffeevendingmachine/CoffeeType.hpp ================================================ #ifndef COFFEE_TYPE_HPP #define COFFEE_TYPE_HPP enum class CoffeeType { ESPRESSO, LATTE, CAPPUCCINO, AMERICANO }; #endif ================================================ FILE: solutions/cpp/coffeevendingmachine/CoffeeVendingMachine.cpp ================================================ #include "CoffeeVendingMachine.hpp" #include #include CoffeeVendingMachine::CoffeeVendingMachine() : moneyCollected(0.0) { initializeMenu(); } void CoffeeVendingMachine::initializeMenu() { coffeeMenu.push_back(Coffee(CoffeeType::ESPRESSO, 2.50, "Strong black coffee")); coffeeMenu.push_back(Coffee(CoffeeType::LATTE, 3.50, "Coffee with steamed milk")); coffeeMenu.push_back(Coffee(CoffeeType::CAPPUCCINO, 3.00, "Coffee topped with foamy milk")); coffeeMenu.push_back(Coffee(CoffeeType::AMERICANO, 2.00, "Diluted espresso")); } void CoffeeVendingMachine::displayMenu() const { std::cout << "\nCoffee Menu:" << std::endl; std::cout << std::fixed << std::setprecision(2); for (const auto& coffee : coffeeMenu) { std::cout << "Type: "; switch (coffee.getType()) { case CoffeeType::ESPRESSO: std::cout << "Espresso"; break; case CoffeeType::LATTE: std::cout << "Latte"; break; case CoffeeType::CAPPUCCINO: std::cout << "Cappuccino"; break; case CoffeeType::AMERICANO: std::cout << "Americano"; break; } std::cout << " - $" << coffee.getPrice() << std::endl; std::cout << "Description: " << coffee.getDescription() << std::endl; std::cout << "Available: " << inventory.getQuantity(coffee.getType()) << std::endl; std::cout << "------------------------" << std::endl; } } bool CoffeeVendingMachine::selectCoffee(CoffeeType type, double payment) { Coffee* coffee = findCoffee(type); if (!coffee) { std::cout << "Invalid coffee selection!" << std::endl; return false; } if (!inventory.hasItem(type)) { std::cout << "Sorry, this coffee is out of stock!" << std::endl; return false; } if (payment < coffee->getPrice()) { std::cout << "Insufficient payment! Price is $" << coffee->getPrice() << std::endl; return false; } inventory.deductItem(type); moneyCollected += coffee->getPrice(); double change = payment - coffee->getPrice(); std::cout << "\nDispensing " << coffee->getDescription() << std::endl; if (change > 0) { std::cout << "Change: $" << std::fixed << std::setprecision(2) << change << std::endl; } return true; } void CoffeeVendingMachine::refillInventory(CoffeeType type, int quantity) { inventory.addItem(type, quantity); std::cout << "Inventory refilled successfully!" << std::endl; } double CoffeeVendingMachine::getMoneyCollected() const { return moneyCollected; } void CoffeeVendingMachine::displayInventory() const { inventory.display(); } Coffee* CoffeeVendingMachine::findCoffee(CoffeeType type) { for (auto& coffee : coffeeMenu) { if (coffee.getType() == type) { return &coffee; } } return nullptr; } ================================================ FILE: solutions/cpp/coffeevendingmachine/CoffeeVendingMachine.hpp ================================================ #ifndef COFFEE_VENDING_MACHINE_HPP #define COFFEE_VENDING_MACHINE_HPP #include #include "Coffee.hpp" #include "Inventory.hpp" class CoffeeVendingMachine { private: std::vector coffeeMenu; Inventory inventory; double moneyCollected; public: CoffeeVendingMachine(); void initializeMenu(); void displayMenu() const; bool selectCoffee(CoffeeType type, double payment); void refillInventory(CoffeeType type, int quantity); double getMoneyCollected() const; void displayInventory() const; private: Coffee* findCoffee(CoffeeType type); }; #endif ================================================ FILE: solutions/cpp/coffeevendingmachine/CoffeeVendingMachineDemo.cpp ================================================ #include "CoffeeVendingMachine.hpp" #include int main() { CoffeeVendingMachine machine; // Refill inventory machine.refillInventory(CoffeeType::ESPRESSO, 5); machine.refillInventory(CoffeeType::LATTE, 5); machine.refillInventory(CoffeeType::CAPPUCCINO, 5); machine.refillInventory(CoffeeType::AMERICANO, 5); // Display menu and inventory machine.displayMenu(); machine.displayInventory(); // Make some purchases std::cout << "\nMaking purchases:" << std::endl; if (machine.selectCoffee(CoffeeType::ESPRESSO, 3.00)) { std::cout << "Espresso purchased successfully!" << std::endl; } if (machine.selectCoffee(CoffeeType::LATTE, 3.50)) { std::cout << "Latte purchased successfully!" << std::endl; } // Try insufficient payment if (!machine.selectCoffee(CoffeeType::CAPPUCCINO, 2.00)) { std::cout << "Cappuccino purchase failed - insufficient payment" << std::endl; } // Display updated inventory and money collected machine.displayInventory(); std::cout << "\nTotal money collected: $" << machine.getMoneyCollected() << std::endl; return 0; } ================================================ FILE: solutions/cpp/coffeevendingmachine/Inventory.cpp ================================================ #include "Inventory.hpp" #include Inventory::Inventory() { // Initialize inventory with zero quantity for all coffee types items[CoffeeType::ESPRESSO] = 0; items[CoffeeType::LATTE] = 0; items[CoffeeType::CAPPUCCINO] = 0; items[CoffeeType::AMERICANO] = 0; } void Inventory::addItem(CoffeeType type, int quantity) { items[type] += quantity; } bool Inventory::hasItem(CoffeeType type) { return items[type] > 0; } void Inventory::deductItem(CoffeeType type) { if (items[type] > 0) { items[type]--; } } int Inventory::getQuantity(CoffeeType type) const { auto it = items.find(type); return it != items.end() ? it->second : 0; } void Inventory::display() const { std::cout << "\nCurrent Inventory:" << std::endl; std::cout << "Espresso: " << items.at(CoffeeType::ESPRESSO) << std::endl; std::cout << "Latte: " << items.at(CoffeeType::LATTE) << std::endl; std::cout << "Cappuccino: " << items.at(CoffeeType::CAPPUCCINO) << std::endl; std::cout << "Americano: " << items.at(CoffeeType::AMERICANO) << std::endl; } ================================================ FILE: solutions/cpp/coffeevendingmachine/Inventory.hpp ================================================ #ifndef INVENTORY_HPP #define INVENTORY_HPP #include #include "CoffeeType.hpp" class Inventory { private: std::map items; public: Inventory(); void addItem(CoffeeType type, int quantity); bool hasItem(CoffeeType type); void deductItem(CoffeeType type); int getQuantity(CoffeeType type) const; void display() const; }; #endif ================================================ FILE: solutions/cpp/coffeevendingmachine/README.md ================================================ # Designing a Coffee Vending Machine ## Requirements 1. The coffee vending machine should support different types of coffee, such as espresso, cappuccino, and latte. 2. Each type of coffee should have a specific price and recipe (ingredients and their quantities). 3. The machine should have a menu to display the available coffee options and their prices. 4. Users should be able to select a coffee type and make a payment. 5. The machine should dispense the selected coffee and provide change if necessary. 6. The machine should track the inventory of ingredients and notify when they are running low. 7. The machine should handle multiple user requests concurrently and ensure thread safety. ## Classes, Interfaces and Enumerations 1. The **Coffee** class represents a coffee type with its name, price, and recipe (ingredients and their quantities). 2. The **Ingredient** class represents an ingredient used in making coffee, with its name and quantity. It provides a synchronized method to update the quantity. 3. The **Payment** class represents a payment made by a user, with the amount paid. 4. The **CoffeeMachine** class is the main class that manages the coffee vending machine. It follows the Singleton pattern to ensure a single instance of the machine. 5. The **CoffeeMachine** class initializes the coffee menu and ingredients in its constructor. It provides methods to display the menu, select a coffee, dispense coffee, and update ingredient quantities. 6. The hasEnoughIngredients method checks if there are sufficient ingredients to make a selected coffee, while the updateIngredients method updates the ingredient quantities after dispensing a coffee. 7. The **CoffeeVendingMachine** class is the entry point of the application and demonstrates the usage of the coffee vending machine. It creates an instance of the machine, displays the menu, and simulates concurrent user requests using an ExecutorService. ================================================ FILE: solutions/cpp/concertticketbookingsystem/Booking.cpp ================================================ #include "Booking.hpp" #include #include Booking::Booking(std::string bookingId, std::string customerName, Concert* concert, int seatNumber, double totalPrice) : bookingId(bookingId), customerName(customerName), concert(concert), seatNumber(seatNumber), totalPrice(totalPrice) {} std::string Booking::getBookingId() const { return bookingId; } std::string Booking::getCustomerName() const { return customerName; } Concert* Booking::getConcert() const { return concert; } int Booking::getSeatNumber() const { return seatNumber; } double Booking::getTotalPrice() const { return totalPrice; } void Booking::displayInfo() const { std::cout << "\nBooking Details:" << std::endl; std::cout << "Booking ID: " << bookingId << std::endl; std::cout << "Customer Name: " << customerName << std::endl; std::cout << "Seat Number: " << seatNumber << std::endl; std::cout << "Total Price: $" << std::fixed << std::setprecision(2) << totalPrice << std::endl; std::cout << "\nConcert Information:" << std::endl; concert->displayInfo(); } ================================================ FILE: solutions/cpp/concertticketbookingsystem/Booking.hpp ================================================ #ifndef BOOKING_HPP #define BOOKING_HPP #include #include "Concert.hpp" class Booking { private: std::string bookingId; std::string customerName; Concert* concert; int seatNumber; double totalPrice; public: Booking(std::string bookingId, std::string customerName, Concert* concert, int seatNumber, double totalPrice); std::string getBookingId() const; std::string getCustomerName() const; Concert* getConcert() const; int getSeatNumber() const; double getTotalPrice() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/concertticketbookingsystem/BookingSystem.cpp ================================================ #include "BookingSystem.hpp" #include #include BookingSystem::BookingSystem() : bookingIdCounter(1) {} BookingSystem::~BookingSystem() { for (auto concert : concerts) delete concert; for (auto booking : bookings) delete booking; } void BookingSystem::addConcert(Concert* concert) { concerts.push_back(concert); } std::string BookingSystem::createBooking(std::string customerName, Concert* concert, int seatNumber) { if (!concert->bookSeat(seatNumber)) { std::cout << "Failed to book seat: Seat " << seatNumber << " is not available" << std::endl; return ""; } std::string bookingId = "B" + std::to_string(bookingIdCounter++); double totalPrice = concert->getBasePrice(); // Could add premium pricing logic here Booking* booking = new Booking(bookingId, customerName, concert, seatNumber, totalPrice); bookings.push_back(booking); return bookingId; } bool BookingSystem::cancelBooking(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking) return false; booking->getConcert()->cancelSeat(booking->getSeatNumber()); auto it = std::find(bookings.begin(), bookings.end(), booking); if (it != bookings.end()) { bookings.erase(it); delete booking; return true; } return false; } void BookingSystem::displayAllConcerts() const { std::cout << "\nAvailable Concerts:" << std::endl; for (const auto& concert : concerts) { concert->displayInfo(); std::cout << "------------------------" << std::endl; } } void BookingSystem::displayAllBookings() const { std::cout << "\nCurrent Bookings:" << std::endl; for (const auto& booking : bookings) { booking->displayInfo(); std::cout << "------------------------" << std::endl; } } void BookingSystem::displayAvailableSeats(Concert* concert) const { std::cout << "\nAvailable seats for concert " << concert->getName() << ":" << std::endl; for (int i = 1; i <= concert->getTotalSeats(); i++) { if (concert->isSeatAvailable(i)) { std::cout << i << " "; } } std::cout << std::endl; } Concert* BookingSystem::findConcert(std::string concertId) const { for (auto concert : concerts) { if (concert->getConcertId() == concertId) return concert; } return nullptr; } Booking* BookingSystem::findBooking(std::string bookingId) const { for (auto booking : bookings) { if (booking->getBookingId() == bookingId) return booking; } return nullptr; } ================================================ FILE: solutions/cpp/concertticketbookingsystem/BookingSystem.hpp ================================================ #ifndef BOOKING_SYSTEM_HPP #define BOOKING_SYSTEM_HPP #include #include #include "Concert.hpp" #include "Booking.hpp" class BookingSystem { private: std::vector concerts; std::vector bookings; int bookingIdCounter; public: BookingSystem(); ~BookingSystem(); void addConcert(Concert* concert); std::string createBooking(std::string customerName, Concert* concert, int seatNumber); bool cancelBooking(std::string bookingId); void displayAllConcerts() const; void displayAllBookings() const; void displayAvailableSeats(Concert* concert) const; Concert* findConcert(std::string concertId) const; Booking* findBooking(std::string bookingId) const; }; #endif ================================================ FILE: solutions/cpp/concertticketbookingsystem/Concert.cpp ================================================ #include "Concert.hpp" #include #include Concert::Concert(std::string concertId, std::string name, std::string venue, std::string date, double basePrice, int totalSeats) : concertId(concertId), name(name), venue(venue), date(date), basePrice(basePrice), totalSeats(totalSeats) { // Initialize seats for (int i = 1; i <= totalSeats; i++) { seats.push_back(Seat(i)); } } std::string Concert::getConcertId() const { return concertId; } std::string Concert::getName() const { return name; } std::string Concert::getVenue() const { return venue; } std::string Concert::getDate() const { return date; } double Concert::getBasePrice() const { return basePrice; } int Concert::getTotalSeats() const { return totalSeats; } int Concert::getAvailableSeats() const { int available = 0; for (const auto& seat : seats) { if (!seat.isBooked()) available++; } return available; } bool Concert::bookSeat(int seatNumber) { if (seatNumber < 1 || seatNumber > totalSeats) return false; if (seats[seatNumber - 1].isBooked()) return false; seats[seatNumber - 1].book(); return true; } bool Concert::cancelSeat(int seatNumber) { if (seatNumber < 1 || seatNumber > totalSeats) return false; if (!seats[seatNumber - 1].isBooked()) return false; seats[seatNumber - 1].cancel(); return true; } bool Concert::isSeatAvailable(int seatNumber) const { if (seatNumber < 1 || seatNumber > totalSeats) return false; return !seats[seatNumber - 1].isBooked(); } void Concert::displayInfo() const { std::cout << "Concert: " << name << std::endl; std::cout << "ID: " << concertId << std::endl; std::cout << "Venue: " << venue << std::endl; std::cout << "Date: " << date << std::endl; std::cout << "Price: $" << std::fixed << std::setprecision(2) << basePrice << std::endl; std::cout << "Available Seats: " << getAvailableSeats() << "/" << totalSeats << std::endl; } ================================================ FILE: solutions/cpp/concertticketbookingsystem/Concert.hpp ================================================ #ifndef CONCERT_HPP #define CONCERT_HPP #include #include #include "Seat.hpp" class Concert { private: std::string concertId; std::string name; std::string venue; std::string date; double basePrice; std::vector seats; int totalSeats; public: Concert(std::string concertId, std::string name, std::string venue, std::string date, double basePrice, int totalSeats); std::string getConcertId() const; std::string getName() const; std::string getVenue() const; std::string getDate() const; double getBasePrice() const; int getTotalSeats() const; int getAvailableSeats() const; bool bookSeat(int seatNumber); bool cancelSeat(int seatNumber); bool isSeatAvailable(int seatNumber) const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/concertticketbookingsystem/ConcertBookingDemo.cpp ================================================ #include "BookingSystem.hpp" #include int main() { BookingSystem bookingSystem; // Create some concerts Concert* concert1 = new Concert("C001", "Rock Festival", "Stadium A", "2024-07-15", 100.0, 50); Concert* concert2 = new Concert("C002", "Jazz Night", "Hall B", "2024-07-20", 75.0, 30); bookingSystem.addConcert(concert1); bookingSystem.addConcert(concert2); // Display all concerts bookingSystem.displayAllConcerts(); // Make some bookings std::string booking1 = bookingSystem.createBooking("John Doe", concert1, 1); std::string booking2 = bookingSystem.createBooking("Jane Smith", concert1, 2); std::string booking3 = bookingSystem.createBooking("Alice Johnson", concert2, 1); if (!booking1.empty()) { std::cout << "\nBooking created successfully: " << booking1 << std::endl; } if (!booking2.empty()) { std::cout << "Booking created successfully: " << booking2 << std::endl; } if (!booking3.empty()) { std::cout << "Booking created successfully: " << booking3 << std::endl; } // Display all bookings bookingSystem.displayAllBookings(); // Display available seats for concert1 bookingSystem.displayAvailableSeats(concert1); // Cancel a booking if (bookingSystem.cancelBooking(booking1)) { std::cout << "\nBooking " << booking1 << " cancelled successfully" << std::endl; } // Display updated available seats bookingSystem.displayAvailableSeats(concert1); return 0; } ================================================ FILE: solutions/cpp/concertticketbookingsystem/README.md ================================================ # Designing a Concert Ticket Booking System ## Requirements 1. The concert ticket booking system should allow users to view available concerts and their seating arrangements. 2. Users should be able to search for concerts based on various criteria such as artist, venue, date, and time. 3. Users should be able to select seats and purchase tickets for a specific concert. 4. The system should handle concurrent booking requests to avoid double-booking of seats. 5. The system should ensure fair booking opportunities for all users. 6. The system should handle payment processing securely. 7. The system should generate booking confirmations and send them to users via email or SMS. 8. The system should provide a waiting list functionality for sold-out concerts. ## Classes, Interfaces and Enumerations 1. The **Concert** class represents a concert event, with properties such as ID, artist, venue, date and time, and a list of seats. 2. The **Seat** class represents a seat in a concert, with properties like ID, seat number, seat type, price, and status. It provides methods to book and release a seat. 3. The **SeatType** enum represents the different types of seats available, such as regular, premium, and VIP. 4. The **SeatStatus** enum represents the status of a seat, which can be available, booked, or reserved. 5. The **Booking** class represents a booking made by a user for a specific concert and seats. It contains properties such as ID, user, concert, seats, total price, and status. It provides methods to confirm and cancel a booking. 6. The **BookingStatus** enum represents the status of a booking, which can be pending, confirmed, or cancelled. 7. The **User** class represents a user of the concert ticket booking system, with properties like ID, name, and email. 8. The **ConcertTicketBookingSystem** class is the central component of the system. It follows the Singleton pattern to ensure a single instance of the system. It manages concerts, bookings, and provides methods to add concerts, search concerts, book tickets, and cancel bookings. 9. The **SeatNotAvailableException** is a custom exception used to handle cases where a seat is not available for booking. ================================================ FILE: solutions/cpp/concertticketbookingsystem/Seat.cpp ================================================ #include "Seat.hpp" Seat::Seat(int number) : seatNumber(number), booked(false) {} int Seat::getSeatNumber() const { return seatNumber; } bool Seat::isBooked() const { return booked; } void Seat::book() { booked = true; } void Seat::cancel() { booked = false; } ================================================ FILE: solutions/cpp/concertticketbookingsystem/Seat.hpp ================================================ #ifndef SEAT_HPP #define SEAT_HPP class Seat { private: int seatNumber; bool booked; public: Seat(int number); int getSeatNumber() const; bool isBooked() const; void book(); void cancel(); }; #endif ================================================ FILE: solutions/cpp/courseregistrationsystem/Course.cpp ================================================ #include "Course.hpp" #include #include Course::Course(std::string courseId, std::string name, int maxCapacity) : courseId(courseId), name(name), maxCapacity(maxCapacity), available(true) {} std::string Course::getCourseId() const { return courseId; } std::string Course::getName() const { return name; } int Course::getMaxCapacity() const { return maxCapacity; } int Course::getCurrentEnrollment() const { return enrolledStudents.size(); } bool Course::isAvailable() const { return available; } bool Course::enrollStudent(Student* student) { if (!available || getCurrentEnrollment() >= maxCapacity) return false; if (hasStudent(student)) return false; enrolledStudents.push_back(student); return true; } bool Course::dropStudent(Student* student) { auto it = std::find(enrolledStudents.begin(), enrolledStudents.end(), student); if (it == enrolledStudents.end()) return false; enrolledStudents.erase(it); return true; } bool Course::hasStudent(Student* student) const { return std::find(enrolledStudents.begin(), enrolledStudents.end(), student) != enrolledStudents.end(); } void Course::displayInfo() const { std::cout << "Course: " << name << " (ID: " << courseId << ")" << std::endl; std::cout << "Enrollment: " << getCurrentEnrollment() << "/" << maxCapacity << std::endl; std::cout << "Status: " << (available ? "Available" : "Closed") << std::endl; } void Course::setAvailable(bool status) { available = status; } ================================================ FILE: solutions/cpp/courseregistrationsystem/Course.hpp ================================================ #ifndef COURSE_HPP #define COURSE_HPP #include #include #include "Student.hpp" class Course { private: std::string courseId; std::string name; int maxCapacity; std::vector enrolledStudents; bool available; public: Course(std::string courseId, std::string name, int maxCapacity); std::string getCourseId() const; std::string getName() const; int getMaxCapacity() const; int getCurrentEnrollment() const; bool isAvailable() const; bool enrollStudent(Student* student); bool dropStudent(Student* student); bool hasStudent(Student* student) const; void displayInfo() const; void setAvailable(bool status); }; #endif ================================================ FILE: solutions/cpp/courseregistrationsystem/README.md ================================================ # Designing a University Course Registration System ## Requirements 1. The course registration system should allow students to register for courses and view their registered courses. 2. Each course should have a course code, name, instructor, and maximum enrollment capacity. 3. Students should be able to search for courses based on course code or name. 4. The system should prevent students from registering for courses that have reached their maximum enrollment capacity. 5. The system should handle concurrent registration requests from multiple students. 6. The system should ensure data consistency and prevent race conditions. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Student** class represents a student in the course registration system, with properties such as ID, name, email, and a list of registered courses. 2. The **Course** class represents a course offered in the system, with properties such as code, name, instructor, maximum capacity, and the number of enrolled students. 3. The **Registration** class represents a registration record, associating a student with a course and capturing the registration timestamp. 4. The **CourseRegistrationSystem** class is the main class that manages the course registration system. It follows the Singleton pattern to ensure only one instance of the system exists. 5. The CourseRegistrationSystem class provides methods for adding courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. 6. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as courses and registrations. 7. The registerCourse method is synchronized to ensure thread safety when multiple students are registering for courses simultaneously. 8. The notifyObservers method is a placeholder for notifying observers (e.g., UI components) about updates to course enrollment. 9. The **CourseRegistrationDemo** class demonstrates the usage of the course registration system by creating courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. ================================================ FILE: solutions/cpp/courseregistrationsystem/RegistrationSystem.cpp ================================================ #include "RegistrationSystem.hpp" #include RegistrationSystem::RegistrationSystem() {} RegistrationSystem::~RegistrationSystem() { for (auto course : courses) delete course; for (auto student : students) delete student; } void RegistrationSystem::addCourse(Course* course) { courses.push_back(course); } void RegistrationSystem::addStudent(Student* student) { students.push_back(student); } bool RegistrationSystem::enrollStudentInCourse(Student* student, Course* course) { if (!student || !course) return false; return student->enrollInCourse(course); } bool RegistrationSystem::dropStudentFromCourse(Student* student, Course* course) { if (!student || !course) return false; return student->dropCourse(course); } void RegistrationSystem::displayAllCourses() const { std::cout << "\nAll Courses:" << std::endl; for (const auto& course : courses) { course->displayInfo(); std::cout << "------------------------" << std::endl; } } void RegistrationSystem::displayAllStudents() const { std::cout << "\nAll Students:" << std::endl; for (const auto& student : students) { student->displayInfo(); std::cout << "------------------------" << std::endl; } } void RegistrationSystem::displayCourseEnrollments(Course* course) const { if (!course) return; std::cout << "\nEnrollments for " << course->getName() << ":" << std::endl; for (const auto& student : students) { if (student->isEnrolledIn(course)) { std::cout << "- " << student->getName() << " (ID: " << student->getStudentId() << ")" << std::endl; } } } void RegistrationSystem::displayStudentEnrollments(Student* student) const { if (!student) return; student->displayInfo(); } Course* RegistrationSystem::findCourse(std::string courseId) const { for (auto course : courses) { if (course->getCourseId() == courseId) return course; } return nullptr; } Student* RegistrationSystem::findStudent(std::string studentId) const { for (auto student : students) { if (student->getStudentId() == studentId) return student; } return nullptr; } ================================================ FILE: solutions/cpp/courseregistrationsystem/RegistrationSystem.hpp ================================================ #ifndef REGISTRATION_SYSTEM_HPP #define REGISTRATION_SYSTEM_HPP #include #include #include "Course.hpp" #include "Student.hpp" class RegistrationSystem { private: std::vector courses; std::vector students; public: RegistrationSystem(); ~RegistrationSystem(); void addCourse(Course* course); void addStudent(Student* student); bool enrollStudentInCourse(Student* student, Course* course); bool dropStudentFromCourse(Student* student, Course* course); void displayAllCourses() const; void displayAllStudents() const; void displayCourseEnrollments(Course* course) const; void displayStudentEnrollments(Student* student) const; Course* findCourse(std::string courseId) const; Student* findStudent(std::string studentId) const; }; #endif ================================================ FILE: solutions/cpp/courseregistrationsystem/RegistrationSystemDemo.cpp ================================================ #include "RegistrationSystem.hpp" #include int main() { RegistrationSystem system; // Create courses Course* course1 = new Course("CS101", "Introduction to Programming", 3); Course* course2 = new Course("CS102", "Data Structures", 2); Course* course3 = new Course("CS103", "Algorithms", 2); system.addCourse(course1); system.addCourse(course2); system.addCourse(course3); // Create students Student* student1 = new Student("S001", "John Doe"); Student* student2 = new Student("S002", "Jane Smith"); Student* student3 = new Student("S003", "Bob Johnson"); system.addStudent(student1); system.addStudent(student2); system.addStudent(student3); // Display initial state system.displayAllCourses(); system.displayAllStudents(); // Enroll students in courses if (system.enrollStudentInCourse(student1, course1)) { std::cout << "Enrolled " << student1->getName() << " in " << course1->getName() << std::endl; } if (system.enrollStudentInCourse(student2, course1)) { std::cout << "Enrolled " << student2->getName() << " in " << course1->getName() << std::endl; } if (system.enrollStudentInCourse(student1, course2)) { std::cout << "Enrolled " << student1->getName() << " in " << course2->getName() << std::endl; } // Display enrollments system.displayCourseEnrollments(course1); system.displayStudentEnrollments(student1); // Drop a course if (system.dropStudentFromCourse(student1, course1)) { std::cout << "\nDropped " << student1->getName() << " from " << course1->getName() << std::endl; } // Display final state system.displayCourseEnrollments(course1); system.displayStudentEnrollments(student1); return 0; } ================================================ FILE: solutions/cpp/courseregistrationsystem/Student.cpp ================================================ #include "Student.hpp" #include "Course.hpp" #include #include Student::Student(std::string studentId, std::string name) : studentId(studentId), name(name) {} std::string Student::getStudentId() const { return studentId; } std::string Student::getName() const { return name; } const std::vector& Student::getEnrolledCourses() const { return enrolledCourses; } bool Student::enrollInCourse(Course* course) { if (isEnrolledIn(course)) return false; if (!course->enrollStudent(this)) return false; enrolledCourses.push_back(course); return true; } bool Student::dropCourse(Course* course) { auto it = std::find(enrolledCourses.begin(), enrolledCourses.end(), course); if (it == enrolledCourses.end()) return false; if (!course->dropStudent(this)) return false; enrolledCourses.erase(it); return true; } bool Student::isEnrolledIn(Course* course) const { return std::find(enrolledCourses.begin(), enrolledCourses.end(), course) != enrolledCourses.end(); } void Student::displayInfo() const { std::cout << "Student: " << name << " (ID: " << studentId << ")" << std::endl; std::cout << "Enrolled Courses:" << std::endl; for (const auto& course : enrolledCourses) { std::cout << "- " << course->getName() << " (ID: " << course->getCourseId() << ")" << std::endl; } } ================================================ FILE: solutions/cpp/courseregistrationsystem/Student.hpp ================================================ #ifndef STUDENT_HPP #define STUDENT_HPP #include #include class Course; // Forward declaration class Student { private: std::string studentId; std::string name; std::vector enrolledCourses; public: Student(std::string studentId, std::string name); std::string getStudentId() const; std::string getName() const; const std::vector& getEnrolledCourses() const; bool enrollInCourse(Course* course); bool dropCourse(Course* course); bool isEnrolledIn(Course* course) const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/cricinfo/CricInfoDemo.cpp ================================================ #include "CricInfoSystem.hpp" #include int main() { CricInfoSystem system; // Create teams Team* team1 = new Team("IND", "India", "India"); Team* team2 = new Team("AUS", "Australia", "Australia"); // Create players Player* player1 = new Player("VK18", "Virat Kohli", "India", PlayerType::BATSMAN); Player* player2 = new Player("RS45", "Rohit Sharma", "India", PlayerType::BATSMAN); Player* player3 = new Player("SPD23", "Steve Smith", "Australia", PlayerType::BATSMAN); Player* player4 = new Player("PCU31", "Pat Cummins", "Australia", PlayerType::BOWLER); // Add players to teams team1->addPlayer(player1); team1->addPlayer(player2); team2->addPlayer(player3); team2->addPlayer(player4); // Add teams to system system.addTeam(team1); system.addTeam(team2); // Create a match Match* match1 = new Match("M001", team1, team2, "MCG", "2024-01-01", "Test"); // Add player performances PlayerStats kohliStats; kohliStats.runsScored = 100; kohliStats.ballsFaced = 150; match1->addPlayerPerformance("VK18", kohliStats); PlayerStats cumminsStats; cumminsStats.wicketsTaken = 3; cumminsStats.ballsBowled = 120; match1->addPlayerPerformance("PCU31", cumminsStats); // Set match winner match1->setWinner(team1); team1->incrementWins(); team2->incrementLosses(); // Update player stats match1->updateTeamStats(); // Add match to system system.addMatch(match1); // Display information system.displayAllTeams(); system.displayAllMatches(); system.displayPlayerStats("VK18"); return 0; } ================================================ FILE: solutions/cpp/cricinfo/CricInfoSystem.cpp ================================================ #include "CricInfoSystem.hpp" #include CricInfoSystem::CricInfoSystem() {} CricInfoSystem::~CricInfoSystem() { for (auto team : teams) delete team; for (auto match : matches) delete match; } void CricInfoSystem::addTeam(Team* team) { teams.push_back(team); } void CricInfoSystem::addMatch(Match* match) { matches.push_back(match); } Team* CricInfoSystem::findTeam(const std::string& teamId) const { for (auto team : teams) { if (team->getTeamId() == teamId) return team; } return nullptr; } Match* CricInfoSystem::findMatch(const std::string& matchId) const { for (auto match : matches) { if (match->getMatchId() == matchId) return match; } return nullptr; } void CricInfoSystem::displayAllTeams() const { std::cout << "\nAll Teams:" << std::endl; for (const auto& team : teams) { team->displayInfo(); std::cout << "------------------------" << std::endl; } } void CricInfoSystem::displayAllMatches() const { std::cout << "\nAll Matches:" << std::endl; for (const auto& match : matches) { match->displayInfo(); std::cout << "------------------------" << std::endl; } } void CricInfoSystem::displayTeamStats(const std::string& teamId) const { Team* team = findTeam(teamId); if (team) { team->displayInfo(); team->displayPlayers(); } } void CricInfoSystem::displayPlayerStats(const std::string& playerId) const { for (const auto& team : teams) { Player* player = team->findPlayer(playerId); if (player) { player->displayInfo(); return; } } std::cout << "Player not found!" << std::endl; } ================================================ FILE: solutions/cpp/cricinfo/CricInfoSystem.hpp ================================================ #ifndef CRIC_INFO_SYSTEM_HPP #define CRIC_INFO_SYSTEM_HPP #include #include "Team.hpp" #include "Match.hpp" class CricInfoSystem { private: std::vector teams; std::vector matches; public: CricInfoSystem(); ~CricInfoSystem(); void addTeam(Team* team); void addMatch(Match* match); Team* findTeam(const std::string& teamId) const; Match* findMatch(const std::string& matchId) const; void displayAllTeams() const; void displayAllMatches() const; void displayTeamStats(const std::string& teamId) const; void displayPlayerStats(const std::string& playerId) const; }; #endif ================================================ FILE: solutions/cpp/cricinfo/Match.cpp ================================================ #include "Match.hpp" #include Match::Match(std::string matchId, Team* team1, Team* team2, std::string venue, std::string date, std::string matchType) : matchId(matchId), team1(team1), team2(team2), venue(venue), date(date), matchType(matchType), winner(nullptr) {} std::string Match::getMatchId() const { return matchId; } Team* Match::getTeam1() const { return team1; } Team* Match::getTeam2() const { return team2; } std::string Match::getVenue() const { return venue; } std::string Match::getDate() const { return date; } std::string Match::getMatchType() const { return matchType; } Team* Match::getWinner() const { return winner; } void Match::setWinner(Team* team) { winner = team; } void Match::addPlayerPerformance(const std::string& playerId, const PlayerStats& stats) { playerPerformances[playerId] = stats; } void Match::updateTeamStats() { for (const auto& performance : playerPerformances) { Player* player = team1->findPlayer(performance.first); if (!player) { player = team2->findPlayer(performance.first); } if (player) { player->updateStats(performance.second); } } } void Match::displayInfo() const { std::cout << "\nMatch Details:" << std::endl; std::cout << "ID: " << matchId << std::endl; std::cout << "Type: " << matchType << std::endl; std::cout << "Venue: " << venue << std::endl; std::cout << "Date: " << date << std::endl; std::cout << "Teams: " << team1->getName() << " vs " << team2->getName() << std::endl; if (winner) { std::cout << "Winner: " << winner->getName() << std::endl; } } ================================================ FILE: solutions/cpp/cricinfo/Match.hpp ================================================ #ifndef MATCH_HPP #define MATCH_HPP #include #include #include "Team.hpp" #include "PlayerStats.hpp" #include class Match { private: std::string matchId; Team* team1; Team* team2; std::string venue; std::string date; std::string matchType; Team* winner; std::map playerPerformances; public: Match(std::string matchId, Team* team1, Team* team2, std::string venue, std::string date, std::string matchType); std::string getMatchId() const; Team* getTeam1() const; Team* getTeam2() const; std::string getVenue() const; std::string getDate() const; std::string getMatchType() const; Team* getWinner() const; void setWinner(Team* team); void addPlayerPerformance(const std::string& playerId, const PlayerStats& stats); void updateTeamStats(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/cricinfo/Player.cpp ================================================ #include "Player.hpp" #include #include Player::Player(std::string playerId, std::string name, std::string country, PlayerType type) : playerId(playerId), name(name), country(country), type(type) {} std::string Player::getPlayerId() const { return playerId; } std::string Player::getName() const { return name; } std::string Player::getCountry() const { return country; } PlayerType Player::getType() const { return type; } PlayerStats& Player::getStats() { return stats; } void Player::updateStats(const PlayerStats& matchStats) { stats.runsScored += matchStats.runsScored; stats.ballsFaced += matchStats.ballsFaced; stats.wicketsTaken += matchStats.wicketsTaken; stats.ballsBowled += matchStats.ballsBowled; stats.matchesPlayed++; } void Player::displayInfo() const { std::cout << "Player: " << name << " (ID: " << playerId << ")" << std::endl; std::cout << "Country: " << country << std::endl; std::cout << "Type: "; switch (type) { case PlayerType::BATSMAN: std::cout << "Batsman"; break; case PlayerType::BOWLER: std::cout << "Bowler"; break; case PlayerType::ALL_ROUNDER: std::cout << "All-Rounder"; break; } std::cout << std::endl; std::cout << "Stats:" << std::endl; std::cout << "Matches: " << stats.matchesPlayed << std::endl; std::cout << "Runs: " << stats.runsScored << std::endl; std::cout << "Balls Faced: " << stats.ballsFaced << std::endl; if (stats.ballsFaced > 0) { double strikeRate = (static_cast(stats.runsScored) / stats.ballsFaced) * 100; std::cout << "Strike Rate: " << std::fixed << std::setprecision(2) << strikeRate << std::endl; } std::cout << "Wickets: " << stats.wicketsTaken << std::endl; std::cout << "Balls Bowled: " << stats.ballsBowled << std::endl; } ================================================ FILE: solutions/cpp/cricinfo/Player.hpp ================================================ #ifndef PLAYER_HPP #define PLAYER_HPP #include #include "PlayerStats.hpp" enum class PlayerType { BATSMAN, BOWLER, ALL_ROUNDER }; class Player { private: std::string playerId; std::string name; std::string country; PlayerType type; PlayerStats stats; public: Player(std::string playerId, std::string name, std::string country, PlayerType type); std::string getPlayerId() const; std::string getName() const; std::string getCountry() const; PlayerType getType() const; PlayerStats& getStats(); void updateStats(const PlayerStats& matchStats); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/cricinfo/PlayerStats.hpp ================================================ #ifndef PLAYER_STATS_HPP #define PLAYER_STATS_HPP struct PlayerStats { int matchesPlayed; int runsScored; int ballsFaced; int wicketsTaken; int ballsBowled; PlayerStats() : matchesPlayed(0), runsScored(0), ballsFaced(0), wicketsTaken(0), ballsBowled(0) {} }; #endif ================================================ FILE: solutions/cpp/cricinfo/README.md ================================================ # Designing a Cricket Information System like CricInfo ## Requirements 1. The Cricinfo system should provide information about cricket matches, teams, players, and live scores. 2. Users should be able to view the schedule of upcoming matches and the results of completed matches. 3. The system should allow users to search for specific matches, teams, or players. 4. Users should be able to view detailed information about a particular match, including the scorecard, commentary, and statistics. 5. The system should support real-time updates of live scores and match information. 6. The system should handle concurrent access to match data and ensure data consistency. 7. The system should be scalable and able to handle a large volume of user requests. 8. The system should be extensible to accommodate new features and enhancements in the future. ## Classes, Interfaces and Enumerations 1. The **Match** class represents a cricket match, with properties such as ID, title, venue, start time, teams, status, and scorecard. 2. The **Team** class represents a cricket team, with properties like ID, name, and a list of players. 3. The **Player** class represents a cricket player, with properties such as ID, name, and role. 4. The **Scorecard** class represents the scorecard of a match, containing team scores and a list of innings. 5. The **Innings** class represents an innings in a match, with properties like ID, batting team, bowling team, and a list of overs. 6. The **Over** class represents an over in an innings, containing a list of balls. 7. The **Ball** class represents a ball bowled in an over, with properties such as ball number, bowler, batsman, and result. 8. The **MatchStatus** enum represents the different statuses of a match, such as scheduled, in progress, completed, or abandoned. 9. The **MatchService** class manages the matches in the system, providing methods to add, retrieve, and update match information. It follows the Singleton pattern to ensure a single instance of the service. 10. The **ScorecardService** class manages the scorecards of matches, allowing the creation, retrieval, and update of scorecards and their associated data, such as innings and scores. It also follows the Singleton pattern. 11. The **CricinfoSystem** class serves as the main entry point of the system, integrating the match and scorecard services and providing high-level methods for interacting with the system. ================================================ FILE: solutions/cpp/cricinfo/Team.cpp ================================================ #include "Team.hpp" #include #include Team::Team(std::string teamId, std::string name, std::string country) : teamId(teamId), name(name), country(country), matchesWon(0), matchesLost(0) {} std::string Team::getTeamId() const { return teamId; } std::string Team::getName() const { return name; } std::string Team::getCountry() const { return country; } int Team::getMatchesWon() const { return matchesWon; } int Team::getMatchesLost() const { return matchesLost; } void Team::addPlayer(Player* player) { if (player && player->getCountry() == country) { players.push_back(player); } } void Team::removePlayer(Player* player) { auto it = std::find(players.begin(), players.end(), player); if (it != players.end()) { players.erase(it); } } Player* Team::findPlayer(const std::string& playerId) const { for (auto player : players) { if (player->getPlayerId() == playerId) return player; } return nullptr; } void Team::incrementWins() { matchesWon++; } void Team::incrementLosses() { matchesLost++; } void Team::displayInfo() const { std::cout << "\nTeam: " << name << " (ID: " << teamId << ")" << std::endl; std::cout << "Country: " << country << std::endl; std::cout << "Matches Won: " << matchesWon << std::endl; std::cout << "Matches Lost: " << matchesLost << std::endl; } void Team::displayPlayers() const { std::cout << "\nPlayers in " << name << ":" << std::endl; for (const auto& player : players) { player->displayInfo(); std::cout << "------------------------" << std::endl; } } ================================================ FILE: solutions/cpp/cricinfo/Team.hpp ================================================ #ifndef TEAM_HPP #define TEAM_HPP #include #include #include "Player.hpp" class Team { private: std::string teamId; std::string name; std::string country; std::vector players; int matchesWon; int matchesLost; public: Team(std::string teamId, std::string name, std::string country); std::string getTeamId() const; std::string getName() const; std::string getCountry() const; int getMatchesWon() const; int getMatchesLost() const; void addPlayer(Player* player); void removePlayer(Player* player); Player* findPlayer(const std::string& playerId) const; void incrementWins(); void incrementLosses(); void displayInfo() const; void displayPlayers() const; }; #endif ================================================ FILE: solutions/cpp/digitalwalletservice/README.md ================================================ # Designing a Digital Wallet System ## Requirements 1. The digital wallet should allow users to create an account and manage their personal information. 2. Users should be able to add and remove payment methods, such as credit cards or bank accounts. 3. The digital wallet should support fund transfers between users and to external accounts. 4. The system should handle transaction history and provide a statement of transactions. 5. The digital wallet should support multiple currencies and perform currency conversions. 6. The system should ensure the security of user information and transactions. 7. The digital wallet should handle concurrent transactions and ensure data consistency. 8. The system should be scalable to handle a large number of users and transactions. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the digital wallet, with properties such as ID, name, email, password, and a list of accounts. 2. The **Account** class represents a user's account within the digital wallet, with properties like ID, user, account number, currency, balance, and a list of transactions. It provides methods to deposit and withdraw funds. 3. The **Transaction** class represents a financial transaction between two accounts, containing properties such as ID, source account, destination account, amount, currency, and timestamp. 4. The **PaymentMethod** class is an abstract base class for different payment methods, such as credit cards and bank accounts. It defines the common properties and methods for processing payments. 5. The **CreditCard** and **BankAccount** classes are concrete implementations of the PaymentMethod class, representing specific payment methods. 6. The **Currency** enum represents different currencies supported by the digital wallet. 7. The **CurrencyConverter** class provides a static method to convert amounts between different currencies based on predefined exchange rates. 8. The **DigitalWallet** class is the central component of the digital wallet system. It follows the Singleton pattern to ensure only one instance of the digital wallet exists. It provides methods to create users, accounts, add payment methods, transfer funds, and retrieve transaction history. It handles concurrent access to shared resources using synchronization. 9. The **DigitalWalletDemo** class demonstrates the usage of the digital wallet system by creating users, accounts, adding payment methods, depositing funds, transferring funds, and retrieving transaction history. ================================================ FILE: solutions/cpp/digitalwalletservice/Transaction.cpp ================================================ #include "Transaction.hpp" #include #include Transaction::Transaction(std::string transactionId, std::string walletId, TransactionType type, double amount, std::string timestamp, std::string description) : transactionId(transactionId), walletId(walletId), type(type), amount(amount), timestamp(timestamp), description(description), status(false) {} std::string Transaction::getTransactionId() const { return transactionId; } std::string Transaction::getWalletId() const { return walletId; } TransactionType Transaction::getType() const { return type; } double Transaction::getAmount() const { return amount; } std::string Transaction::getTimestamp() const { return timestamp; } std::string Transaction::getDescription() const { return description; } bool Transaction::getStatus() const { return status; } void Transaction::setStatus(bool status) { this->status = status; } void Transaction::displayInfo() const { std::cout << "Transaction ID: " << transactionId << std::endl; std::cout << "Type: "; switch (type) { case TransactionType::ADD_MONEY: std::cout << "Add Money"; break; case TransactionType::WITHDRAW: std::cout << "Withdraw"; break; case TransactionType::TRANSFER: std::cout << "Transfer"; break; } std::cout << std::endl; std::cout << "Amount: $" << std::fixed << std::setprecision(2) << amount << std::endl; std::cout << "Time: " << timestamp << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Status: " << (status ? "Success" : "Pending") << std::endl; } ================================================ FILE: solutions/cpp/digitalwalletservice/Transaction.hpp ================================================ #ifndef TRANSACTION_HPP #define TRANSACTION_HPP #include enum class TransactionType { ADD_MONEY, WITHDRAW, TRANSFER }; class Transaction { private: std::string transactionId; std::string walletId; TransactionType type; double amount; std::string timestamp; std::string description; bool status; public: Transaction(std::string transactionId, std::string walletId, TransactionType type, double amount, std::string timestamp, std::string description); std::string getTransactionId() const; std::string getWalletId() const; TransactionType getType() const; double getAmount() const; std::string getTimestamp() const; std::string getDescription() const; bool getStatus() const; void setStatus(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/digitalwalletservice/User.cpp ================================================ #include "User.hpp" #include User::User(std::string userId, std::string name, std::string email, std::string phoneNumber) : userId(userId), name(name), email(email), phoneNumber(phoneNumber) {} std::string User::getUserId() const { return userId; } std::string User::getName() const { return name; } std::string User::getEmail() const { return email; } std::string User::getPhoneNumber() const { return phoneNumber; } void User::displayInfo() const { std::cout << "User: " << name << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Phone: " << phoneNumber << std::endl; } ================================================ FILE: solutions/cpp/digitalwalletservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include class User { private: std::string userId; std::string name; std::string email; std::string phoneNumber; public: User(std::string userId, std::string name, std::string email, std::string phoneNumber); std::string getUserId() const; std::string getName() const; std::string getEmail() const; std::string getPhoneNumber() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/digitalwalletservice/Wallet.cpp ================================================ #include "Wallet.hpp" #include #include Wallet::Wallet(std::string walletId, std::string userId) : walletId(walletId), userId(userId), balance(0.0) {} Wallet::~Wallet() { for (auto transaction : transactions) { delete transaction; } } std::string Wallet::getWalletId() const { return walletId; } std::string Wallet::getUserId() const { return userId; } double Wallet::getBalance() const { return balance; } bool Wallet::addMoney(double amount, std::string source) { if (amount <= 0) return false; balance += amount; return true; } bool Wallet::withdrawMoney(double amount, std::string destination) { if (amount <= 0 || amount > balance) return false; balance -= amount; return true; } void Wallet::addTransaction(Transaction* transaction) { transactions.push_back(transaction); } void Wallet::displayInfo() const { std::cout << "Wallet ID: " << walletId << std::endl; std::cout << "User ID: " << userId << std::endl; std::cout << "Balance: $" << std::fixed << std::setprecision(2) << balance << std::endl; } void Wallet::displayTransactions() const { std::cout << "\nTransaction History:" << std::endl; for (const auto& transaction : transactions) { transaction->displayInfo(); std::cout << "------------------------" << std::endl; } } ================================================ FILE: solutions/cpp/digitalwalletservice/Wallet.hpp ================================================ #ifndef WALLET_HPP #define WALLET_HPP #include #include #include "Transaction.hpp" class Wallet { private: std::string walletId; std::string userId; double balance; std::vector transactions; public: Wallet(std::string walletId, std::string userId); ~Wallet(); std::string getWalletId() const; std::string getUserId() const; double getBalance() const; bool addMoney(double amount, std::string source); bool withdrawMoney(double amount, std::string destination); void addTransaction(Transaction* transaction); void displayInfo() const; void displayTransactions() const; }; #endif ================================================ FILE: solutions/cpp/digitalwalletservice/WalletDemo.cpp ================================================ #include "WalletSystem.hpp" #include int main() { WalletSystem system; // Create users User* user1 = new User("U001", "John Doe", "john@example.com", "+1-555-0123"); User* user2 = new User("U002", "Jane Smith", "jane@example.com", "+1-555-0124"); system.addUser(user1); system.addUser(user2); // Create wallets Wallet* wallet1 = system.createWallet("U001"); Wallet* wallet2 = system.createWallet("U002"); // Add money to wallets if (system.addMoney("WU001", 1000.0, "Bank Transfer")) { std::cout << "Added $1000 to John's wallet" << std::endl; } if (system.addMoney("WU002", 500.0, "Credit Card")) { std::cout << "Added $500 to Jane's wallet" << std::endl; } // Transfer money if (system.transferMoney("WU001", "WU002", 300.0)) { std::cout << "Transferred $300 from John to Jane" << std::endl; } // Withdraw money if (system.withdrawMoney("WU002", 200.0, "Bank Account")) { std::cout << "Jane withdrew $200" << std::endl; } // Display information system.displayAllUsers(); system.displayAllWallets(); // Display detailed user information std::cout << "\nDetailed User Information:" << std::endl; system.displayUserInfo("U001"); return 0; } ================================================ FILE: solutions/cpp/digitalwalletservice/WalletSystem.cpp ================================================ #include "WalletSystem.hpp" #include #include #include #include WalletSystem::WalletSystem() : transactionIdCounter(1) {} WalletSystem::~WalletSystem() { for (auto user : users) delete user; for (auto wallet : wallets) delete wallet; } void WalletSystem::addUser(User* user) { users.push_back(user); } Wallet* WalletSystem::createWallet(std::string userId) { if (!findUser(userId)) return nullptr; std::string walletId = "W" + userId; Wallet* wallet = new Wallet(walletId, userId); wallets.push_back(wallet); return wallet; } bool WalletSystem::addMoney(std::string walletId, double amount, std::string source) { Wallet* wallet = findWallet(walletId); if (!wallet) return false; if (wallet->addMoney(amount, source)) { Transaction* transaction = new Transaction( generateTransactionId(), walletId, TransactionType::ADD_MONEY, amount, getCurrentTimestamp(), "Added money from " + source ); transaction->setStatus(true); wallet->addTransaction(transaction); return true; } return false; } bool WalletSystem::withdrawMoney(std::string walletId, double amount, std::string destination) { Wallet* wallet = findWallet(walletId); if (!wallet) return false; if (wallet->withdrawMoney(amount, destination)) { Transaction* transaction = new Transaction( generateTransactionId(), walletId, TransactionType::WITHDRAW, amount, getCurrentTimestamp(), "Withdrawn to " + destination ); transaction->setStatus(true); wallet->addTransaction(transaction); return true; } return false; } bool WalletSystem::transferMoney(std::string fromWalletId, std::string toWalletId, double amount) { Wallet* fromWallet = findWallet(fromWalletId); Wallet* toWallet = findWallet(toWalletId); if (!fromWallet || !toWallet) return false; if (fromWallet->withdrawMoney(amount, "Transfer to " + toWalletId) && toWallet->addMoney(amount, "Transfer from " + fromWalletId)) { Transaction* transaction = new Transaction( generateTransactionId(), fromWalletId, TransactionType::TRANSFER, amount, getCurrentTimestamp(), "Transfer to wallet " + toWalletId ); transaction->setStatus(true); fromWallet->addTransaction(transaction); transaction = new Transaction( generateTransactionId(), toWalletId, TransactionType::TRANSFER, amount, getCurrentTimestamp(), "Transfer from wallet " + fromWalletId ); transaction->setStatus(true); toWallet->addTransaction(transaction); return true; } return false; } void WalletSystem::displayUserInfo(std::string userId) const { User* user = findUser(userId); if (user) { user->displayInfo(); for (const auto& wallet : wallets) { if (wallet->getUserId() == userId) { wallet->displayInfo(); wallet->displayTransactions(); } } } } void WalletSystem::displayWalletInfo(std::string walletId) const { Wallet* wallet = findWallet(walletId); if (wallet) { wallet->displayInfo(); wallet->displayTransactions(); } } void WalletSystem::displayAllUsers() const { std::cout << "\nAll Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void WalletSystem::displayAllWallets() const { std::cout << "\nAll Wallets:" << std::endl; for (const auto& wallet : wallets) { wallet->displayInfo(); std::cout << "------------------------" << std::endl; } } User* WalletSystem::findUser(const std::string& userId) const { for (auto user : users) { if (user->getUserId() == userId) return user; } return nullptr; } Wallet* WalletSystem::findWallet(const std::string& walletId) const { for (auto wallet : wallets) { if (wallet->getWalletId() == walletId) return wallet; } return nullptr; } std::string WalletSystem::generateTransactionId() { return "T" + std::to_string(transactionIdCounter++); } std::string WalletSystem::getCurrentTimestamp() const { auto now = std::time(nullptr); auto tm = *std::localtime(&now); std::ostringstream oss; oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); return oss.str(); } ================================================ FILE: solutions/cpp/digitalwalletservice/WalletSystem.hpp ================================================ #ifndef WALLET_SYSTEM_HPP #define WALLET_SYSTEM_HPP #include #include #include "User.hpp" #include "Wallet.hpp" #include "Transaction.hpp" class WalletSystem { private: std::vector users; std::vector wallets; int transactionIdCounter; public: WalletSystem(); ~WalletSystem(); void addUser(User* user); Wallet* createWallet(std::string userId); bool addMoney(std::string walletId, double amount, std::string source); bool withdrawMoney(std::string walletId, double amount, std::string destination); bool transferMoney(std::string fromWalletId, std::string toWalletId, double amount); void displayUserInfo(std::string userId) const; void displayWalletInfo(std::string walletId) const; void displayAllUsers() const; void displayAllWallets() const; private: User* findUser(const std::string& userId) const; Wallet* findWallet(const std::string& walletId) const; std::string generateTransactionId(); std::string getCurrentTimestamp() const; }; #endif ================================================ FILE: solutions/cpp/elevatorsystem/Elevator.cpp ================================================ #include "Elevator.hpp" #include Elevator::Elevator(int id, int maxFloor, int minFloor) : id(id), currentFloor(minFloor), direction(Direction::IDLE), status(Status::STOPPED), maxFloor(maxFloor), minFloor(minFloor) { floorsToVisit.resize(maxFloor + 1, false); } int Elevator::getId() const { return id; } int Elevator::getCurrentFloor() const { return currentFloor; } Direction Elevator::getDirection() const { return direction; } Status Elevator::getStatus() const { return status; } void Elevator::setDirection(Direction direction) { this->direction = direction; } void Elevator::setStatus(Status status) { this->status = status; } void Elevator::addRequest(const Request& request) { requests.push(request); floorsToVisit[request.getDestinationFloor()] = true; if (direction == Direction::IDLE) { if (request.getDestinationFloor() > currentFloor) { direction = Direction::UP; } else if (request.getDestinationFloor() < currentFloor) { direction = Direction::DOWN; } } } void Elevator::moveToNextFloor() { if (status != Status::MOVING) return; if (direction == Direction::UP && currentFloor < maxFloor) { currentFloor++; } else if (direction == Direction::DOWN && currentFloor > minFloor) { currentFloor--; } updateDirection(); } bool Elevator::hasStopRequest() const { return floorsToVisit[currentFloor]; } void Elevator::processFloor() { if (floorsToVisit[currentFloor]) { floorsToVisit[currentFloor] = false; status = Status::STOPPED; std::cout << "Elevator " << id << " stopped at floor " << currentFloor << std::endl; // Remove processed requests while (!requests.empty() && requests.front().getDestinationFloor() == currentFloor) { requests.pop(); } } } void Elevator::updateDirection() { if (direction == Direction::UP) { bool hasHigherFloorRequest = false; for (int i = currentFloor + 1; i <= maxFloor; i++) { if (floorsToVisit[i]) { hasHigherFloorRequest = true; break; } } if (!hasHigherFloorRequest) { direction = Direction::DOWN; } } else if (direction == Direction::DOWN) { bool hasLowerFloorRequest = false; for (int i = currentFloor - 1; i >= minFloor; i--) { if (floorsToVisit[i]) { hasLowerFloorRequest = true; break; } } if (!hasLowerFloorRequest) { direction = Direction::UP; } } if (!requests.empty()) { status = Status::MOVING; } else { direction = Direction::IDLE; status = Status::STOPPED; } } void Elevator::displayInfo() const { std::cout << "Elevator " << id << " - Floor: " << currentFloor; std::cout << " - Direction: "; switch (direction) { case Direction::UP: std::cout << "UP"; break; case Direction::DOWN: std::cout << "DOWN"; break; case Direction::IDLE: std::cout << "IDLE"; break; } std::cout << " - Status: "; switch (status) { case Status::MOVING: std::cout << "MOVING"; break; case Status::STOPPED: std::cout << "STOPPED"; break; case Status::MAINTENANCE: std::cout << "MAINTENANCE"; break; } std::cout << std::endl; } ================================================ FILE: solutions/cpp/elevatorsystem/Elevator.hpp ================================================ #ifndef ELEVATOR_HPP #define ELEVATOR_HPP #include #include #include #include "Request.hpp" enum class Direction { UP, DOWN, IDLE }; enum class Status { MOVING, STOPPED, MAINTENANCE }; class Elevator { private: int id; int currentFloor; Direction direction; Status status; int maxFloor; int minFloor; std::vector floorsToVisit; std::queue requests; public: Elevator(int id, int maxFloor, int minFloor = 0); int getId() const; int getCurrentFloor() const; Direction getDirection() const; Status getStatus() const; void setDirection(Direction direction); void setStatus(Status status); void addRequest(const Request& request); void moveToNextFloor(); bool hasStopRequest() const; void processFloor(); void displayInfo() const; private: void updateDirection(); }; #endif ================================================ FILE: solutions/cpp/elevatorsystem/ElevatorDemo.cpp ================================================ #include "ElevatorSystem.hpp" #include #include #include int main() { ElevatorSystem system(2, 10); // 2 elevators, 10 floors // Add some requests system.addRequest(0, Request(0, 5)); // Elevator 0: Ground floor to 5th floor system.addRequest(1, Request(2, 7)); // Elevator 1: 2nd floor to 7th floor system.addRequest(0, Request(5, 3)); // Elevator 0: 5th floor to 3rd floor // Simulate elevator movement for (int i = 0; i < 15; i++) { system.displayStatus(); system.step(); // Wait for a second before next step std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; } ================================================ FILE: solutions/cpp/elevatorsystem/ElevatorSystem.cpp ================================================ #include "ElevatorSystem.hpp" #include ElevatorSystem::ElevatorSystem(int numElevators, int maxFloor, int minFloor) : maxFloor(maxFloor), minFloor(minFloor) { for (int i = 0; i < numElevators; i++) { elevators.push_back(new Elevator(i, maxFloor, minFloor)); } } ElevatorSystem::~ElevatorSystem() { for (auto elevator : elevators) { delete elevator; } } void ElevatorSystem::addRequest(int elevatorId, const Request& request) { Elevator* elevator = findElevator(elevatorId); if (elevator) { elevator->addRequest(request); std::cout << "Added request to elevator " << elevatorId << " from floor " << request.getSourceFloor() << " to floor " << request.getDestinationFloor() << std::endl; } } void ElevatorSystem::step() { for (auto elevator : elevators) { if (elevator->getStatus() == Status::MOVING) { elevator->moveToNextFloor(); } if (elevator->hasStopRequest()) { elevator->processFloor(); } } } void ElevatorSystem::displayStatus() const { std::cout << "\nElevator System Status:" << std::endl; for (const auto& elevator : elevators) { elevator->displayInfo(); } std::cout << std::endl; } Elevator* ElevatorSystem::findElevator(int elevatorId) const { if (elevatorId >= 0 && elevatorId < elevators.size()) { return elevators[elevatorId]; } return nullptr; } ================================================ FILE: solutions/cpp/elevatorsystem/ElevatorSystem.hpp ================================================ #ifndef ELEVATOR_SYSTEM_HPP #define ELEVATOR_SYSTEM_HPP #include #include "Elevator.hpp" class ElevatorSystem { private: std::vector elevators; int maxFloor; int minFloor; public: ElevatorSystem(int numElevators, int maxFloor, int minFloor = 0); ~ElevatorSystem(); void addRequest(int elevatorId, const Request& request); void step(); void displayStatus() const; private: Elevator* findElevator(int elevatorId) const; }; #endif ================================================ FILE: solutions/cpp/elevatorsystem/README.md ================================================ # Designing an Elevator System ## Requirements 1. The elevator system should consist of multiple elevators serving multiple floors. 2. Each elevator should have a capacity limit and should not exceed it. 3. Users should be able to request an elevator from any floor and select a destination floor. 4. The elevator system should efficiently handle user requests and optimize the movement of elevators to minimize waiting time. 5. The system should prioritize requests based on the direction of travel and the proximity of the elevators to the requested floor. 6. The elevators should be able to handle multiple requests concurrently and process them in an optimal order. 7. The system should ensure thread safety and prevent race conditions when multiple threads interact with the elevators. ## Classes, Interfaces and Enumerations 1. The **Direction** enum represents the possible directions of elevator movement (UP or DOWN). 2. The **Request** class represents a user request for an elevator, containing the source floor and destination floor. 3. The **Elevator** class represents an individual elevator in the system. It has a capacity limit and maintains a list of 4. requests. The elevator processes requests concurrently and moves between floors based on the requests. 4. The **ElevatorController** class manages multiple elevators and handles user requests. It finds the optimal elevator to serve a request based on the proximity of the elevators to the requested floor. 5. The **ElevatorSystem** class is the entry point of the application and demonstrates the usage of the elevator system. ================================================ FILE: solutions/cpp/elevatorsystem/Request.cpp ================================================ #include "Request.hpp" Request::Request(int sourceFloor, int destinationFloor) : sourceFloor(sourceFloor), destinationFloor(destinationFloor) { isUp = destinationFloor > sourceFloor; } int Request::getSourceFloor() const { return sourceFloor; } int Request::getDestinationFloor() const { return destinationFloor; } bool Request::getIsUp() const { return isUp; } ================================================ FILE: solutions/cpp/elevatorsystem/Request.hpp ================================================ #ifndef REQUEST_HPP #define REQUEST_HPP class Request { private: int sourceFloor; int destinationFloor; bool isUp; public: Request(int sourceFloor, int destinationFloor); int getSourceFloor() const; int getDestinationFloor() const; bool getIsUp() const; }; #endif ================================================ FILE: solutions/cpp/fooddeliveryservice/DeliveryDemo.cpp ================================================ #include "DeliveryService.hpp" #include int main() { DeliveryService service; // Create users User* user1 = new User("U001", "John Doe", "john@example.com", "+1-555-0123", "123 Main St"); service.addUser(user1); // Create restaurants Restaurant* restaurant1 = new Restaurant("R001", "Pizza Palace", "Italian", "456 Oak Ave"); // Add menu items MenuItem* item1 = new MenuItem("I001", "Margherita Pizza", "Classic tomato and mozzarella", 12.99); MenuItem* item2 = new MenuItem("I002", "Pepperoni Pizza", "Spicy pepperoni with cheese", 14.99); restaurant1->addMenuItem(item1); restaurant1->addMenuItem(item2); service.addRestaurant(restaurant1); // Display available restaurants service.displayAllRestaurants(); // Create an order Order* order = service.createOrder("U001", "R001"); if (order) { service.addItemToOrder(order->getOrderId(), "I001", 2); // 2 Margherita pizzas service.addItemToOrder(order->getOrderId(), "I002", 1); // 1 Pepperoni pizza // Display order details service.displayOrderDetails(order->getOrderId()); // Update order status service.updateOrderStatus(order->getOrderId(), OrderStatus::PREPARING); service.updateOrderStatus(order->getOrderId(), OrderStatus::OUT_FOR_DELIVERY); service.updateOrderStatus(order->getOrderId(), OrderStatus::DELIVERED); // Display order history std::cout << "\nOrder History for John Doe:" << std::endl; service.displayOrderHistory("U001"); } return 0; } ================================================ FILE: solutions/cpp/fooddeliveryservice/DeliveryService.cpp ================================================ #include "DeliveryService.hpp" #include DeliveryService::DeliveryService() : orderIdCounter(1) {} DeliveryService::~DeliveryService() { for (auto user : users) delete user; for (auto restaurant : restaurants) delete restaurant; for (auto order : orders) delete order; } void DeliveryService::addUser(User* user) { users.push_back(user); } void DeliveryService::addRestaurant(Restaurant* restaurant) { restaurants.push_back(restaurant); } Order* DeliveryService::createOrder(std::string userId, std::string restaurantId) { User* user = findUser(userId); Restaurant* restaurant = findRestaurant(restaurantId); if (!user || !restaurant || !restaurant->getIsOpen()) return nullptr; Order* order = new Order(generateOrderId(), user, restaurant); orders.push_back(order); return order; } bool DeliveryService::addItemToOrder(std::string orderId, std::string itemId, int quantity) { Order* order = findOrder(orderId); if (!order || order->getStatus() != OrderStatus::PLACED) return false; MenuItem* item = order->getRestaurant()->findMenuItem(itemId); if (!item || !item->isAvailable()) return false; order->addItem(item, quantity); return true; } bool DeliveryService::updateOrderStatus(std::string orderId, OrderStatus status) { Order* order = findOrder(orderId); if (!order) return false; order->setStatus(status); return true; } void DeliveryService::displayAllRestaurants() const { std::cout << "\nAvailable Restaurants:" << std::endl; for (const auto& restaurant : restaurants) { restaurant->displayInfo(); std::cout << "------------------------" << std::endl; } } void DeliveryService::displayRestaurantMenu(std::string restaurantId) const { Restaurant* restaurant = findRestaurant(restaurantId); if (restaurant) { restaurant->displayInfo(); restaurant->displayMenu(); } } void DeliveryService::displayOrderHistory(std::string userId) const { for (const auto& order : orders) { if (order->getUser()->getUserId() == userId) { order->displayInfo(); std::cout << "------------------------" << std::endl; } } } void DeliveryService::displayOrderDetails(std::string orderId) const { Order* order = findOrder(orderId); if (order) { order->displayInfo(); } } User* DeliveryService::findUser(const std::string& userId) const { for (auto user : users) { if (user->getUserId() == userId) return user; } return nullptr; } Restaurant* DeliveryService::findRestaurant(const std::string& restaurantId) const { for (auto restaurant : restaurants) { if (restaurant->getRestaurantId() == restaurantId) return restaurant; } return nullptr; } Order* DeliveryService::findOrder(const std::string& orderId) const { for (auto order : orders) { if (order->getOrderId() == orderId) return order; } return nullptr; } std::string DeliveryService::generateOrderId() { return "ORD" + std::to_string(orderIdCounter++); } ================================================ FILE: solutions/cpp/fooddeliveryservice/DeliveryService.hpp ================================================ #ifndef DELIVERY_SERVICE_HPP #define DELIVERY_SERVICE_HPP #include #include #include "User.hpp" #include "Restaurant.hpp" #include "Order.hpp" class DeliveryService { private: std::vector users; std::vector restaurants; std::vector orders; int orderIdCounter; public: DeliveryService(); ~DeliveryService(); void addUser(User* user); void addRestaurant(Restaurant* restaurant); Order* createOrder(std::string userId, std::string restaurantId); bool addItemToOrder(std::string orderId, std::string itemId, int quantity); bool updateOrderStatus(std::string orderId, OrderStatus status); void displayAllRestaurants() const; void displayRestaurantMenu(std::string restaurantId) const; void displayOrderHistory(std::string userId) const; void displayOrderDetails(std::string orderId) const; private: User* findUser(const std::string& userId) const; Restaurant* findRestaurant(const std::string& restaurantId) const; Order* findOrder(const std::string& orderId) const; std::string generateOrderId(); }; #endif ================================================ FILE: solutions/cpp/fooddeliveryservice/MenuItem.cpp ================================================ #include "MenuItem.hpp" #include #include MenuItem::MenuItem(std::string itemId, std::string name, std::string description, double price) : itemId(itemId), name(name), description(description), price(price), available(true) {} std::string MenuItem::getItemId() const { return itemId; } std::string MenuItem::getName() const { return name; } std::string MenuItem::getDescription() const { return description; } double MenuItem::getPrice() const { return price; } bool MenuItem::isAvailable() const { return available; } void MenuItem::setAvailable(bool status) { available = status; } void MenuItem::displayInfo() const { std::cout << "Item: " << name << " (ID: " << itemId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Price: $" << std::fixed << std::setprecision(2) << price << std::endl; std::cout << "Status: " << (available ? "Available" : "Not Available") << std::endl; } ================================================ FILE: solutions/cpp/fooddeliveryservice/MenuItem.hpp ================================================ #ifndef MENU_ITEM_HPP #define MENU_ITEM_HPP #include class MenuItem { private: std::string itemId; std::string name; std::string description; double price; bool available; public: MenuItem(std::string itemId, std::string name, std::string description, double price); std::string getItemId() const; std::string getName() const; std::string getDescription() const; double getPrice() const; bool isAvailable() const; void setAvailable(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/fooddeliveryservice/Order.cpp ================================================ #include "Order.hpp" #include #include Order::Order(std::string orderId, User* user, Restaurant* restaurant) : orderId(orderId), user(user), restaurant(restaurant), status(OrderStatus::PLACED), totalAmount(0.0) { // Get current timestamp auto now = std::time(nullptr); timestamp = std::ctime(&now); } std::string Order::getOrderId() const { return orderId; } User* Order::getUser() const { return user; } Restaurant* Order::getRestaurant() const { return restaurant; } OrderStatus Order::getStatus() const { return status; } double Order::getTotalAmount() const { return totalAmount; } std::string Order::getTimestamp() const { return timestamp; } void Order::addItem(MenuItem* item, int quantity) { if (item && quantity > 0) { items[item] = quantity; calculateTotal(); } } void Order::setStatus(OrderStatus status) { this->status = status; } void Order::calculateTotal() { totalAmount = 0.0; for (const auto& pair : items) { totalAmount += pair.first->getPrice() * pair.second; } } void Order::displayInfo() const { std::cout << "\nOrder Details:" << std::endl; std::cout << "Order ID: " << orderId << std::endl; std::cout << "Customer: " << user->getName() << std::endl; std::cout << "Restaurant: " << restaurant->getName() << std::endl; std::cout << "Status: "; switch (status) { case OrderStatus::PLACED: std::cout << "Placed"; break; case OrderStatus::PREPARING: std::cout << "Preparing"; break; case OrderStatus::OUT_FOR_DELIVERY: std::cout << "Out for Delivery"; break; case OrderStatus::DELIVERED: std::cout << "Delivered"; break; case OrderStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; std::cout << "\nOrdered Items:" << std::endl; for (const auto& pair : items) { std::cout << pair.first->getName() << " x " << pair.second << " = $" << std::fixed << std::setprecision(2) << pair.first->getPrice() * pair.second << std::endl; } std::cout << "\nTotal Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; std::cout << "Order Time: " << timestamp; } ================================================ FILE: solutions/cpp/fooddeliveryservice/Order.hpp ================================================ #ifndef ORDER_HPP #define ORDER_HPP #include #include #include #include "User.hpp" #include "Restaurant.hpp" #include "MenuItem.hpp" enum class OrderStatus { PLACED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, CANCELLED }; class Order { private: std::string orderId; User* user; Restaurant* restaurant; std::map items; // item and quantity OrderStatus status; double totalAmount; std::string timestamp; public: Order(std::string orderId, User* user, Restaurant* restaurant); std::string getOrderId() const; User* getUser() const; Restaurant* getRestaurant() const; OrderStatus getStatus() const; double getTotalAmount() const; std::string getTimestamp() const; void addItem(MenuItem* item, int quantity); void setStatus(OrderStatus status); void calculateTotal(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/fooddeliveryservice/README.md ================================================ # Designing an Online Food Delivery Service Like Swiggy ## Requirements 1. The food delivery service should allow customers to browse restaurants, view menus, and place orders. 2. Restaurants should be able to manage their menus, prices, and availability. 3. Delivery agents should be able to accept and fulfill orders. 4. The system should handle order tracking and status updates. 5. The system should support multiple payment methods. 6. The system should handle concurrent orders and ensure data consistency. 7. The system should be scalable and handle a high volume of orders. 8. The system should provide real-time notifications to customers, restaurants, and delivery agents. ## Classes, Interfaces and Enumerations 1. The **Customer** class represents a customer who can place orders. It contains customer details such as ID, name, email, and phone number. 2. The **Restaurant** class represents a restaurant that offers menu items. It contains restaurant details such as ID, name, address, and a list of menu items. It provides methods to add and remove menu items. 3. The **MenuItem** class represents an item on a restaurant's menu. It contains details such as ID, name, description, price, and availability status. 4. The **Order** class represents an order placed by a customer. It contains order details such as ID, customer, restaurant, list of order items, status, and assigned delivery agent. It provides methods to add and remove order items, update order status, and assign a delivery agent. 5. The **OrderItem** class represents an item within an order. It contains the selected menu item and the quantity ordered. 6. The **OrderStatus** enum represents the different statuses an order can have, such as PENDING, CONFIRMED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, and CANCELLED. 7. The **DeliveryAgent** class represents a delivery agent who fulfills orders. It contains details such as ID, name, phone number, and availability status. 8. The **FoodDeliveryService** class is the main class that manages the food delivery service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register customers, restaurants, and delivery agents, retrieve available restaurants and menus, place orders, update order status, cancel orders, and assign delivery agents to orders. It also handles notifications to customers, restaurants, and delivery agents. ================================================ FILE: solutions/cpp/fooddeliveryservice/Restaurant.cpp ================================================ #include "Restaurant.hpp" #include #include Restaurant::Restaurant(std::string restaurantId, std::string name, std::string cuisine, std::string address) : restaurantId(restaurantId), name(name), cuisine(cuisine), address(address), isOpen(true) {} Restaurant::~Restaurant() { for (auto item : menu) { delete item; } } std::string Restaurant::getRestaurantId() const { return restaurantId; } std::string Restaurant::getName() const { return name; } std::string Restaurant::getCuisine() const { return cuisine; } std::string Restaurant::getAddress() const { return address; } bool Restaurant::getIsOpen() const { return isOpen; } void Restaurant::addMenuItem(MenuItem* item) { menu.push_back(item); } void Restaurant::removeMenuItem(MenuItem* item) { auto it = std::find(menu.begin(), menu.end(), item); if (it != menu.end()) { menu.erase(it); } } MenuItem* Restaurant::findMenuItem(const std::string& itemId) const { for (auto item : menu) { if (item->getItemId() == itemId) return item; } return nullptr; } void Restaurant::setOpen(bool status) { isOpen = status; } void Restaurant::displayInfo() const { std::cout << "Restaurant: " << name << " (ID: " << restaurantId << ")" << std::endl; std::cout << "Cuisine: " << cuisine << std::endl; std::cout << "Address: " << address << std::endl; std::cout << "Status: " << (isOpen ? "Open" : "Closed") << std::endl; } void Restaurant::displayMenu() const { std::cout << "\nMenu Items:" << std::endl; for (const auto& item : menu) { item->displayInfo(); std::cout << "------------------------" << std::endl; } } ================================================ FILE: solutions/cpp/fooddeliveryservice/Restaurant.hpp ================================================ #ifndef RESTAURANT_HPP #define RESTAURANT_HPP #include #include #include "MenuItem.hpp" class Restaurant { private: std::string restaurantId; std::string name; std::string cuisine; std::string address; std::vector menu; bool isOpen; public: Restaurant(std::string restaurantId, std::string name, std::string cuisine, std::string address); ~Restaurant(); std::string getRestaurantId() const; std::string getName() const; std::string getCuisine() const; std::string getAddress() const; bool getIsOpen() const; void addMenuItem(MenuItem* item); void removeMenuItem(MenuItem* item); MenuItem* findMenuItem(const std::string& itemId) const; void setOpen(bool status); void displayInfo() const; void displayMenu() const; }; #endif ================================================ FILE: solutions/cpp/fooddeliveryservice/User.cpp ================================================ #include "User.hpp" #include User::User(std::string userId, std::string name, std::string email, std::string phone, std::string address) : userId(userId), name(name), email(email), phone(phone), address(address) {} std::string User::getUserId() const { return userId; } std::string User::getName() const { return name; } std::string User::getEmail() const { return email; } std::string User::getPhone() const { return phone; } std::string User::getAddress() const { return address; } void User::displayInfo() const { std::cout << "User: " << name << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Phone: " << phone << std::endl; std::cout << "Address: " << address << std::endl; } ================================================ FILE: solutions/cpp/fooddeliveryservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include class User { private: std::string userId; std::string name; std::string email; std::string phone; std::string address; public: User(std::string userId, std::string name, std::string email, std::string phone, std::string address); std::string getUserId() const; std::string getName() const; std::string getEmail() const; std::string getPhone() const; std::string getAddress() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/hotelmanagementsystem/Booking.cpp ================================================ #include "Booking.hpp" #include #include Booking::Booking(std::string bookingId, Guest* guest, Room* room, std::string checkInDate, std::string checkOutDate, int numberOfNights) : bookingId(bookingId), guest(guest), room(room), checkInDate(checkInDate), checkOutDate(checkOutDate), numberOfNights(numberOfNights), status(BookingStatus::CONFIRMED) { calculateTotalAmount(); } std::string Booking::getBookingId() const { return bookingId; } Guest* Booking::getGuest() const { return guest; } Room* Booking::getRoom() const { return room; } std::string Booking::getCheckInDate() const { return checkInDate; } std::string Booking::getCheckOutDate() const { return checkOutDate; } int Booking::getNumberOfNights() const { return numberOfNights; } double Booking::getTotalAmount() const { return totalAmount; } BookingStatus Booking::getStatus() const { return status; } void Booking::calculateTotalAmount() { totalAmount = room->getPricePerNight() * numberOfNights; } void Booking::setStatus(BookingStatus status) { this->status = status; } void Booking::displayInfo() const { std::cout << "\nBooking Details:" << std::endl; std::cout << "Booking ID: " << bookingId << std::endl; std::cout << "Guest: " << guest->getName() << std::endl; std::cout << "Room: " << room->getRoomNumber() << std::endl; std::cout << "Check-in Date: " << checkInDate << std::endl; std::cout << "Check-out Date: " << checkOutDate << std::endl; std::cout << "Number of Nights: " << numberOfNights << std::endl; std::cout << "Total Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; std::cout << "Status: "; switch (status) { case BookingStatus::CONFIRMED: std::cout << "Confirmed"; break; case BookingStatus::CHECKED_IN: std::cout << "Checked In"; break; case BookingStatus::CHECKED_OUT: std::cout << "Checked Out"; break; case BookingStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; } ================================================ FILE: solutions/cpp/hotelmanagementsystem/Booking.hpp ================================================ #ifndef BOOKING_HPP #define BOOKING_HPP #include #include "Guest.hpp" #include "Room.hpp" enum class BookingStatus { CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED }; class Booking { private: std::string bookingId; Guest* guest; Room* room; std::string checkInDate; std::string checkOutDate; int numberOfNights; double totalAmount; BookingStatus status; public: Booking(std::string bookingId, Guest* guest, Room* room, std::string checkInDate, std::string checkOutDate, int numberOfNights); std::string getBookingId() const; Guest* getGuest() const; Room* getRoom() const; std::string getCheckInDate() const; std::string getCheckOutDate() const; int getNumberOfNights() const; double getTotalAmount() const; BookingStatus getStatus() const; void calculateTotalAmount(); void setStatus(BookingStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/hotelmanagementsystem/Guest.cpp ================================================ #include "Guest.hpp" #include Guest::Guest(std::string guestId, std::string name, std::string email, std::string phone, std::string address) : guestId(guestId), name(name), email(email), phone(phone), address(address) {} std::string Guest::getGuestId() const { return guestId; } std::string Guest::getName() const { return name; } std::string Guest::getEmail() const { return email; } std::string Guest::getPhone() const { return phone; } std::string Guest::getAddress() const { return address; } void Guest::displayInfo() const { std::cout << "Guest: " << name << " (ID: " << guestId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Phone: " << phone << std::endl; std::cout << "Address: " << address << std::endl; } ================================================ FILE: solutions/cpp/hotelmanagementsystem/Guest.hpp ================================================ #ifndef GUEST_HPP #define GUEST_HPP #include class Guest { private: std::string guestId; std::string name; std::string email; std::string phone; std::string address; public: Guest(std::string guestId, std::string name, std::string email, std::string phone, std::string address); std::string getGuestId() const; std::string getName() const; std::string getEmail() const; std::string getPhone() const; std::string getAddress() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/hotelmanagementsystem/HotelDemo.cpp ================================================ #include "HotelManager.hpp" #include int main() { HotelManager hotel; // Add rooms Room* room1 = new Room("101", RoomType::STANDARD, 100.0, 2); Room* room2 = new Room("201", RoomType::DELUXE, 150.0, 3); Room* room3 = new Room("301", RoomType::SUITE, 250.0, 4); hotel.addRoom(room1); hotel.addRoom(room2); hotel.addRoom(room3); // Add guests Guest* guest1 = new Guest("G001", "John Doe", "john@example.com", "+1-555-0123", "123 Main St"); hotel.addGuest(guest1); // Display available rooms hotel.displayAvailableRooms(); // Create a booking Booking* booking = hotel.createBooking("G001", "101", "2024-01-01", "2024-01-03", 2); if (booking) { std::cout << "\nBooking created successfully!" << std::endl; booking->displayInfo(); // Check in if (hotel.checkIn(booking->getBookingId())) { std::cout << "\nChecked in successfully!" << std::endl; } // Display available rooms after check-in hotel.displayAvailableRooms(); // Check out if (hotel.checkOut(booking->getBookingId())) { std::cout << "\nChecked out successfully!" << std::endl; } // Display booking history hotel.displayBookingHistory("G001"); } return 0; } ================================================ FILE: solutions/cpp/hotelmanagementsystem/HotelManager.cpp ================================================ #include "HotelManager.hpp" #include HotelManager::HotelManager() : bookingIdCounter(1) {} HotelManager::~HotelManager() { for (auto room : rooms) delete room; for (auto guest : guests) delete guest; for (auto booking : bookings) delete booking; } void HotelManager::addRoom(Room* room) { rooms.push_back(room); } void HotelManager::addGuest(Guest* guest) { guests.push_back(guest); } Booking* HotelManager::createBooking(std::string guestId, std::string roomNumber, std::string checkInDate, std::string checkOutDate, int numberOfNights) { Guest* guest = findGuest(guestId); Room* room = findRoom(roomNumber); if (!guest || !room || room->getStatus() != RoomStatus::AVAILABLE) { return nullptr; } Booking* booking = new Booking(generateBookingId(), guest, room, checkInDate, checkOutDate, numberOfNights); bookings.push_back(booking); return booking; } bool HotelManager::checkIn(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking || booking->getStatus() != BookingStatus::CONFIRMED) { return false; } booking->setStatus(BookingStatus::CHECKED_IN); booking->getRoom()->setStatus(RoomStatus::OCCUPIED); return true; } bool HotelManager::checkOut(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking || booking->getStatus() != BookingStatus::CHECKED_IN) { return false; } booking->setStatus(BookingStatus::CHECKED_OUT); booking->getRoom()->setStatus(RoomStatus::AVAILABLE); return true; } bool HotelManager::cancelBooking(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking || booking->getStatus() != BookingStatus::CONFIRMED) { return false; } booking->setStatus(BookingStatus::CANCELLED); booking->getRoom()->setStatus(RoomStatus::AVAILABLE); return true; } void HotelManager::displayAvailableRooms() const { std::cout << "\nAvailable Rooms:" << std::endl; for (const auto& room : rooms) { if (room->getStatus() == RoomStatus::AVAILABLE) { room->displayInfo(); std::cout << "------------------------" << std::endl; } } } void HotelManager::displayBookingHistory(std::string guestId) const { std::cout << "\nBooking History:" << std::endl; for (const auto& booking : bookings) { if (booking->getGuest()->getGuestId() == guestId) { booking->displayInfo(); std::cout << "------------------------" << std::endl; } } } void HotelManager::displayAllGuests() const { std::cout << "\nAll Guests:" << std::endl; for (const auto& guest : guests) { guest->displayInfo(); std::cout << "------------------------" << std::endl; } } void HotelManager::displayAllBookings() const { std::cout << "\nAll Bookings:" << std::endl; for (const auto& booking : bookings) { booking->displayInfo(); std::cout << "------------------------" << std::endl; } } Room* HotelManager::findRoom(const std::string& roomNumber) const { for (auto room : rooms) { if (room->getRoomNumber() == roomNumber) return room; } return nullptr; } Guest* HotelManager::findGuest(const std::string& guestId) const { for (auto guest : guests) { if (guest->getGuestId() == guestId) return guest; } return nullptr; } Booking* HotelManager::findBooking(const std::string& bookingId) const { for (auto booking : bookings) { if (booking->getBookingId() == bookingId) return booking; } return nullptr; } std::string HotelManager::generateBookingId() { return "BK" + std::to_string(bookingIdCounter++); } ================================================ FILE: solutions/cpp/hotelmanagementsystem/HotelManager.hpp ================================================ #ifndef HOTEL_MANAGER_HPP #define HOTEL_MANAGER_HPP #include #include #include "Room.hpp" #include "Guest.hpp" #include "Booking.hpp" class HotelManager { private: std::vector rooms; std::vector guests; std::vector bookings; int bookingIdCounter; public: HotelManager(); ~HotelManager(); void addRoom(Room* room); void addGuest(Guest* guest); Booking* createBooking(std::string guestId, std::string roomNumber, std::string checkInDate, std::string checkOutDate, int numberOfNights); bool checkIn(std::string bookingId); bool checkOut(std::string bookingId); bool cancelBooking(std::string bookingId); void displayAvailableRooms() const; void displayBookingHistory(std::string guestId) const; void displayAllGuests() const; void displayAllBookings() const; private: Room* findRoom(const std::string& roomNumber) const; Guest* findGuest(const std::string& guestId) const; Booking* findBooking(const std::string& bookingId) const; std::string generateBookingId(); }; #endif ================================================ FILE: solutions/cpp/hotelmanagementsystem/README.md ================================================ # Designing a Hotel Management System ## Requirements 1. The hotel management system should allow guests to book rooms, check-in, and check-out. 2. The system should manage different types of rooms, such as single, double, deluxe, and suite. 3. The system should handle room availability and reservation status. 4. The system should allow the hotel staff to manage guest information, room assignments, and billing. 5. The system should support multiple payment methods, such as cash, credit card, and online payment. 6. The system should handle concurrent bookings and ensure data consistency. 7. The system should provide reporting and analytics features for hotel management. 8. The system should be scalable and handle a large number of rooms and guests. ## Classes, Interfaces and Enumerations 1. The **Guest** class represents a guest of the hotel, with properties such as ID, name, email, and phone number. 2. The **Room** class represents a room in the hotel, with properties like ID, room type, price, and status. It provides methods to book, check-in, and check-out a room. 3. The **RoomType** enum represents the different types of rooms available in the hotel. 4. The **RoomStatus** enum represents the status of a room, which can be available, booked, or occupied. 5. The **Reservation** class represents a reservation made by a guest for a specific room and date range. It contains properties such as ID, guest, room, check-in date, check-out date, and status. It provides a method to cancel a reservation. 6. The **ReservationStatus** enum represents the status of a reservation, which can be confirmed or cancelled. 7. The **Payment** interface defines the contract for processing payments. It is implemented by concrete payment classes like CashPayment and CreditCardPayment. 8. The **HotelManagementSystem** class is the central component of the hotel management system. It follows the Singleton pattern to ensure only one instance of the system exists. It provides methods to add guests and rooms, book rooms, cancel reservations, check-in, check-out, and process payments. It also handles concurrent access to shared resources using synchronization. 9. The **HotelManagementSystemDemo** class demonstrates the usage of the hotel management system by creating guests, rooms, booking a room, checking in, checking out, and cancelling a reservation. ================================================ FILE: solutions/cpp/hotelmanagementsystem/Room.cpp ================================================ #include "Room.hpp" #include #include Room::Room(std::string roomNumber, RoomType type, double pricePerNight, int capacity) : roomNumber(roomNumber), type(type), status(RoomStatus::AVAILABLE), pricePerNight(pricePerNight), capacity(capacity) {} std::string Room::getRoomNumber() const { return roomNumber; } RoomType Room::getType() const { return type; } RoomStatus Room::getStatus() const { return status; } double Room::getPricePerNight() const { return pricePerNight; } int Room::getCapacity() const { return capacity; } void Room::setStatus(RoomStatus status) { this->status = status; } void Room::displayInfo() const { std::cout << "Room " << roomNumber << std::endl; std::cout << "Type: "; switch (type) { case RoomType::STANDARD: std::cout << "Standard"; break; case RoomType::DELUXE: std::cout << "Deluxe"; break; case RoomType::SUITE: std::cout << "Suite"; break; } std::cout << std::endl; std::cout << "Status: "; switch (status) { case RoomStatus::AVAILABLE: std::cout << "Available"; break; case RoomStatus::OCCUPIED: std::cout << "Occupied"; break; case RoomStatus::UNDER_MAINTENANCE: std::cout << "Under Maintenance"; break; } std::cout << std::endl; std::cout << "Price per night: $" << std::fixed << std::setprecision(2) << pricePerNight << std::endl; std::cout << "Capacity: " << capacity << " persons" << std::endl; } ================================================ FILE: solutions/cpp/hotelmanagementsystem/Room.hpp ================================================ #ifndef ROOM_HPP #define ROOM_HPP #include enum class RoomType { STANDARD, DELUXE, SUITE }; enum class RoomStatus { AVAILABLE, OCCUPIED, UNDER_MAINTENANCE }; class Room { private: std::string roomNumber; RoomType type; RoomStatus status; double pricePerNight; int capacity; public: Room(std::string roomNumber, RoomType type, double pricePerNight, int capacity); std::string getRoomNumber() const; RoomType getType() const; RoomStatus getStatus() const; double getPricePerNight() const; int getCapacity() const; void setStatus(RoomStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/librarymanagementsystem/Book.cpp ================================================ #include "Book.hpp" #include Book::Book(std::string bookId, std::string title, std::string author, std::string publisher, std::string isbn, int publicationYear) : bookId(bookId), title(title), author(author), publisher(publisher), isbn(isbn), status(BookStatus::AVAILABLE), publicationYear(publicationYear) {} std::string Book::getBookId() const { return bookId; } std::string Book::getTitle() const { return title; } std::string Book::getAuthor() const { return author; } std::string Book::getPublisher() const { return publisher; } std::string Book::getIsbn() const { return isbn; } BookStatus Book::getStatus() const { return status; } int Book::getPublicationYear() const { return publicationYear; } void Book::setStatus(BookStatus status) { this->status = status; } void Book::displayInfo() const { std::cout << "Book: " << title << " (ID: " << bookId << ")" << std::endl; std::cout << "Author: " << author << std::endl; std::cout << "Publisher: " << publisher << std::endl; std::cout << "ISBN: " << isbn << std::endl; std::cout << "Publication Year: " << publicationYear << std::endl; std::cout << "Status: "; switch (status) { case BookStatus::AVAILABLE: std::cout << "Available"; break; case BookStatus::BORROWED: std::cout << "Borrowed"; break; case BookStatus::RESERVED: std::cout << "Reserved"; break; case BookStatus::LOST: std::cout << "Lost"; break; } std::cout << std::endl; } ================================================ FILE: solutions/cpp/librarymanagementsystem/Book.hpp ================================================ #ifndef BOOK_HPP #define BOOK_HPP #include enum class BookStatus { AVAILABLE, BORROWED, RESERVED, LOST }; class Book { private: std::string bookId; std::string title; std::string author; std::string publisher; std::string isbn; BookStatus status; int publicationYear; public: Book(std::string bookId, std::string title, std::string author, std::string publisher, std::string isbn, int publicationYear); std::string getBookId() const; std::string getTitle() const; std::string getAuthor() const; std::string getPublisher() const; std::string getIsbn() const; BookStatus getStatus() const; int getPublicationYear() const; void setStatus(BookStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/librarymanagementsystem/LibraryDemo.cpp ================================================ #include "LibraryManager.hpp" #include int main() { LibraryManager library; // Add books Book* book1 = new Book("B001", "The Great Gatsby", "F. Scott Fitzgerald", "Scribner", "978-0743273565", 1925); Book* book2 = new Book("B002", "To Kill a Mockingbird", "Harper Lee", "HarperCollins", "978-0446310789", 1960); library.addBook(book1); library.addBook(book2); // Add members Member* member1 = new Member("M001", "John Doe", "john@example.com", "+1-555-0123"); library.addMember(member1); // Display available books library.displayAvailableBooks(); // Borrow a book if (library.borrowBook("M001", "B001", "2024-01-01", "2024-01-15")) { std::cout << "\nBook borrowed successfully!" << std::endl; } // Display member's books library.displayMemberBooks("M001"); // Return the book if (library.returnBook("M001", "B001", "2024-01-10")) { std::cout << "\nBook returned successfully!" << std::endl; } // Display transaction history library.displayTransactionHistory(); return 0; } ================================================ FILE: solutions/cpp/librarymanagementsystem/LibraryManager.cpp ================================================ #include "LibraryManager.hpp" #include LibraryManager::LibraryManager() : transactionIdCounter(1) {} LibraryManager::~LibraryManager() { for (auto book : books) delete book; for (auto member : members) delete member; for (auto transaction : transactions) delete transaction; } void LibraryManager::addBook(Book* book) { books.push_back(book); } void LibraryManager::addMember(Member* member) { members.push_back(member); } bool LibraryManager::borrowBook(std::string memberId, std::string bookId, std::string issueDate, std::string dueDate) { Member* member = findMember(memberId); Book* book = findBook(bookId); if (!member || !member->isActive() || !book || book->getStatus() != BookStatus::AVAILABLE) { return false; } Transaction* transaction = new Transaction( generateTransactionId(), book, member, TransactionType::BORROW, issueDate, dueDate ); transactions.push_back(transaction); book->setStatus(BookStatus::BORROWED); member->addBorrowedBook(book); return true; } bool LibraryManager::returnBook(std::string memberId, std::string bookId, std::string returnDate) { Member* member = findMember(memberId); Book* book = findBook(bookId); Transaction* transaction = findTransaction(bookId, memberId); if (!member || !book || !transaction || book->getStatus() != BookStatus::BORROWED) { return false; } transaction->setReturnDate(returnDate); book->setStatus(BookStatus::AVAILABLE); member->removeBorrowedBook(book); // Create return transaction Transaction* returnTrans = new Transaction( generateTransactionId(), book, member, TransactionType::RETURN, returnDate, returnDate ); transactions.push_back(returnTrans); return true; } bool LibraryManager::reserveBook(std::string memberId, std::string bookId) { Member* member = findMember(memberId); Book* book = findBook(bookId); if (!member || !member->isActive() || !book || book->getStatus() != BookStatus::AVAILABLE) { return false; } book->setStatus(BookStatus::RESERVED); Transaction* transaction = new Transaction( generateTransactionId(), book, member, TransactionType::RESERVE, "NOW", // Should use actual datetime "NOW" // Should use actual datetime ); transactions.push_back(transaction); return true; } bool LibraryManager::renewBook(std::string memberId, std::string bookId, std::string newDueDate) { Member* member = findMember(memberId); Book* book = findBook(bookId); Transaction* transaction = findTransaction(bookId, memberId); if (!member || !book || !transaction || book->getStatus() != BookStatus::BORROWED) { return false; } Transaction* renewTrans = new Transaction( generateTransactionId(), book, member, TransactionType::RENEW, transaction->getDueDate(), newDueDate ); transactions.push_back(renewTrans); return true; } void LibraryManager::displayAvailableBooks() const { std::cout << "\nAvailable Books:" << std::endl; for (const auto& book : books) { if (book->getStatus() == BookStatus::AVAILABLE) { book->displayInfo(); std::cout << "------------------------" << std::endl; } } } void LibraryManager::displayMemberBooks(std::string memberId) const { Member* member = findMember(memberId); if (!member) return; std::cout << "\nBooks borrowed by " << member->getName() << ":" << std::endl; for (const auto& book : member->getBorrowedBooks()) { book->displayInfo(); std::cout << "------------------------" << std::endl; } } void LibraryManager::displayAllMembers() const { std::cout << "\nAll Members:" << std::endl; for (const auto& member : members) { member->displayInfo(); std::cout << "------------------------" << std::endl; } } void LibraryManager::displayTransactionHistory() const { std::cout << "\nTransaction History:" << std::endl; for (const auto& transaction : transactions) { transaction->displayInfo(); std::cout << "------------------------" << std::endl; } } Book* LibraryManager::findBook(const std::string& bookId) const { for (auto book : books) { if (book->getBookId() == bookId) return book; } return nullptr; } Member* LibraryManager::findMember(const std::string& memberId) const { for (auto member : members) { if (member->getMemberId() == memberId) return member; } return nullptr; } Transaction* LibraryManager::findTransaction(const std::string& bookId, const std::string& memberId) const { for (auto transaction : transactions) { if (transaction->getBook()->getBookId() == bookId && transaction->getMember()->getMemberId() == memberId && transaction->getType() == TransactionType::BORROW) { return transaction; } } return nullptr; } std::string LibraryManager::generateTransactionId() { return "T" + std::to_string(transactionIdCounter++); } ================================================ FILE: solutions/cpp/librarymanagementsystem/LibraryManager.hpp ================================================ #ifndef LIBRARY_MANAGER_HPP #define LIBRARY_MANAGER_HPP #include #include #include "Book.hpp" #include "Member.hpp" #include "Transaction.hpp" class LibraryManager { private: std::vector books; std::vector members; std::vector transactions; int transactionIdCounter; public: LibraryManager(); ~LibraryManager(); void addBook(Book* book); void addMember(Member* member); bool borrowBook(std::string memberId, std::string bookId, std::string issueDate, std::string dueDate); bool returnBook(std::string memberId, std::string bookId, std::string returnDate); bool reserveBook(std::string memberId, std::string bookId); bool renewBook(std::string memberId, std::string bookId, std::string newDueDate); void displayAvailableBooks() const; void displayMemberBooks(std::string memberId) const; void displayAllMembers() const; void displayTransactionHistory() const; private: Book* findBook(const std::string& bookId) const; Member* findMember(const std::string& memberId) const; Transaction* findTransaction(const std::string& bookId, const std::string& memberId) const; std::string generateTransactionId(); }; #endif ================================================ FILE: solutions/cpp/librarymanagementsystem/Member.cpp ================================================ #include "Member.hpp" #include #include Member::Member(std::string memberId, std::string name, std::string email, std::string phone) : memberId(memberId), name(name), email(email), phone(phone), active(true) {} std::string Member::getMemberId() const { return memberId; } std::string Member::getName() const { return name; } std::string Member::getEmail() const { return email; } std::string Member::getPhone() const { return phone; } bool Member::isActive() const { return active; } const std::vector& Member::getBorrowedBooks() const { return borrowedBooks; } void Member::addBorrowedBook(Book* book) { borrowedBooks.push_back(book); } void Member::removeBorrowedBook(Book* book) { auto it = std::find(borrowedBooks.begin(), borrowedBooks.end(), book); if (it != borrowedBooks.end()) { borrowedBooks.erase(it); } } void Member::setActive(bool status) { active = status; } void Member::displayInfo() const { std::cout << "Member: " << name << " (ID: " << memberId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Phone: " << phone << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Borrowed Books: " << borrowedBooks.size() << std::endl; } ================================================ FILE: solutions/cpp/librarymanagementsystem/Member.hpp ================================================ #ifndef MEMBER_HPP #define MEMBER_HPP #include #include #include "Book.hpp" class Member { private: std::string memberId; std::string name; std::string email; std::string phone; std::vector borrowedBooks; bool active; public: Member(std::string memberId, std::string name, std::string email, std::string phone); std::string getMemberId() const; std::string getName() const; std::string getEmail() const; std::string getPhone() const; bool isActive() const; const std::vector& getBorrowedBooks() const; void addBorrowedBook(Book* book); void removeBorrowedBook(Book* book); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/librarymanagementsystem/README.md ================================================ # Designing a Library Management System ## Requirements 1. The library management system should allow librarians to manage books, members, and borrowing activities. 2. The system should support adding, updating, and removing books from the library catalog. 3. Each book should have details such as title, author, ISBN, publication year, and availability status. 4. The system should allow members to borrow and return books. 5. Each member should have details such as name, member ID, contact information, and borrowing history. 6. The system should enforce borrowing rules, such as a maximum number of books that can be borrowed at a time and loan duration. 7. The system should handle concurrent access to the library catalog and member records. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Book** class represents a book in the library catalog, with properties such as ISBN, title, author, publication year, and availability status. 2. The **Member** class represents a library member, with properties like member ID, name, contact information, and a list of borrowed books. 3. The **LibraryManager** class is the core of the library management system and follows the Singleton pattern to ensure a single instance of the library manager. 4. The LibraryManager class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to the library catalog and member records. 5. The LibraryManager class provides methods for adding and removing books, registering and unregistering members, borrowing and returning books, and searching for books based on keywords. 6. The **LibraryManagementSystemDemo** class serves as the entry point of the application and demonstrates the usage of the library management system. ================================================ FILE: solutions/cpp/librarymanagementsystem/Transaction.cpp ================================================ #include "Transaction.hpp" #include #include Transaction::Transaction(std::string transactionId, Book* book, Member* member, TransactionType type, std::string issueDate, std::string dueDate) : transactionId(transactionId), book(book), member(member), type(type), issueDate(issueDate), dueDate(dueDate), fine(0.0) {} std::string Transaction::getTransactionId() const { return transactionId; } Book* Transaction::getBook() const { return book; } Member* Transaction::getMember() const { return member; } TransactionType Transaction::getType() const { return type; } std::string Transaction::getIssueDate() const { return issueDate; } std::string Transaction::getDueDate() const { return dueDate; } std::string Transaction::getReturnDate() const { return returnDate; } double Transaction::getFine() const { return fine; } void Transaction::setReturnDate(std::string date) { returnDate = date; } void Transaction::setFine(double amount) { fine = amount; } void Transaction::displayInfo() const { std::cout << "\nTransaction Details:" << std::endl; std::cout << "Transaction ID: " << transactionId << std::endl; std::cout << "Book: " << book->getTitle() << std::endl; std::cout << "Member: " << member->getName() << std::endl; std::cout << "Type: "; switch (type) { case TransactionType::BORROW: std::cout << "Borrow"; break; case TransactionType::RETURN: std::cout << "Return"; break; case TransactionType::RESERVE: std::cout << "Reserve"; break; case TransactionType::RENEW: std::cout << "Renew"; break; } std::cout << std::endl; std::cout << "Issue Date: " << issueDate << std::endl; std::cout << "Due Date: " << dueDate << std::endl; if (!returnDate.empty()) { std::cout << "Return Date: " << returnDate << std::endl; } if (fine > 0) { std::cout << "Fine: $" << std::fixed << std::setprecision(2) << fine << std::endl; } } ================================================ FILE: solutions/cpp/librarymanagementsystem/Transaction.hpp ================================================ #ifndef TRANSACTION_HPP #define TRANSACTION_HPP #include #include "Book.hpp" #include "Member.hpp" enum class TransactionType { BORROW, RETURN, RESERVE, RENEW }; class Transaction { private: std::string transactionId; Book* book; Member* member; TransactionType type; std::string issueDate; std::string dueDate; std::string returnDate; double fine; public: Transaction(std::string transactionId, Book* book, Member* member, TransactionType type, std::string issueDate, std::string dueDate); std::string getTransactionId() const; Book* getBook() const; Member* getMember() const; TransactionType getType() const; std::string getIssueDate() const; std::string getDueDate() const; std::string getReturnDate() const; double getFine() const; void setReturnDate(std::string date); void setFine(double amount); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/linkedin/LinkedInDemo.cpp ================================================ #include "LinkedInManager.hpp" #include int main() { LinkedInManager linkedin; // Create users User* user1 = new User("U001", "john@example.com", "password123"); User* user2 = new User("U002", "jane@example.com", "password456"); // Create profiles Profile* profile1 = new Profile("John Doe", "Software Engineer"); Profile* profile2 = new Profile("Jane Smith", "Product Manager"); user1->setProfile(profile1); user2->setProfile(profile2); // Add skills profile1->addSkill("C++"); profile1->addSkill("Python"); profile2->addSkill("Product Management"); profile2->addSkill("Agile"); // Add experience Experience exp1{"Tech Corp", "Software Engineer", "2020", "Present", "Developing enterprise applications"}; profile1->addExperience(exp1); // Add education Education edu1{"University of Tech", "BS", "Computer Science", "2016", "2020"}; profile1->addEducation(edu1); linkedin.addUser(user1); linkedin.addUser(user2); // Create connection linkedin.addConnection("U001", "U002"); // Create posts Post* post = linkedin.createPost("U001", "Hello LinkedIn!", PostType::TEXT, "2024-01-01"); if (post) { linkedin.likePost("U002", post->getPostId()); linkedin.commentOnPost("U002", post->getPostId(), "Great to see you here!"); } // Display information std::cout << "User Profiles:" << std::endl; linkedin.displayUserProfile("U001"); linkedin.displayUserProfile("U002"); std::cout << "\nUser Connections:" << std::endl; linkedin.displayUserConnections("U001"); std::cout << "\nUser Posts:" << std::endl; linkedin.displayUserPosts("U001"); return 0; } ================================================ FILE: solutions/cpp/linkedin/LinkedInManager.cpp ================================================ #include "LinkedInManager.hpp" #include LinkedInManager::LinkedInManager() : postIdCounter(1) {} LinkedInManager::~LinkedInManager() { for (auto user : users) delete user; for (auto post : posts) delete post; } void LinkedInManager::addUser(User* user) { users.push_back(user); } Post* LinkedInManager::createPost(std::string userId, std::string content, PostType type, std::string timestamp) { User* user = findUser(userId); if (!user || !user->isActive()) return nullptr; Post* post = new Post(generatePostId(), user, content, type, timestamp); posts.push_back(post); user->addPost(post); return post; } bool LinkedInManager::addConnection(std::string userId1, std::string userId2) { User* user1 = findUser(userId1); User* user2 = findUser(userId2); if (!user1 || !user2 || !user1->isActive() || !user2->isActive()) { return false; } user1->addConnection(user2); return true; } bool LinkedInManager::removeConnection(std::string userId1, std::string userId2) { User* user1 = findUser(userId1); User* user2 = findUser(userId2); if (!user1 || !user2) return false; user1->removeConnection(user2); return true; } bool LinkedInManager::likePost(std::string userId, std::string postId) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post || !user->isActive()) return false; post->addLike(user); return true; } bool LinkedInManager::unlikePost(std::string userId, std::string postId) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post) return false; post->removeLike(user); return true; } bool LinkedInManager::commentOnPost(std::string userId, std::string postId, const std::string& comment) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post || !user->isActive()) return false; post->addComment(comment); return true; } void LinkedInManager::displayUserProfile(std::string userId) const { User* user = findUser(userId); if (user) { user->displayInfo(); } } void LinkedInManager::displayUserConnections(std::string userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nConnections for " << user->getEmail() << ":" << std::endl; for (const auto& connection : user->getConnections()) { connection->displayInfo(); std::cout << "------------------------" << std::endl; } } void LinkedInManager::displayUserPosts(std::string userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nPosts by " << user->getEmail() << ":" << std::endl; for (const auto& post : user->getPosts()) { post->displayInfo(); std::cout << "------------------------" << std::endl; } } void LinkedInManager::displayAllUsers() const { std::cout << "\nAll Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } User* LinkedInManager::findUser(const std::string& userId) const { for (auto user : users) { if (user->getUserId() == userId) return user; } return nullptr; } Post* LinkedInManager::findPost(const std::string& postId) const { for (auto post : posts) { if (post->getPostId() == postId) return post; } return nullptr; } std::string LinkedInManager::generatePostId() { return "P" + std::to_string(postIdCounter++); } ================================================ FILE: solutions/cpp/linkedin/LinkedInManager.hpp ================================================ #ifndef LINKEDIN_MANAGER_HPP #define LINKEDIN_MANAGER_HPP #include #include #include "User.hpp" #include "Post.hpp" class LinkedInManager { private: std::vector users; std::vector posts; int postIdCounter; public: LinkedInManager(); ~LinkedInManager(); void addUser(User* user); Post* createPost(std::string userId, std::string content, PostType type, std::string timestamp); bool addConnection(std::string userId1, std::string userId2); bool removeConnection(std::string userId1, std::string userId2); bool likePost(std::string userId, std::string postId); bool unlikePost(std::string userId, std::string postId); bool commentOnPost(std::string userId, std::string postId, const std::string& comment); void displayUserProfile(std::string userId) const; void displayUserConnections(std::string userId) const; void displayUserPosts(std::string userId) const; void displayAllUsers() const; private: User* findUser(const std::string& userId) const; Post* findPost(const std::string& postId) const; std::string generatePostId(); }; #endif ================================================ FILE: solutions/cpp/linkedin/Post.cpp ================================================ #include "Post.hpp" #include #include Post::Post(std::string postId, User* author, std::string content, PostType type, std::string timestamp) : postId(postId), author(author), content(content), type(type), timestamp(timestamp) {} std::string Post::getPostId() const { return postId; } User* Post::getAuthor() const { return author; } std::string Post::getContent() const { return content; } PostType Post::getType() const { return type; } std::string Post::getTimestamp() const { return timestamp; } const std::vector& Post::getLikes() const { return likes; } const std::vector& Post::getComments() const { return comments; } void Post::addLike(User* user) { if (user && std::find(likes.begin(), likes.end(), user) == likes.end()) { likes.push_back(user); } } void Post::removeLike(User* user) { auto it = std::find(likes.begin(), likes.end(), user); if (it != likes.end()) { likes.erase(it); } } void Post::addComment(const std::string& comment) { comments.push_back(comment); } void Post::displayInfo() const { std::cout << "\nPost Details:" << std::endl; std::cout << "ID: " << postId << std::endl; std::cout << "Author: " << author->getProfile()->getName() << std::endl; std::cout << "Type: "; switch (type) { case PostType::TEXT: std::cout << "Text"; break; case PostType::IMAGE: std::cout << "Image"; break; case PostType::VIDEO: std::cout << "Video"; break; case PostType::ARTICLE: std::cout << "Article"; break; } std::cout << std::endl; std::cout << "Content: " << content << std::endl; std::cout << "Timestamp: " << timestamp << std::endl; std::cout << "Likes: " << likes.size() << std::endl; std::cout << "Comments: " << comments.size() << std::endl; if (!comments.empty()) { std::cout << "\nComments:" << std::endl; for (const auto& comment : comments) { std::cout << "- " << comment << std::endl; } } } ================================================ FILE: solutions/cpp/linkedin/Post.hpp ================================================ #ifndef POST_HPP #define POST_HPP #include #include #include "User.hpp" enum class PostType { TEXT, IMAGE, VIDEO, ARTICLE }; class Post { private: std::string postId; User* author; std::string content; PostType type; std::string timestamp; std::vector likes; std::vector comments; public: Post(std::string postId, User* author, std::string content, PostType type, std::string timestamp); std::string getPostId() const; User* getAuthor() const; std::string getContent() const; PostType getType() const; std::string getTimestamp() const; const std::vector& getLikes() const; const std::vector& getComments() const; void addLike(User* user); void removeLike(User* user); void addComment(const std::string& comment); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/linkedin/Profile.cpp ================================================ #include "Profile.hpp" #include Profile::Profile(std::string name, std::string headline) : name(name), headline(headline) {} std::string Profile::getName() const{ return name; } void Profile::setAbout(const std::string& about) { this->about = about; } void Profile::setLocation(const std::string& location) { this->location = location; } void Profile::addSkill(const std::string& skill) { skills.push_back(skill); } void Profile::addExperience(const Experience& exp) { experiences.push_back(exp); } void Profile::addEducation(const Education& edu) { educations.push_back(edu); } void Profile::displayInfo() const { std::cout << "\nProfile Information:" << std::endl; std::cout << "Name: " << name << std::endl; std::cout << "Headline: " << headline << std::endl; if (!about.empty()) { std::cout << "About: " << about << std::endl; } if (!location.empty()) { std::cout << "Location: " << location << std::endl; } if (!skills.empty()) { std::cout << "\nSkills:" << std::endl; for (const auto& skill : skills) { std::cout << "- " << skill << std::endl; } } if (!experiences.empty()) { std::cout << "\nExperience:" << std::endl; for (const auto& exp : experiences) { std::cout << exp.position << " at " << exp.company << std::endl; std::cout << exp.startDate << " - " << exp.endDate << std::endl; std::cout << exp.description << std::endl; std::cout << "------------------------" << std::endl; } } if (!educations.empty()) { std::cout << "\nEducation:" << std::endl; for (const auto& edu : educations) { std::cout << edu.degree << " in " << edu.field << std::endl; std::cout << edu.school << std::endl; std::cout << edu.startDate << " - " << edu.endDate << std::endl; std::cout << "------------------------" << std::endl; } } } ================================================ FILE: solutions/cpp/linkedin/Profile.hpp ================================================ #ifndef PROFILE_HPP #define PROFILE_HPP #include #include struct Experience { std::string company; std::string position; std::string startDate; std::string endDate; std::string description; }; struct Education { std::string school; std::string degree; std::string field; std::string startDate; std::string endDate; }; class Profile { private: std::string name; std::string headline; std::string about; std::string location; std::vector skills; std::vector experiences; std::vector educations; public: Profile(std::string name, std::string headline); std::string getName() const; void setAbout(const std::string& about); void setLocation(const std::string& location); void addSkill(const std::string& skill); void addExperience(const Experience& exp); void addEducation(const Education& edu); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/linkedin/README.md ================================================ # Designing a Professional Networking Platform like LinkedIn ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their professional information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their professional information, such as profile picture, headline, summary, experience, education, and skills. - Users should be able to update their profile information. #### Connections: - Users should be able to send connection requests to other users. - Users should be able to accept or decline connection requests. - Users should be able to view their list of connections. #### Messaging: - Users should be able to send messages to their connections. - Users should be able to view their inbox and sent messages. #### Job Postings: - Employers should be able to post job listings with details such as title, description, requirements, and location. - Users should be able to view and apply for job postings. #### Search Functionality: - Users should be able to search for other users, companies, and job postings based on relevant criteria. - Search results should be ranked based on relevance and user preferences. #### Notifications: - Users should receive notifications for events such as connection requests, messages, and job postings. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the LinkedIn system, containing properties such as ID, name, email, password, profile, connections, inbox, and sent messages. 2. The **Profile** class represents a user's profile, containing properties such as profile picture, headline, summary, experiences, educations, and skills. 3. The **Experience**, **Education**, and **Skill** classes represent different components of a user's profile. 4. The **Connection** class represents a connection between two users, containing the user and the connection date. 5. The **Message** class represents a message sent between users, containing properties such as ID, sender, receiver, content, and timestamp. 6. The **JobPosting** class represents a job listing posted by an employer, containing properties such as ID, title, description, requirements, location, and post date. 7. The **Notification** class represents a notification generated for a user, containing properties such as ID, user, notification type, content, and timestamp. 8. The **NotificationType** enum defines the different types of notifications, such as connection request, message, and job posting. 9. The **LinkedInService** class is the main class that manages the LinkedIn system. It follows the Singleton pattern to ensure only one instance of the service exists. 10. The **LinkedInService** class provides methods for user registration, login, profile updates, connection requests, job postings, user and job search, messaging, and notifications. 11. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 12. The **LinkedInDemo** class demonstrates the usage of the LinkedIn system by registering users, logging in, updating profiles, sending connection requests, posting job listings, searching for users and jobs, sending messages, and retrieving notifications. ================================================ FILE: solutions/cpp/linkedin/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string email, std::string password) : userId(userId), email(email), password(password), profile(nullptr), active(true) {} User::~User() { delete profile; for (auto post : posts) { delete post; } } std::string User::getUserId() const { return userId; } std::string User::getEmail() const { return email; } Profile* User::getProfile() const { return profile; } bool User::isActive() const { return active; } const std::vector& User::getConnections() const { return connections; } const std::vector& User::getPosts() const { return posts; } void User::setProfile(Profile* profile) { delete this->profile; this->profile = profile; } void User::addConnection(User* user) { if (user && std::find(connections.begin(), connections.end(), user) == connections.end()) { connections.push_back(user); user->connections.push_back(this); } } void User::removeConnection(User* user) { auto it = std::find(connections.begin(), connections.end(), user); if (it != connections.end()) { connections.erase(it); auto it2 = std::find(user->connections.begin(), user->connections.end(), this); if (it2 != user->connections.end()) { user->connections.erase(it2); } } } void User::addPost(Post* post) { posts.push_back(post); } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User ID: " << userId << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Connections: " << connections.size() << std::endl; std::cout << "Posts: " << posts.size() << std::endl; if (profile) { profile->displayInfo(); } } ================================================ FILE: solutions/cpp/linkedin/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include "Profile.hpp" #include "Post.hpp" class User { private: std::string userId; std::string email; std::string password; Profile* profile; std::vector connections; std::vector posts; bool active; public: User(std::string userId, std::string email, std::string password); ~User(); std::string getUserId() const; std::string getEmail() const; Profile* getProfile() const; bool isActive() const; const std::vector& getConnections() const; const std::vector& getPosts() const; void setProfile(Profile* profile); void addConnection(User* user); void removeConnection(User* user); void addPost(Post* post); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/loggingframework/ConsoleAppender.cpp ================================================ #include "ConsoleAppender.hpp" #include void ConsoleAppender::append(const LogMessage& message) { std::cout << message.getFormattedMessage() << std::endl; } ================================================ FILE: solutions/cpp/loggingframework/ConsoleAppender.hpp ================================================ #ifndef CONSOLE_APPENDER_HPP #define CONSOLE_APPENDER_HPP #include "LogAppender.hpp" class ConsoleAppender : public LogAppender { public: void append(const LogMessage& message) override; }; #endif ================================================ FILE: solutions/cpp/loggingframework/FileAppender.cpp ================================================ #include "FileAppender.hpp" FileAppender::FileAppender(const std::string& filename) : filename(filename) { file.open(filename, std::ios::app); } FileAppender::~FileAppender() { if (file.is_open()) { file.close(); } } void FileAppender::append(const LogMessage& message) { if (file.is_open()) { file << message.getFormattedMessage() << std::endl; } } ================================================ FILE: solutions/cpp/loggingframework/FileAppender.hpp ================================================ #ifndef FILE_APPENDER_HPP #define FILE_APPENDER_HPP #include #include #include "LogAppender.hpp" class FileAppender : public LogAppender { private: std::string filename; std::ofstream file; public: FileAppender(const std::string& filename); ~FileAppender(); void append(const LogMessage& message) override; }; #endif ================================================ FILE: solutions/cpp/loggingframework/LogAppender.hpp ================================================ #ifndef LOG_APPENDER_HPP #define LOG_APPENDER_HPP #include "LogMessage.hpp" class LogAppender { public: virtual ~LogAppender() = default; virtual void append(const LogMessage& message) = 0; }; #endif ================================================ FILE: solutions/cpp/loggingframework/LogLevel.hpp ================================================ #ifndef LOG_LEVEL_HPP #define LOG_LEVEL_HPP enum class LogLevel { TRACE, DEBUG, INFO, WARN, ERROR, FATAL }; // Helper function to convert LogLevel to string inline std::string logLevelToString(LogLevel level) { switch (level) { case LogLevel::TRACE: return "TRACE"; case LogLevel::DEBUG: return "DEBUG"; case LogLevel::INFO: return "INFO"; case LogLevel::WARN: return "WARN"; case LogLevel::ERROR: return "ERROR"; case LogLevel::FATAL: return "FATAL"; default: return "UNKNOWN"; } } #endif ================================================ FILE: solutions/cpp/loggingframework/LogMessage.cpp ================================================ #include "LogMessage.hpp" #include #include LogMessage::LogMessage(LogLevel level, const std::string& message, const std::string& source) : level(level), message(message), source(source) { // Get current timestamp auto now = std::time(nullptr); auto tm = *std::localtime(&now); std::ostringstream oss; oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); timestamp = oss.str(); } LogLevel LogMessage::getLevel() const { return level; } std::string LogMessage::getMessage() const { return message; } std::string LogMessage::getTimestamp() const { return timestamp; } std::string LogMessage::getSource() const { return source; } std::string LogMessage::getFormattedMessage() const { std::ostringstream oss; oss << "[" << timestamp << "] " << "[" << logLevelToString(level) << "] " << "[" << source << "] " << message; return oss.str(); } ================================================ FILE: solutions/cpp/loggingframework/LogMessage.hpp ================================================ #ifndef LOG_MESSAGE_HPP #define LOG_MESSAGE_HPP #include #include #include "LogLevel.hpp" class LogMessage { private: LogLevel level; std::string message; std::string timestamp; std::string source; public: LogMessage(LogLevel level, const std::string& message, const std::string& source); LogLevel getLevel() const; std::string getMessage() const; std::string getTimestamp() const; std::string getSource() const; std::string getFormattedMessage() const; }; #endif ================================================ FILE: solutions/cpp/loggingframework/Logger.cpp ================================================ #include "Logger.hpp" Logger::Logger(const std::string& name, LogLevel minLevel) : name(name), minLevel(minLevel) {} void Logger::addAppender(std::shared_ptr appender) { appenders.push_back(appender); } void Logger::setMinLevel(LogLevel level) { minLevel = level; } bool Logger::isLevelEnabled(LogLevel level) const { return static_cast(level) >= static_cast(minLevel); } void Logger::log(LogLevel level, const std::string& message) { if (!isLevelEnabled(level)) return; LogMessage logMessage(level, message, name); for (const auto& appender : appenders) { appender->append(logMessage); } } void Logger::trace(const std::string& message) { log(LogLevel::TRACE, message); } void Logger::debug(const std::string& message) { log(LogLevel::DEBUG, message); } void Logger::info(const std::string& message) { log(LogLevel::INFO, message); } void Logger::warn(const std::string& message) { log(LogLevel::WARN, message); } void Logger::error(const std::string& message) { log(LogLevel::ERROR, message); } void Logger::fatal(const std::string& message) { log(LogLevel::FATAL, message); } ================================================ FILE: solutions/cpp/loggingframework/Logger.hpp ================================================ #ifndef LOGGER_HPP #define LOGGER_HPP #include #include #include #include "LogLevel.hpp" #include "LogMessage.hpp" #include "LogAppender.hpp" class Logger { private: std::string name; LogLevel minLevel; std::vector> appenders; public: Logger(const std::string& name, LogLevel minLevel = LogLevel::INFO); void addAppender(std::shared_ptr appender); void setMinLevel(LogLevel level); void log(LogLevel level, const std::string& message); void trace(const std::string& message); void debug(const std::string& message); void info(const std::string& message); void warn(const std::string& message); void error(const std::string& message); void fatal(const std::string& message); private: bool isLevelEnabled(LogLevel level) const; }; #endif ================================================ FILE: solutions/cpp/loggingframework/LoggingDemo.cpp ================================================ #include "Logger.hpp" #include "ConsoleAppender.hpp" #include "FileAppender.hpp" #include int main() { // Create logger Logger logger("MyApp"); // Add console appender auto consoleAppender = std::make_shared(); logger.addAppender(consoleAppender); // Add file appender auto fileAppender = std::make_shared("app.log"); logger.addAppender(fileAppender); // Log messages at different levels logger.trace("This is a trace message"); // Won't be logged (below INFO) logger.debug("This is a debug message"); // Won't be logged (below INFO) logger.info("Application started"); logger.warn("This is a warning message"); logger.error("An error occurred"); logger.fatal("Fatal error: application shutting down"); // Change minimum log level logger.setMinLevel(LogLevel::DEBUG); logger.debug("Now debug messages will be logged"); return 0; } ================================================ FILE: solutions/cpp/loggingframework/README.md ================================================ # Designing a Logging Framework ## Requirements 1. The logging framework should support different log levels, such as DEBUG, INFO, WARNING, ERROR, and FATAL. 2. It should allow logging messages with a timestamp, log level, and message content. 3. The framework should support multiple output destinations, such as console, file, and database. 4. It should provide a configuration mechanism to set the log level and output destination. 5. The logging framework should be thread-safe to handle concurrent logging from multiple threads. 6. It should be extensible to accommodate new log levels and output destinations in the future. ## Classes, Interfaces and Enumerations 1. The **LogLevel** enum defines the different log levels supported by the logging framework. 2. The **LogMessage** class represents a log message with a timestamp, log level, and message content. 3. The **LogAppender** interface defines the contract for appending log messages to different output destinations. 4. The **ConsoleAppender**, **FileAppender**, and **DatabaseAppender** classes are concrete implementations of the LogAppender interface, supporting logging to the console, file, and database, respectively. 5. The **LoggerConfig** class holds the configuration settings for the logger, including the log level and the selected log appender. 6. The **Logger** class is a singleton that provides the main logging functionality. It allows setting the configuration, logging messages at different levels, and provides convenience methods for each log level. 7. The **LoggingExample** class demonstrates the usage of the logging framework, showcasing different log levels, changing the configuration, and logging from multiple threads. ================================================ FILE: solutions/cpp/lrucache/DoublyLinkedList.hpp ================================================ #ifndef DOUBLY_LINKED_LIST_HPP #define DOUBLY_LINKED_LIST_HPP template struct Node { K key; V value; Node* prev; Node* next; Node(K key, V value) : key(key), value(value), prev(nullptr), next(nullptr) {} }; template class DoublyLinkedList { private: Node* head; Node* tail; int size; public: DoublyLinkedList() : head(nullptr), tail(nullptr), size(0) {} ~DoublyLinkedList() { while (head) { Node* temp = head; head = head->next; delete temp; } } Node* addToFront(K key, V value) { Node* node = new Node(key, value); if (!head) { head = tail = node; } else { node->next = head; head->prev = node; head = node; } size++; return node; } void moveToFront(Node* node) { if (node == head) return; if (node == tail) { tail = node->prev; tail->next = nullptr; } else { node->prev->next = node->next; node->next->prev = node->prev; } node->prev = nullptr; node->next = head; head->prev = node; head = node; } void removeNode(Node* node) { if (node == head) { head = node->next; if (head) head->prev = nullptr; } else if (node == tail) { tail = node->prev; tail->next = nullptr; } else { node->prev->next = node->next; node->next->prev = node->prev; } delete node; size--; if (size == 0) { head = tail = nullptr; } } Node* removeLast() { if (!tail) return nullptr; Node* node = tail; tail = tail->prev; if (tail) { tail->next = nullptr; } else { head = nullptr; } size--; return node; } int getSize() const { return size; } bool isEmpty() const { return size == 0; } Node* getHead() const { return head; } Node* getTail() const { return tail; } }; #endif ================================================ FILE: solutions/cpp/lrucache/LRUCache.hpp ================================================ #ifndef LRU_CACHE_HPP #define LRU_CACHE_HPP #include #include "DoublyLinkedList.hpp" template class LRUCache { private: int capacity; DoublyLinkedList dll; std::unordered_map*> cache; public: LRUCache(int capacity) : capacity(capacity) {} V get(K key) { auto it = cache.find(key); if (it == cache.end()) { throw std::runtime_error("Key not found"); } Node* node = it->second; dll.moveToFront(node); return node->value; } void put(K key, V value) { auto it = cache.find(key); if (it != cache.end()) { // Key exists, update value and move to front Node* node = it->second; node->value = value; dll.moveToFront(node); } else { // Key doesn't exist, add new entry if (cache.size() >= capacity) { // Remove least recently used item Node* lastNode = dll.getTail(); cache.erase(lastNode->key); dll.removeNode(lastNode); } // Add new item to front Node* newNode = dll.addToFront(key, value); cache[key] = newNode; } } bool contains(K key) const { return cache.find(key) != cache.end(); } int getSize() const { return cache.size(); } bool isEmpty() const { return cache.empty(); } void clear() { while (!dll.isEmpty()) { Node* node = dll.removeLast(); cache.erase(node->key); delete node; } } void display() const { std::cout << "\nLRU Cache Contents:" << std::endl; Node* current = dll.getHead(); while (current) { std::cout << current->key << " -> " << current->value << std::endl; current = current->next; } std::cout << "Cache size: " << cache.size() << "/" << capacity << std::endl; } }; #endif ================================================ FILE: solutions/cpp/lrucache/LRUCacheDemo.cpp ================================================ #include "LRUCache.hpp" #include #include int main() { // Create LRU cache with capacity 3 LRUCache cache(3); // Add some entries std::cout << "Adding entries to cache..." << std::endl; cache.put(1, "One"); cache.put(2, "Two"); cache.put(3, "Three"); cache.display(); // Try to get an entry std::cout << "\nGetting value for key 2..." << std::endl; std::cout << "Value: " << cache.get(2) << std::endl; cache.display(); // 2 should move to front // Add new entry when cache is full std::cout << "\nAdding new entry when cache is full..." << std::endl; cache.put(4, "Four"); // Should evict least recently used item cache.display(); // Try to access non-existent key std::cout << "\nTrying to access non-existent key..." << std::endl; try { cache.get(1); // Should throw exception } catch (const std::runtime_error& e) { std::cout << "Error: " << e.what() << std::endl; } // Update existing entry std::cout << "\nUpdating existing entry..." << std::endl; cache.put(2, "Two Updated"); cache.display(); // Clear cache std::cout << "\nClearing cache..." << std::endl; cache.clear(); cache.display(); return 0; } ================================================ FILE: solutions/cpp/lrucache/README.md ================================================ # Designing a LRU Cache ## Requirements 1. The LRU cache should support the following operations: - put(key, value): Insert a key-value pair into the cache. If the cache is at capacity, remove the least recently used item before inserting the new item. - get(key): Get the value associated with the given key. If the key exists in the cache, move it to the front of the cache (most recently used) and return its value. If the key does not exist, return -1. 2. The cache should have a fixed capacity, specified during initialization. 3. The cache should be thread-safe, allowing concurrent access from multiple threads. 4. The cache should be efficient in terms of time complexity for both put and get operations, ideally O(1). ## Classes, Interfaces and Enumerations 1. The **Node** class represents a node in the doubly linked list, containing the key, value, and references to the previous and next nodes. 2. The **LRUCache** class implements the LRU cache functionality using a combination of a hash map (cache) and a doubly linked list (head and tail). 3. The get method retrieves the value associated with a given key. If the key exists in the cache, it is moved to the head of the linked list (most recently used) and its value is returned. If the key does not exist, null is returned. 4. The put method inserts a key-value pair into the cache. If the key already exists, its value is updated, and the node is moved to the head of the linked list. If the key does not exist and the cache is at capacity, the least recently used item (at the tail of the linked list) is removed, and the new item is inserted at the head. 5. The addToHead, removeNode, moveToHead, and removeTail methods are helper methods to manipulate the doubly linked list. 6. The synchronized keyword is used on the get and put methods to ensure thread safety, allowing concurrent access from multiple threads. 7. The **LRUCacheDemo** class demonstrates the usage of the LRU cache by creating an instance of LRUCache with a capacity of 3, performing various put and get operations, and printing the results. ================================================ FILE: solutions/cpp/movieticketbookingsystem/Booking.cpp ================================================ #include "Booking.hpp" #include #include #include Booking::Booking(std::string bookingId, Show* show, std::string customerName, std::string customerPhone, const std::vector& seatNumbers) : bookingId(bookingId), show(show), customerName(customerName), customerPhone(customerPhone), seatNumbers(seatNumbers), status(BookingStatus::PENDING) { // Get current timestamp auto now = std::time(nullptr); auto tm = *std::localtime(&now); std::ostringstream oss; oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); timestamp = oss.str(); calculateTotalAmount(); } std::string Booking::getBookingId() const { return bookingId; } Show* Booking::getShow() const { return show; } std::string Booking::getCustomerName() const { return customerName; } std::string Booking::getCustomerPhone() const { return customerPhone; } const std::vector& Booking::getSeatNumbers() const { return seatNumbers; } double Booking::getTotalAmount() const { return totalAmount; } BookingStatus Booking::getStatus() const { return status; } std::string Booking::getTimestamp() const { return timestamp; } void Booking::calculateTotalAmount() { totalAmount = show->getTicketPrice() * seatNumbers.size(); } void Booking::setStatus(BookingStatus status) { this->status = status; } void Booking::displayInfo() const { std::cout << "\nBooking Details:" << std::endl; std::cout << "Booking ID: " << bookingId << std::endl; std::cout << "Customer Name: " << customerName << std::endl; std::cout << "Customer Phone: " << customerPhone << std::endl; show->displayInfo(); std::cout << "Seats: "; for (int seat : seatNumbers) { std::cout << seat << " "; } std::cout << std::endl; std::cout << "Total Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; std::cout << "Status: "; switch (status) { case BookingStatus::PENDING: std::cout << "Pending"; break; case BookingStatus::CONFIRMED: std::cout << "Confirmed"; break; case BookingStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; std::cout << "Booking Time: " << timestamp << std::endl; } ================================================ FILE: solutions/cpp/movieticketbookingsystem/Booking.hpp ================================================ #ifndef BOOKING_HPP #define BOOKING_HPP #include #include #include "Show.hpp" enum class BookingStatus { PENDING, CONFIRMED, CANCELLED }; class Booking { private: std::string bookingId; Show* show; std::string customerName; std::string customerPhone; std::vector seatNumbers; double totalAmount; BookingStatus status; std::string timestamp; public: Booking(std::string bookingId, Show* show, std::string customerName, std::string customerPhone, const std::vector& seatNumbers); std::string getBookingId() const; Show* getShow() const; std::string getCustomerName() const; std::string getCustomerPhone() const; const std::vector& getSeatNumbers() const; double getTotalAmount() const; BookingStatus getStatus() const; std::string getTimestamp() const; void calculateTotalAmount(); void setStatus(BookingStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/movieticketbookingsystem/BookingDemo.cpp ================================================ #include "BookingSystem.hpp" #include int main() { BookingSystem system; // Create movies Movie* movie1 = new Movie("M001", "The Matrix", "A sci-fi action movie", MovieGenre::SCIFI, 136, "English"); movie1->addCastMember("Keanu Reeves"); movie1->addCastMember("Laurence Fishburne"); Movie* movie2 = new Movie("M002", "Inception", "A mind-bending thriller", MovieGenre::THRILLER, 148, "English"); movie2->addCastMember("Leonardo DiCaprio"); movie2->addCastMember("Ellen Page"); system.addMovie(movie1); system.addMovie(movie2); // Create theaters Theater* theater1 = new Theater("T001", "Cineplex", "Downtown", 100); Theater* theater2 = new Theater("T002", "MovieMax", "Uptown", 150); system.addTheater(theater1); system.addTheater(theater2); // Create shows Show* show1 = new Show("S001", movie1, "2024-01-01", "18:00", 12.99, 100); Show* show2 = new Show("S002", movie2, "2024-01-01", "20:00", 14.99, 150); theater1->addShow(show1); theater2->addShow(show2); // Display available movies and shows system.displayMovies(); system.displayShows("M001"); // Create a booking std::vector seats = {1, 2, 3}; Booking* booking = system.createBooking("S001", "John Doe", "+1-555-0123", seats); if (booking) { std::cout << "\nBooking created successfully!" << std::endl; system.displayBooking(booking->getBookingId()); // Try to book same seats again std::cout << "\nTrying to book same seats again..." << std::endl; Booking* failedBooking = system.createBooking("S001", "Jane Smith", "+1-555-0124", seats); if (!failedBooking) { std::cout << "Booking failed: Seats already taken" << std::endl; } // Cancel booking std::cout << "\nCancelling booking..." << std::endl; if (system.cancelBooking(booking->getBookingId())) { std::cout << "Booking cancelled successfully!" << std::endl; system.displayBooking(booking->getBookingId()); } } return 0; } ================================================ FILE: solutions/cpp/movieticketbookingsystem/BookingSystem.cpp ================================================ #include "BookingSystem.hpp" #include #include BookingSystem::BookingSystem() : bookingIdCounter(1) {} BookingSystem::~BookingSystem() { for (auto movie : movies) delete movie; for (auto theater : theaters) delete theater; for (auto booking : bookings) delete booking; } void BookingSystem::addMovie(Movie* movie) { movies.push_back(movie); } void BookingSystem::addTheater(Theater* theater) { theaters.push_back(theater); } Booking* BookingSystem::createBooking(std::string showId, std::string customerName, std::string customerPhone, const std::vector& seats) { Show* show = findShow(showId); if (!show || show->getStatus() != ShowStatus::SCHEDULED) { return nullptr; } // Check if all seats are available for (int seatNumber : seats) { if (!show->isSeatAvailable(seatNumber)) { return nullptr; } } // Book all seats for (int seatNumber : seats) { show->bookSeat(seatNumber); } // Create booking Booking* booking = new Booking(generateBookingId(), show, customerName, customerPhone, seats); booking->setStatus(BookingStatus::CONFIRMED); bookings.push_back(booking); return booking; } bool BookingSystem::cancelBooking(std::string bookingId) { Booking* booking = findBooking(bookingId); if (!booking || booking->getStatus() == BookingStatus::CANCELLED) { return false; } // Cancel seat bookings Show* show = booking->getShow(); for (int seatNumber : booking->getSeatNumbers()) { show->cancelSeatBooking(seatNumber); } booking->setStatus(BookingStatus::CANCELLED); return true; } void BookingSystem::displayMovies() const { std::cout << "\nAvailable Movies:" << std::endl; for (const auto& movie : movies) { if (movie->isActive()) { movie->displayInfo(); std::cout << "------------------------" << std::endl; } } } void BookingSystem::displayTheaters() const { std::cout << "\nTheaters:" << std::endl; for (const auto& theater : theaters) { if (theater->isActive()) { theater->displayInfo(); std::cout << "------------------------" << std::endl; } } } void BookingSystem::displayShows(std::string movieId) const { std::cout << "\nShows for Movie ID " << movieId << ":" << std::endl; for (const auto& theater : theaters) { for (const auto& show : theater->getShows()) { if (show->getMovie()->getMovieId() == movieId) { show->displayInfo(); std::cout << "------------------------" << std::endl; } } } } void BookingSystem::displayBooking(std::string bookingId) const { Booking* booking = findBooking(bookingId); if (booking) { booking->displayInfo(); } } Show* BookingSystem::findShow(const std::string& showId) const { for (const auto& theater : theaters) { for (const auto& show : theater->getShows()) { if (show->getShowId() == showId) { return show; } } } return nullptr; } Booking* BookingSystem::findBooking(const std::string& bookingId) const { for (auto booking : bookings) { if (booking->getBookingId() == bookingId) { return booking; } } return nullptr; } std::string BookingSystem::generateBookingId() { return "B" + std::to_string(bookingIdCounter++); } ================================================ FILE: solutions/cpp/movieticketbookingsystem/BookingSystem.hpp ================================================ #ifndef BOOKING_SYSTEM_HPP #define BOOKING_SYSTEM_HPP #include #include #include "Movie.hpp" #include "Theater.hpp" #include "Show.hpp" #include "Booking.hpp" class BookingSystem { private: std::vector movies; std::vector theaters; std::vector bookings; int bookingIdCounter; public: BookingSystem(); ~BookingSystem(); void addMovie(Movie* movie); void addTheater(Theater* theater); Booking* createBooking(std::string showId, std::string customerName, std::string customerPhone, const std::vector& seats); bool cancelBooking(std::string bookingId); void displayMovies() const; void displayTheaters() const; void displayShows(std::string movieId) const; void displayBooking(std::string bookingId) const; private: Show* findShow(const std::string& showId) const; Booking* findBooking(const std::string& bookingId) const; std::string generateBookingId(); }; #endif ================================================ FILE: solutions/cpp/movieticketbookingsystem/Movie.cpp ================================================ #include "Movie.hpp" #include Movie::Movie(std::string movieId, std::string title, std::string description, MovieGenre genre, int durationMinutes, std::string language) : movieId(movieId), title(title), description(description), genre(genre), durationMinutes(durationMinutes), language(language), active(true) {} std::string Movie::getMovieId() const { return movieId; } std::string Movie::getTitle() const { return title; } std::string Movie::getDescription() const { return description; } MovieGenre Movie::getGenre() const { return genre; } int Movie::getDurationMinutes() const { return durationMinutes; } std::string Movie::getLanguage() const { return language; } bool Movie::isActive() const { return active; } const std::vector& Movie::getCast() const { return cast; } void Movie::addCastMember(const std::string& actor) { cast.push_back(actor); } void Movie::setActive(bool status) { active = status; } void Movie::displayInfo() const { std::cout << "Movie: " << title << " (ID: " << movieId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Genre: "; switch (genre) { case MovieGenre::ACTION: std::cout << "Action"; break; case MovieGenre::COMEDY: std::cout << "Comedy"; break; case MovieGenre::DRAMA: std::cout << "Drama"; break; case MovieGenre::HORROR: std::cout << "Horror"; break; case MovieGenre::SCIFI: std::cout << "Sci-Fi"; break; case MovieGenre::THRILLER: std::cout << "Thriller"; break; } std::cout << std::endl; std::cout << "Duration: " << durationMinutes << " minutes" << std::endl; std::cout << "Language: " << language << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; if (!cast.empty()) { std::cout << "Cast:" << std::endl; for (const auto& actor : cast) { std::cout << "- " << actor << std::endl; } } } ================================================ FILE: solutions/cpp/movieticketbookingsystem/Movie.hpp ================================================ #ifndef MOVIE_HPP #define MOVIE_HPP #include #include enum class MovieGenre { ACTION, COMEDY, DRAMA, HORROR, SCIFI, THRILLER }; class Movie { private: std::string movieId; std::string title; std::string description; MovieGenre genre; int durationMinutes; std::string language; std::vector cast; bool active; public: Movie(std::string movieId, std::string title, std::string description, MovieGenre genre, int durationMinutes, std::string language); std::string getMovieId() const; std::string getTitle() const; std::string getDescription() const; MovieGenre getGenre() const; int getDurationMinutes() const; std::string getLanguage() const; bool isActive() const; const std::vector& getCast() const; void addCastMember(const std::string& actor); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/movieticketbookingsystem/README.md ================================================ # Designing a Movie Ticket Booking System like BookMyShow ## Requirements 1. The system should allow users to view the list of movies playing in different theaters. 2. Users should be able to select a movie, theater, and show timing to book tickets. 3. The system should display the seating arrangement of the selected show and allow users to choose seats. 4. Users should be able to make payments and confirm their booking. 5. The system should handle concurrent bookings and ensure seat availability is updated in real-time. 6. The system should support different types of seats (e.g., normal, premium) and pricing. 7. The system should allow theater administrators to add, update, and remove movies, shows, and seating arrangements. 8. The system should be scalable to handle a large number of concurrent users and bookings. ## Classes, Interfaces and Enumerations 1. The **Movie** class represents a movie with properties such as ID, title, description, and duration. 2. The **Theater** class represents a theater with properties such as ID, name, location, and a list of shows. 3. The **Show** class represents a movie show in a theater, with properties such as ID, movie, theater, start time, end time, and a map of seats. 4. The **Seat** class represents a seat in a show, with properties such as ID, row, column, type, price, and status. 5. The **SeatType** enum defines the different types of seats (normal or premium). 6. The **SeatStatus** enum defines the different statuses of a seat (available or booked). 7. The **Booking** class represents a booking made by a user, with properties such as ID, user, show, selected seats, total price, and status. 8. The **BookingStatus** enum defines the different statuses of a booking (pending, confirmed, or cancelled). 9. The **User** class represents a user of the booking system, with properties such as ID, name, and email. 10. The **MovieTicketBookingSystem** class is the main class that manages the movie ticket booking system. It follows the Singleton pattern to ensure only one instance of the system exists. 11. The MovieTicketBookingSystem class provides methods for adding movies, theaters, and shows, as well as booking tickets, confirming bookings, and cancelling bookings. 12. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap to handle concurrent access to shared resources like shows and bookings. 13. The **MovieTicketBookingDemo** class demonstrates the usage of the movie ticket booking system by adding movies, theaters, shows, booking tickets, and confirming or cancelling bookings. ================================================ FILE: solutions/cpp/movieticketbookingsystem/Show.cpp ================================================ #include "Show.hpp" #include #include Show::Show(std::string showId, Movie* movie, std::string date, std::string startTime, double ticketPrice, int totalSeats) : showId(showId), movie(movie), date(date), startTime(startTime), ticketPrice(ticketPrice), seats(totalSeats, false), status(ShowStatus::SCHEDULED) {} std::string Show::getShowId() const { return showId; } Movie* Show::getMovie() const { return movie; } std::string Show::getDate() const { return date; } std::string Show::getStartTime() const { return startTime; } double Show::getTicketPrice() const { return ticketPrice; } ShowStatus Show::getStatus() const { return status; } bool Show::isSeatAvailable(int seatNumber) const { if (seatNumber < 1 || seatNumber > seats.size()) return false; return !seats[seatNumber - 1]; } bool Show::bookSeat(int seatNumber) { if (!isSeatAvailable(seatNumber)) return false; seats[seatNumber - 1] = true; return true; } void Show::cancelSeatBooking(int seatNumber) { if (seatNumber >= 1 && seatNumber <= seats.size()) { seats[seatNumber - 1] = false; } } void Show::setStatus(ShowStatus status) { this->status = status; } int Show::getAvailableSeats() const { int count = 0; for (bool seat : seats) { if (!seat) count++; } return count; } void Show::displayInfo() const { std::cout << "\nShow Details:" << std::endl; std::cout << "Show ID: " << showId << std::endl; movie->displayInfo(); std::cout << "Date: " << date << std::endl; std::cout << "Start Time: " << startTime << std::endl; std::cout << "Ticket Price: $" << std::fixed << std::setprecision(2) << ticketPrice << std::endl; std::cout << "Available Seats: " << getAvailableSeats() << "/" << seats.size() << std::endl; std::cout << "Status: "; switch (status) { case ShowStatus::SCHEDULED: std::cout << "Scheduled"; break; case ShowStatus::RUNNING: std::cout << "Running"; break; case ShowStatus::COMPLETED: std::cout << "Completed"; break; case ShowStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; } ================================================ FILE: solutions/cpp/movieticketbookingsystem/Show.hpp ================================================ #ifndef SHOW_HPP #define SHOW_HPP #include #include #include "Movie.hpp" enum class ShowStatus { SCHEDULED, RUNNING, COMPLETED, CANCELLED }; class Show { private: std::string showId; Movie* movie; std::string date; std::string startTime; double ticketPrice; std::vector seats; // true if seat is booked ShowStatus status; public: Show(std::string showId, Movie* movie, std::string date, std::string startTime, double ticketPrice, int totalSeats); std::string getShowId() const; Movie* getMovie() const; std::string getDate() const; std::string getStartTime() const; double getTicketPrice() const; ShowStatus getStatus() const; bool isSeatAvailable(int seatNumber) const; bool bookSeat(int seatNumber); void cancelSeatBooking(int seatNumber); void setStatus(ShowStatus status); int getAvailableSeats() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/movieticketbookingsystem/Theater.cpp ================================================ #include "Theater.hpp" #include #include Theater::Theater(std::string theaterId, std::string name, std::string location, int totalSeats) : theaterId(theaterId), name(name), location(location), totalSeats(totalSeats), active(true) {} Theater::~Theater() { for (auto show : shows) { delete show; } } std::string Theater::getTheaterId() const { return theaterId; } std::string Theater::getName() const { return name; } std::string Theater::getLocation() const { return location; } int Theater::getTotalSeats() const { return totalSeats; } bool Theater::isActive() const { return active; } const std::vector& Theater::getShows() const { return shows; } void Theater::addShow(Show* show) { shows.push_back(show); } void Theater::removeShow(Show* show) { auto it = std::find(shows.begin(), shows.end(), show); if (it != shows.end()) { shows.erase(it); } } void Theater::setActive(bool status) { active = status; } void Theater::displayInfo() const { std::cout << "Theater: " << name << " (ID: " << theaterId << ")" << std::endl; std::cout << "Location: " << location << std::endl; std::cout << "Total Seats: " << totalSeats << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Number of Shows: " << shows.size() << std::endl; } ================================================ FILE: solutions/cpp/movieticketbookingsystem/Theater.hpp ================================================ #ifndef THEATER_HPP #define THEATER_HPP #include #include #include "Show.hpp" class Theater { private: std::string theaterId; std::string name; std::string location; int totalSeats; std::vector shows; bool active; public: Theater(std::string theaterId, std::string name, std::string location, int totalSeats); ~Theater(); std::string getTheaterId() const; std::string getName() const; std::string getLocation() const; int getTotalSeats() const; bool isActive() const; const std::vector& getShows() const; void addShow(Show* show); void removeShow(Show* show); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/musicstreamingservice/Artist.cpp ================================================ #include "Artist.hpp" #include #include Artist::Artist(std::string artistId, std::string name, std::string bio) : artistId(artistId), name(name), bio(bio), active(true) {} Artist::~Artist() { for (auto song : songs) { delete song; } } std::string Artist::getArtistId() const { return artistId; } std::string Artist::getName() const { return name; } std::string Artist::getBio() const { return bio; } bool Artist::isActive() const { return active; } const std::vector& Artist::getSongs() const { return songs; } void Artist::addSong(Song* song) { songs.push_back(song); } void Artist::removeSong(Song* song) { auto it = std::find(songs.begin(), songs.end(), song); if (it != songs.end()) { delete *it; songs.erase(it); } } void Artist::setActive(bool status) { active = status; } void Artist::displayInfo() const { std::cout << "Artist: " << name << " (ID: " << artistId << ")" << std::endl; std::cout << "Bio: " << bio << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Number of Songs: " << songs.size() << std::endl; if (!songs.empty()) { std::cout << "\nSongs:" << std::endl; for (const auto& song : songs) { std::cout << "- " << song->getTitle() << " (" << song->getAlbum() << ")" << std::endl; } } } ================================================ FILE: solutions/cpp/musicstreamingservice/Artist.hpp ================================================ #ifndef ARTIST_HPP #define ARTIST_HPP #include #include #include "Song.hpp" class Artist { private: std::string artistId; std::string name; std::string bio; std::vector songs; bool active; public: Artist(std::string artistId, std::string name, std::string bio); ~Artist(); std::string getArtistId() const; std::string getName() const; std::string getBio() const; bool isActive() const; const std::vector& getSongs() const; void addSong(Song* song); void removeSong(Song* song); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/musicstreamingservice/MusicStreamingDemo.cpp ================================================ #include "MusicStreamingService.hpp" #include int main() { MusicStreamingService service; // Create users User* user1 = new User("U001", "john_doe", "john@email.com"); User* user2 = new User("U002", "jane_smith", "jane@email.com", UserType::PREMIUM); service.addUser(user1); service.addUser(user2); // Create artists Artist* artist1 = new Artist("A001", "The Beatles", "Legendary British rock band"); Artist* artist2 = new Artist("A002", "Queen", "Iconic rock band led by Freddie Mercury"); service.addArtist(artist1); service.addArtist(artist2); // Add songs Song* song1 = new Song("S001", "Hey Jude", "The Beatles", "The Beatles", Genre::ROCK, 431, "path/to/hey_jude.mp3"); Song* song2 = new Song("S002", "Let It Be", "The Beatles", "Let It Be", Genre::ROCK, 243, "path/to/let_it_be.mp3"); Song* song3 = new Song("S003", "Bohemian Rhapsody", "Queen", "A Night at the Opera", Genre::ROCK, 354, "path/to/bohemian_rhapsody.mp3"); service.addSong(song1, "A001"); service.addSong(song2, "A001"); service.addSong(song3, "A002"); // Display all songs and artists std::cout << "Initial catalog:" << std::endl; service.displayAllSongs(); service.displayAllArtists(); // Create playlists Playlist* playlist1 = service.createPlaylist("U001", "Rock Classics", "Best rock songs of all time"); if (playlist1) { service.addSongToPlaylist(playlist1->getPlaylistId(), "S001"); service.addSongToPlaylist(playlist1->getPlaylistId(), "S003"); } Playlist* playlist2 = service.createPlaylist("U002", "Beatles Only", "Beatles songs collection", false); if (playlist2) { service.addSongToPlaylist(playlist2->getPlaylistId(), "S001"); service.addSongToPlaylist(playlist2->getPlaylistId(), "S002"); } // Display user playlists std::cout << "\nUser Playlists:" << std::endl; service.displayUserPlaylists("U001"); service.displayUserPlaylists("U002"); // Search functionality std::cout << "\nSearching for 'Beatles':" << std::endl; auto songResults = service.searchSongs("Beatles"); for (const auto& song : songResults) { song->displayInfo(); } // Remove song from playlist std::cout << "\nRemoving 'Hey Jude' from Rock Classics playlist..." << std::endl; if (service.removeSongFromPlaylist(playlist1->getPlaylistId(), "S001")) { std::cout << "Song removed successfully" << std::endl; service.displayUserPlaylists("U001"); } // Upgrade user to premium std::cout << "\nUpgrading user john_doe to premium..." << std::endl; user1->upgradeToPremuim(); user1->displayInfo(); return 0; } ================================================ FILE: solutions/cpp/musicstreamingservice/MusicStreamingService.cpp ================================================ #include "MusicStreamingService.hpp" #include #include MusicStreamingService::MusicStreamingService() : playlistIdCounter(1) {} MusicStreamingService::~MusicStreamingService() { for (auto user : users) delete user; for (auto artist : artists) delete artist; for (auto song : songs) delete song; } void MusicStreamingService::addUser(User* user) { users.push_back(user); } void MusicStreamingService::addArtist(Artist* artist) { artists.push_back(artist); } void MusicStreamingService::addSong(Song* song, std::string artistId) { Artist* artist = findArtist(artistId); if (artist && artist->isActive()) { songs.push_back(song); artist->addSong(song); } } Playlist* MusicStreamingService::createPlaylist(std::string userId, std::string name, std::string description, bool isPublic) { User* user = findUser(userId); if (!user || !user->isActive()) return nullptr; Playlist* playlist = new Playlist(generatePlaylistId(), name, description, isPublic); user->addPlaylist(playlist); return playlist; } bool MusicStreamingService::addSongToPlaylist(std::string playlistId, std::string songId) { Playlist* playlist = findPlaylist(playlistId); Song* song = findSong(songId); if (playlist && song && song->isActive()) { playlist->addSong(song); return true; } return false; } bool MusicStreamingService::removeSongFromPlaylist(std::string playlistId, std::string songId) { Playlist* playlist = findPlaylist(playlistId); Song* song = findSong(songId); if (playlist && song) { playlist->removeSong(song); return true; } return false; } std::vector MusicStreamingService::searchSongs(const std::string& query) const { std::vector results; for (auto song : songs) { if (song->isActive() && (song->getTitle().find(query) != std::string::npos || song->getArtist().find(query) != std::string::npos || song->getAlbum().find(query) != std::string::npos)) { results.push_back(song); } } return results; } std::vector MusicStreamingService::searchArtists(const std::string& query) const { std::vector results; for (auto artist : artists) { if (artist->isActive() && (artist->getName().find(query) != std::string::npos || artist->getBio().find(query) != std::string::npos)) { results.push_back(artist); } } return results; } std::vector MusicStreamingService::searchPlaylists(const std::string& query) const { std::vector results; for (auto user : users) { for (auto playlist : user->getPlaylists()) { if (playlist->getIsPublic() && (playlist->getName().find(query) != std::string::npos || playlist->getDescription().find(query) != std::string::npos)) { results.push_back(playlist); } } } return results; } void MusicStreamingService::displayAllSongs() const { std::cout << "\nAll Songs:" << std::endl; for (const auto& song : songs) { if (song->isActive()) { song->displayInfo(); std::cout << "------------------------" << std::endl; } } } void MusicStreamingService::displayAllArtists() const { std::cout << "\nAll Artists:" << std::endl; for (const auto& artist : artists) { if (artist->isActive()) { artist->displayInfo(); std::cout << "------------------------" << std::endl; } } } void MusicStreamingService::displayUserPlaylists(std::string userId) const { User* user = findUser(userId); if (user && user->isActive()) { std::cout << "\nPlaylists for user " << user->getUsername() << ":" << std::endl; for (const auto& playlist : user->getPlaylists()) { playlist->displayInfo(); std::cout << "------------------------" << std::endl; } } } void MusicStreamingService::displayArtistSongs(std::string artistId) const { Artist* artist = findArtist(artistId); if (artist && artist->isActive()) { artist->displayInfo(); } } User* MusicStreamingService::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [&userId](const User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Artist* MusicStreamingService::findArtist(const std::string& artistId) const { auto it = std::find_if(artists.begin(), artists.end(), [&artistId](const Artist* artist) { return artist->getArtistId() == artistId; }); return it != artists.end() ? *it : nullptr; } Song* MusicStreamingService::findSong(const std::string& songId) const { auto it = std::find_if(songs.begin(), songs.end(), [&songId](const Song* song) { return song->getSongId() == songId; }); return it != songs.end() ? *it : nullptr; } Playlist* MusicStreamingService::findPlaylist(const std::string& playlistId) const { for (const auto& user : users) { for (const auto& playlist : user->getPlaylists()) { if (playlist->getPlaylistId() == playlistId) { return playlist; } } } return nullptr; } std::string MusicStreamingService::generatePlaylistId() { return "P" + std::to_string(playlistIdCounter++); } ================================================ FILE: solutions/cpp/musicstreamingservice/MusicStreamingService.hpp ================================================ #ifndef MUSIC_STREAMING_SERVICE_HPP #define MUSIC_STREAMING_SERVICE_HPP #include #include #include "User.hpp" #include "Artist.hpp" #include "Song.hpp" #include "Playlist.hpp" class MusicStreamingService { private: std::vector users; std::vector artists; std::vector songs; int playlistIdCounter; public: MusicStreamingService(); ~MusicStreamingService(); void addUser(User* user); void addArtist(Artist* artist); void addSong(Song* song, std::string artistId); Playlist* createPlaylist(std::string userId, std::string name, std::string description, bool isPublic = true); bool addSongToPlaylist(std::string playlistId, std::string songId); bool removeSongFromPlaylist(std::string playlistId, std::string songId); std::vector searchSongs(const std::string& query) const; std::vector searchArtists(const std::string& query) const; std::vector searchPlaylists(const std::string& query) const; void displayAllSongs() const; void displayAllArtists() const; void displayUserPlaylists(std::string userId) const; void displayArtistSongs(std::string artistId) const; private: User* findUser(const std::string& userId) const; Artist* findArtist(const std::string& artistId) const; Song* findSong(const std::string& songId) const; Playlist* findPlaylist(const std::string& playlistId) const; std::string generatePlaylistId(); }; #endif ================================================ FILE: solutions/cpp/musicstreamingservice/Playlist.cpp ================================================ #include "Playlist.hpp" #include #include #include Playlist::Playlist(std::string playlistId, std::string name, std::string description, bool isPublic) : playlistId(playlistId), name(name), description(description), isPublic(isPublic) {} std::string Playlist::getPlaylistId() const { return playlistId; } std::string Playlist::getName() const { return name; } std::string Playlist::getDescription() const { return description; } bool Playlist::getIsPublic() const { return isPublic; } const std::vector& Playlist::getSongs() const { return songs; } void Playlist::addSong(Song* song) { if (song && song->isActive()) { songs.push_back(song); } } void Playlist::removeSong(Song* song) { auto it = std::find(songs.begin(), songs.end(), song); if (it != songs.end()) { songs.erase(it); } } void Playlist::setPublic(bool isPublic) { this->isPublic = isPublic; } int Playlist::getTotalDuration() const { int total = 0; for (const auto& song : songs) { total += song->getDurationSeconds(); } return total; } void Playlist::displayInfo() const { std::cout << "\nPlaylist: " << name << " (ID: " << playlistId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Visibility: " << (isPublic ? "Public" : "Private") << std::endl; std::cout << "Number of Songs: " << songs.size() << std::endl; int totalDuration = getTotalDuration(); int minutes = totalDuration / 60; int seconds = totalDuration % 60; std::cout << "Total Duration: " << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; if (!songs.empty()) { std::cout << "\nSongs:" << std::endl; for (const auto& song : songs) { std::cout << "- " << song->getTitle() << " by " << song->getArtist() << std::endl; } } } ================================================ FILE: solutions/cpp/musicstreamingservice/Playlist.hpp ================================================ #ifndef PLAYLIST_HPP #define PLAYLIST_HPP #include #include #include "Song.hpp" class Playlist { private: std::string playlistId; std::string name; std::string description; std::vector songs; bool isPublic; public: Playlist(std::string playlistId, std::string name, std::string description, bool isPublic = true); std::string getPlaylistId() const; std::string getName() const; std::string getDescription() const; bool getIsPublic() const; const std::vector& getSongs() const; void addSong(Song* song); void removeSong(Song* song); void setPublic(bool isPublic); int getTotalDuration() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/musicstreamingservice/README.md ================================================ # Designing an Online Music Streaming Service Like Spotify ## Requirements 1. The music streaming service should allow users to browse and search for songs, albums, and artists. 2. Users should be able to create and manage playlists. 3. The system should support user authentication and authorization. 4. Users should be able to play, pause, skip, and seek within songs. 5. The system should recommend songs and playlists based on user preferences and listening history. 6. The system should handle concurrent requests and ensure smooth streaming experience for multiple users. 7. The system should be scalable and handle a large volume of songs and users. 8. The system should be extensible to support additional features such as social sharing and offline playback. ## Classes, Interfaces and Enumerations 1. The **Song**, **Album**, and **Artist** classes represent the basic entities in the music streaming service, with properties such as ID, title, artist, album, duration, and relationships between them. 2. The **User** class represents a user of the music streaming service, with properties like ID, username, password, and a list of playlists. 3. The **Playlist** class represents a user-created playlist, containing a list of songs. 4. The **MusicLibrary** class serves as a central repository for storing and managing songs, albums, and artists. It follows the Singleton pattern to ensure a single instance of the music library. 5. The **UserManager** class handles user registration, login, and other user-related operations. It also follows the Singleton pattern. 6. The **MusicPlayer** class represents the music playback functionality, allowing users to play, pause, skip, and seek within songs. 7. The **MusicRecommender** class generates song recommendations based on user preferences and listening history. It follows the Singleton pattern. 8. The **MusicStreamingService** class is the main entry point of the music streaming service. It initializes the necessary components, handles user requests, and manages the overall functionality of the service. ================================================ FILE: solutions/cpp/musicstreamingservice/Song.cpp ================================================ #include "Song.hpp" #include #include Song::Song(std::string songId, std::string title, std::string artist, std::string album, Genre genre, int durationSeconds, std::string filePath) : songId(songId), title(title), artist(artist), album(album), genre(genre), durationSeconds(durationSeconds), filePath(filePath), active(true) {} std::string Song::getSongId() const { return songId; } std::string Song::getTitle() const { return title; } std::string Song::getArtist() const { return artist; } std::string Song::getAlbum() const { return album; } Genre Song::getGenre() const { return genre; } int Song::getDurationSeconds() const { return durationSeconds; } std::string Song::getFilePath() const { return filePath; } bool Song::isActive() const { return active; } void Song::setActive(bool status) { active = status; } void Song::displayInfo() const { std::cout << "Song: " << title << " (ID: " << songId << ")" << std::endl; std::cout << "Artist: " << artist << std::endl; std::cout << "Album: " << album << std::endl; std::cout << "Genre: "; switch (genre) { case Genre::POP: std::cout << "Pop"; break; case Genre::ROCK: std::cout << "Rock"; break; case Genre::JAZZ: std::cout << "Jazz"; break; case Genre::CLASSICAL: std::cout << "Classical"; break; case Genre::HIPHOP: std::cout << "Hip Hop"; break; case Genre::ELECTRONIC: std::cout << "Electronic"; break; } std::cout << std::endl; int minutes = durationSeconds / 60; int seconds = durationSeconds % 60; std::cout << "Duration: " << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; } ================================================ FILE: solutions/cpp/musicstreamingservice/Song.hpp ================================================ #ifndef SONG_HPP #define SONG_HPP #include #include enum class Genre { POP, ROCK, JAZZ, CLASSICAL, HIPHOP, ELECTRONIC }; class Song { private: std::string songId; std::string title; std::string artist; std::string album; Genre genre; int durationSeconds; std::string filePath; bool active; public: Song(std::string songId, std::string title, std::string artist, std::string album, Genre genre, int durationSeconds, std::string filePath); std::string getSongId() const; std::string getTitle() const; std::string getArtist() const; std::string getAlbum() const; Genre getGenre() const; int getDurationSeconds() const; std::string getFilePath() const; bool isActive() const; void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/musicstreamingservice/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string username, std::string email, UserType type) : userId(userId), username(username), email(email), type(type), active(true) {} User::~User() { for (auto playlist : playlists) { delete playlist; } } std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } UserType User::getType() const { return type; } bool User::isActive() const { return active; } const std::vector& User::getPlaylists() const { return playlists; } void User::addPlaylist(Playlist* playlist) { playlists.push_back(playlist); } void User::removePlaylist(Playlist* playlist) { auto it = std::find(playlists.begin(), playlists.end(), playlist); if (it != playlists.end()) { delete *it; playlists.erase(it); } } void User::upgradeToPremuim() { type = UserType::PREMIUM; } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Type: " << (type == UserType::PREMIUM ? "Premium" : "Free") << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Number of Playlists: " << playlists.size() << std::endl; } ================================================ FILE: solutions/cpp/musicstreamingservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include "Playlist.hpp" enum class UserType { FREE, PREMIUM }; class User { private: std::string userId; std::string username; std::string email; UserType type; std::vector playlists; bool active; public: User(std::string userId, std::string username, std::string email, UserType type = UserType::FREE); ~User(); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; UserType getType() const; bool isActive() const; const std::vector& getPlaylists() const; void addPlaylist(Playlist* playlist); void removePlaylist(Playlist* playlist); void upgradeToPremuim(); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineauctionsystem/Auction.cpp ================================================ #include "Auction.hpp" #include #include Auction::Auction(std::string auctionId, Item* item, std::time_t startTime, std::time_t endTime) : auctionId(auctionId), item(item), startTime(startTime), endTime(endTime), currentPrice(item->getStartingPrice()), status(AuctionStatus::PENDING) {} std::string Auction::getAuctionId() const { return auctionId; } Item* Auction::getItem() const { return item; } std::time_t Auction::getStartTime() const { return startTime; } std::time_t Auction::getEndTime() const { return endTime; } double Auction::getCurrentPrice() const { return currentPrice; } AuctionStatus Auction::getStatus() const { return status; } std::string Auction::getWinnerId() const { return winnerId; } const std::vector& Auction::getBids() const { return bids; } bool Auction::placeBid(const std::string& bidderId, double amount) { if (status != AuctionStatus::ACTIVE || amount <= currentPrice) { return false; } bids.emplace_back(bidderId, amount); currentPrice = amount; winnerId = bidderId; return true; } void Auction::start() { if (status == AuctionStatus::PENDING) { status = AuctionStatus::ACTIVE; item->setStatus(ItemStatus::IN_AUCTION); } } void Auction::end() { if (status == AuctionStatus::ACTIVE) { status = AuctionStatus::ENDED; item->setStatus(ItemStatus::SOLD); } } void Auction::cancel() { status = AuctionStatus::CANCELLED; item->setStatus(ItemStatus::AVAILABLE); winnerId.clear(); } bool Auction::isActive() const { return status == AuctionStatus::ACTIVE; } void Auction::displayInfo() const { std::cout << "\nAuction Details:" << std::endl; std::cout << "Auction ID: " << auctionId << std::endl; item->displayInfo(); std::cout << "Start Time: " << std::ctime(&startTime); std::cout << "End Time: " << std::ctime(&endTime); std::cout << "Current Price: $" << std::fixed << std::setprecision(2) << currentPrice << std::endl; std::cout << "Status: "; switch (status) { case AuctionStatus::PENDING: std::cout << "Pending"; break; case AuctionStatus::ACTIVE: std::cout << "Active"; break; case AuctionStatus::ENDED: std::cout << "Ended"; break; case AuctionStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; if (!bids.empty()) { std::cout << "\nBid History:" << std::endl; for (const auto& bid : bids) { std::cout << "Bidder: " << bid.bidderId << ", Amount: $" << std::fixed << std::setprecision(2) << bid.amount << ", Time: " << std::ctime(&bid.timestamp); } } if (!winnerId.empty()) { std::cout << "Winner ID: " << winnerId << std::endl; } } ================================================ FILE: solutions/cpp/onlineauctionsystem/Auction.hpp ================================================ #ifndef AUCTION_HPP #define AUCTION_HPP #include #include #include #include "Item.hpp" #include "User.hpp" struct Bid { std::string bidderId; double amount; std::time_t timestamp; Bid(std::string bidderId, double amount) : bidderId(bidderId), amount(amount), timestamp(std::time(nullptr)) {} }; enum class AuctionStatus { PENDING, ACTIVE, ENDED, CANCELLED }; class Auction { private: std::string auctionId; Item* item; std::time_t startTime; std::time_t endTime; double currentPrice; std::vector bids; AuctionStatus status; std::string winnerId; public: Auction(std::string auctionId, Item* item, std::time_t startTime, std::time_t endTime); std::string getAuctionId() const; Item* getItem() const; std::time_t getStartTime() const; std::time_t getEndTime() const; double getCurrentPrice() const; AuctionStatus getStatus() const; std::string getWinnerId() const; const std::vector& getBids() const; bool placeBid(const std::string& bidderId, double amount); void start(); void end(); void cancel(); bool isActive() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineauctionsystem/AuctionSystem.cpp ================================================ #include "AuctionSystem.hpp" #include #include AuctionSystem::AuctionSystem() : itemIdCounter(1), auctionIdCounter(1) {} AuctionSystem::~AuctionSystem() { for (auto user : users) delete user; for (auto item : items) delete item; for (auto auction : auctions) delete auction; } User* AuctionSystem::registerUser(std::string username, std::string email) { std::string userId = "U" + std::to_string(users.size() + 1); User* user = new User(userId, username, email); users.push_back(user); return user; } Item* AuctionSystem::createItem(std::string sellerId, std::string name, std::string description, ItemCategory category, double startingPrice) { User* seller = findUser(sellerId); if (!seller || !seller->isActive()) return nullptr; Item* item = new Item(generateItemId(), name, description, category, startingPrice, sellerId); items.push_back(item); seller->addListedItem(item); return item; } Auction* AuctionSystem::createAuction(std::string itemId, std::time_t startTime, std::time_t endTime) { Item* item = findItem(itemId); if (!item || item->getStatus() != ItemStatus::AVAILABLE) return nullptr; Auction* auction = new Auction(generateAuctionId(), item, startTime, endTime); auctions.push_back(auction); return auction; } bool AuctionSystem::placeBid(std::string auctionId, std::string bidderId, double amount) { Auction* auction = findAuction(auctionId); User* bidder = findUser(bidderId); if (!auction || !bidder || !bidder->isActive() || !auction->isActive() || bidder->getBalance() < amount) { return false; } if (auction->placeBid(bidderId, amount)) { bidder->deductBalance(amount); return true; } return false; } bool AuctionSystem::addUserBalance(std::string userId, double amount) { User* user = findUser(userId); if (user && user->isActive()) { user->addBalance(amount); return true; } return false; } void AuctionSystem::startAuction(std::string auctionId) { Auction* auction = findAuction(auctionId); if (auction) auction->start(); } void AuctionSystem::endAuction(std::string auctionId) { Auction* auction = findAuction(auctionId); if (auction) { auction->end(); if (!auction->getWinnerId().empty()) { User* winner = findUser(auction->getWinnerId()); if (winner) { winner->addPurchasedItem(auction->getItem()); } } } } void AuctionSystem::cancelAuction(std::string auctionId) { Auction* auction = findAuction(auctionId); if (auction) auction->cancel(); } std::vector AuctionSystem::getActiveAuctions() const { std::vector activeAuctions; for (auto auction : auctions) { if (auction->isActive()) { activeAuctions.push_back(auction); } } return activeAuctions; } std::vector AuctionSystem::searchItems(const std::string& query) const { std::vector results; for (auto item : items) { if (item->getStatus() == ItemStatus::AVAILABLE && (item->getName().find(query) != std::string::npos || item->getDescription().find(query) != std::string::npos)) { results.push_back(item); } } return results; } void AuctionSystem::displayUserInfo(std::string userId) const { User* user = findUser(userId); if (user) user->displayInfo(); } void AuctionSystem::displayItemInfo(std::string itemId) const { Item* item = findItem(itemId); if (item) item->displayInfo(); } void AuctionSystem::displayAuctionInfo(std::string auctionId) const { Auction* auction = findAuction(auctionId); if (auction) auction->displayInfo(); } void AuctionSystem::displayAllAuctions() const { std::cout << "\nAll Auctions:" << std::endl; for (const auto& auction : auctions) { auction->displayInfo(); std::cout << "------------------------" << std::endl; } } User* AuctionSystem::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [&userId](const User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Item* AuctionSystem::findItem(const std::string& itemId) const { auto it = std::find_if(items.begin(), items.end(), [&itemId](const Item* item) { return item->getItemId() == itemId; }); return it != items.end() ? *it : nullptr; } Auction* AuctionSystem::findAuction(const std::string& auctionId) const { auto it = std::find_if(auctions.begin(), auctions.end(), [&auctionId](const Auction* auction) { return auction->getAuctionId() == auctionId; }); return it != auctions.end() ? *it : nullptr; } std::string AuctionSystem::generateItemId() { return "I" + std::to_string(itemIdCounter++); } std::string AuctionSystem::generateAuctionId() { return "A" + std::to_string(auctionIdCounter++); } ================================================ FILE: solutions/cpp/onlineauctionsystem/AuctionSystem.hpp ================================================ #ifndef AUCTION_SYSTEM_HPP #define AUCTION_SYSTEM_HPP #include #include #include "User.hpp" #include "Item.hpp" #include "Auction.hpp" class AuctionSystem { private: std::vector users; std::vector items; std::vector auctions; int itemIdCounter; int auctionIdCounter; public: AuctionSystem(); ~AuctionSystem(); User* registerUser(std::string username, std::string email); Item* createItem(std::string sellerId, std::string name, std::string description, ItemCategory category, double startingPrice); Auction* createAuction(std::string itemId, std::time_t startTime, std::time_t endTime); bool placeBid(std::string auctionId, std::string bidderId, double amount); bool addUserBalance(std::string userId, double amount); void startAuction(std::string auctionId); void endAuction(std::string auctionId); void cancelAuction(std::string auctionId); std::vector getActiveAuctions() const; std::vector searchItems(const std::string& query) const; void displayUserInfo(std::string userId) const; void displayItemInfo(std::string itemId) const; void displayAuctionInfo(std::string auctionId) const; void displayAllAuctions() const; private: User* findUser(const std::string& userId) const; Item* findItem(const std::string& itemId) const; Auction* findAuction(const std::string& auctionId) const; std::string generateItemId(); std::string generateAuctionId(); }; #endif ================================================ FILE: solutions/cpp/onlineauctionsystem/AuctionSystemDemo.cpp ================================================ #include "AuctionSystem.hpp" #include #include int main() { AuctionSystem system; // Register users User* seller = system.registerUser("john_seller", "john@email.com"); User* bidder1 = system.registerUser("alice_bidder", "alice@email.com"); User* bidder2 = system.registerUser("bob_bidder", "bob@email.com"); // Add balance to bidders system.addUserBalance(bidder1->getUserId(), 1000.0); system.addUserBalance(bidder2->getUserId(), 1500.0); std::cout << "Initial user balances:" << std::endl; system.displayUserInfo(bidder1->getUserId()); system.displayUserInfo(bidder2->getUserId()); // Create items Item* phone = system.createItem(seller->getUserId(), "Smartphone", "Latest model smartphone", ItemCategory::ELECTRONICS, 500.0); Item* watch = system.createItem(seller->getUserId(), "Luxury Watch", "Vintage luxury timepiece", ItemCategory::FASHION, 1000.0); if (phone && watch) { std::cout << "\nCreated items:" << std::endl; system.displayItemInfo(phone->getItemId()); system.displayItemInfo(watch->getItemId()); // Create auctions std::time_t now = std::time(nullptr); std::time_t oneHourLater = now + 3600; Auction* phoneAuction = system.createAuction(phone->getItemId(), now, oneHourLater); Auction* watchAuction = system.createAuction(watch->getItemId(), now, oneHourLater); if (phoneAuction && watchAuction) { // Start auctions system.startAuction(phoneAuction->getAuctionId()); system.startAuction(watchAuction->getAuctionId()); std::cout << "\nActive auctions:" << std::endl; system.displayAllAuctions(); // Place bids std::cout << "\nPlacing bids..." << std::endl; if (system.placeBid(phoneAuction->getAuctionId(), bidder1->getUserId(), 600.0)) { std::cout << "Bid placed successfully by " << bidder1->getUsername() << std::endl; } if (system.placeBid(phoneAuction->getAuctionId(), bidder2->getUserId(), 700.0)) { std::cout << "Bid placed successfully by " << bidder2->getUsername() << std::endl; } if (system.placeBid(watchAuction->getAuctionId(), bidder2->getUserId(), 1200.0)) { std::cout << "Bid placed successfully by " << bidder2->getUsername() << std::endl; } // Display auction status std::cout << "\nCurrent auction status:" << std::endl; system.displayAuctionInfo(phoneAuction->getAuctionId()); system.displayAuctionInfo(watchAuction->getAuctionId()); // End auctions std::cout << "\nEnding auctions..." << std::endl; system.endAuction(phoneAuction->getAuctionId()); system.endAuction(watchAuction->getAuctionId()); // Display final results std::cout << "\nFinal auction results:" << std::endl; system.displayAuctionInfo(phoneAuction->getAuctionId()); system.displayAuctionInfo(watchAuction->getAuctionId()); // Display updated user balances std::cout << "\nFinal user balances:" << std::endl; system.displayUserInfo(bidder1->getUserId()); system.displayUserInfo(bidder2->getUserId()); } } return 0; } ================================================ FILE: solutions/cpp/onlineauctionsystem/Item.cpp ================================================ #include "Item.hpp" #include #include Item::Item(std::string itemId, std::string name, std::string description, ItemCategory category, double startingPrice, std::string sellerId) : itemId(itemId), name(name), description(description), category(category), startingPrice(startingPrice), sellerId(sellerId), status(ItemStatus::AVAILABLE) {} std::string Item::getItemId() const { return itemId; } std::string Item::getName() const { return name; } std::string Item::getDescription() const { return description; } ItemCategory Item::getCategory() const { return category; } double Item::getStartingPrice() const { return startingPrice; } ItemStatus Item::getStatus() const { return status; } std::string Item::getSellerId() const { return sellerId; } void Item::setStatus(ItemStatus status) { this->status = status; } void Item::displayInfo() const { std::cout << "Item: " << name << " (ID: " << itemId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Category: "; switch (category) { case ItemCategory::ELECTRONICS: std::cout << "Electronics"; break; case ItemCategory::FASHION: std::cout << "Fashion"; break; case ItemCategory::HOME: std::cout << "Home"; break; case ItemCategory::SPORTS: std::cout << "Sports"; break; case ItemCategory::BOOKS: std::cout << "Books"; break; case ItemCategory::COLLECTIBLES: std::cout << "Collectibles"; break; case ItemCategory::OTHER: std::cout << "Other"; break; } std::cout << std::endl; std::cout << "Starting Price: $" << std::fixed << std::setprecision(2) << startingPrice << std::endl; std::cout << "Status: "; switch (status) { case ItemStatus::AVAILABLE: std::cout << "Available"; break; case ItemStatus::IN_AUCTION: std::cout << "In Auction"; break; case ItemStatus::SOLD: std::cout << "Sold"; break; case ItemStatus::WITHDRAWN: std::cout << "Withdrawn"; break; } std::cout << std::endl; std::cout << "Seller ID: " << sellerId << std::endl; } ================================================ FILE: solutions/cpp/onlineauctionsystem/Item.hpp ================================================ #ifndef ITEM_HPP #define ITEM_HPP #include enum class ItemCategory { ELECTRONICS, FASHION, HOME, SPORTS, BOOKS, COLLECTIBLES, OTHER }; enum class ItemStatus { AVAILABLE, IN_AUCTION, SOLD, WITHDRAWN }; class Item { private: std::string itemId; std::string name; std::string description; ItemCategory category; double startingPrice; ItemStatus status; std::string sellerId; public: Item(std::string itemId, std::string name, std::string description, ItemCategory category, double startingPrice, std::string sellerId); std::string getItemId() const; std::string getName() const; std::string getDescription() const; ItemCategory getCategory() const; double getStartingPrice() const; ItemStatus getStatus() const; std::string getSellerId() const; void setStatus(ItemStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineauctionsystem/README.md ================================================ # Designing an Online Auction System In this article, we delve into the object-oriented design and implementation of an Online Auction System using Java. This system allows for the creation and management of auctions, user participation in bidding, and handling transactions. ## Requirements 1. The online auction system should allow users to register and log in to their accounts. 2. Users should be able to create new auction listings with details such as item name, description, starting price, and auction duration. 3. Users should be able to browse and search for auction listings based on various criteria (e.g., item name, category, price range). 4. Users should be able to place bids on active auction listings. 5. The system should automatically update the current highest bid and notify the bidders accordingly. 6. The auction should end when the specified duration is reached, and the highest bidder should be declared the winner. 7. The system should handle concurrent access to auction listings and ensure data consistency. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online auction system, with properties such as id, username, and email. 2. The **AuctionStatus** enum defines the possible states of an auction listing, such as active and closed. 3. The **AuctionListing** class represents an auction listing in the system, with properties like id, item name, description, starting price, duration, seller, current highest bid, and a list of bids. 4. The **Bid** class represents a bid placed by a user on an auction listing, with properties such as id, bidder, amount, and timestamp. 5. The **AuctionSystem** class is the core of the online auction system and follows the Singleton pattern to ensure a single instance of the auction system. 6. The AuctionSystem class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to auction listings and ensure thread safety. 7. The AuctionSystem class provides methods for registering users, creating auction listings, searching auction listings, and placing bids. 8. The **AuctionSystemDemo** class serves as the entry point of the application and demonstrates the usage of the online auction system. ================================================ FILE: solutions/cpp/onlineauctionsystem/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string username, std::string email) : userId(userId), username(username), email(email), balance(0.0), active(true) {} User::~User() { // Note: Items are managed by the auction system listedItems.clear(); purchasedItems.clear(); } std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } double User::getBalance() const { return balance; } bool User::isActive() const { return active; } const std::vector& User::getListedItems() const { return listedItems; } const std::vector& User::getPurchasedItems() const { return purchasedItems; } void User::addBalance(double amount) { if (amount > 0) { balance += amount; } } bool User::deductBalance(double amount) { if (amount > 0 && balance >= amount) { balance -= amount; return true; } return false; } void User::addListedItem(Item* item) { listedItems.push_back(item); } void User::addPurchasedItem(Item* item) { purchasedItems.push_back(item); } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Balance: $" << std::fixed << std::setprecision(2) << balance << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Listed Items: " << listedItems.size() << std::endl; std::cout << "Purchased Items: " << purchasedItems.size() << std::endl; } ================================================ FILE: solutions/cpp/onlineauctionsystem/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include "Item.hpp" class User { private: std::string userId; std::string username; std::string email; double balance; std::vector listedItems; std::vector purchasedItems; bool active; public: User(std::string userId, std::string username, std::string email); ~User(); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; double getBalance() const; bool isActive() const; const std::vector& getListedItems() const; const std::vector& getPurchasedItems() const; void addBalance(double amount); bool deductBalance(double amount); void addListedItem(Item* item); void addPurchasedItem(Item* item); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/Cart.cpp ================================================ #include "Cart.hpp" #include #include #include Cart::Cart(User* user) : user(user), total(0.0) {} Cart::~Cart() { clear(); } User* Cart::getUser() const { return user; } const std::vector& Cart::getItems() const { return items; } double Cart::getTotal() const { return total; } bool Cart::addItem(Product* product, int quantity) { if (!product->isAvailable() || quantity <= 0 || quantity > product->getStockQuantity()) { return false; } // Check if product already exists in cart for (auto item : items) { if (item->getProduct() == product) { return updateItemQuantity(product, item->getQuantity() + quantity); } } items.push_back(new CartItem(product, quantity)); calculateTotal(); return true; } bool Cart::updateItemQuantity(Product* product, int quantity) { if (quantity <= 0 || quantity > product->getStockQuantity()) { return false; } for (auto item : items) { if (item->getProduct() == product) { item->setQuantity(quantity); calculateTotal(); return true; } } return false; } bool Cart::removeItem(Product* product) { auto it = std::find_if(items.begin(), items.end(), [product](CartItem* item) { return item->getProduct() == product; }); if (it != items.end()) { delete *it; items.erase(it); calculateTotal(); return true; } return false; } void Cart::clear() { for (auto item : items) { delete item; } items.clear(); total = 0.0; } void Cart::calculateTotal() { total = 0.0; for (const auto& item : items) { total += item->getSubtotal(); } } void Cart::displayInfo() const { std::cout << "\nShopping Cart for " << user->getUsername() << ":" << std::endl; std::cout << "Items:" << std::endl; for (const auto& item : items) { item->displayInfo(); } std::cout << "------------------------" << std::endl; std::cout << "Total: $" << std::fixed << std::setprecision(2) << total << std::endl; } ================================================ FILE: solutions/cpp/onlineshoppingservice/Cart.hpp ================================================ #ifndef CART_HPP #define CART_HPP #include #include "CartItem.hpp" #include "User.hpp" class Cart { private: User* user; std::vector items; double total; public: Cart(User* user); ~Cart(); User* getUser() const; const std::vector& getItems() const; double getTotal() const; bool addItem(Product* product, int quantity); bool updateItemQuantity(Product* product, int quantity); bool removeItem(Product* product); void clear(); void calculateTotal(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/CartItem.cpp ================================================ #include "CartItem.hpp" #include #include CartItem::CartItem(Product* product, int quantity) : product(product), quantity(quantity) {} Product* CartItem::getProduct() const { return product; } int CartItem::getQuantity() const { return quantity; } double CartItem::getSubtotal() const { return product->getPrice() * quantity; } void CartItem::setQuantity(int quantity) { if (quantity > 0) { this->quantity = quantity; } } void CartItem::displayInfo() const { std::cout << product->getName() << " x " << quantity << " = $" << std::fixed << std::setprecision(2) << getSubtotal() << std::endl; } ================================================ FILE: solutions/cpp/onlineshoppingservice/CartItem.hpp ================================================ #ifndef CART_ITEM_HPP #define CART_ITEM_HPP #include "Product.hpp" class CartItem { private: Product* product; int quantity; public: CartItem(Product* product, int quantity); Product* getProduct() const; int getQuantity() const; double getSubtotal() const; void setQuantity(int quantity); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/Order.cpp ================================================ #include "Order.hpp" #include #include Order::Order(std::string orderId, User* user, const std::vector& cartItems) : orderId(orderId), user(user), status(OrderStatus::PENDING), totalAmount(0.0) { // Deep copy cart items for (const auto& cartItem : cartItems) { items.push_back(new CartItem(cartItem->getProduct(), cartItem->getQuantity())); totalAmount += cartItem->getSubtotal(); } // Set order date to current time orderDate = std::time(nullptr); } Order::~Order() { for (auto item : items) { delete item; } } std::string Order::getOrderId() const { return orderId; } User* Order::getUser() const { return user; } const std::vector& Order::getItems() const { return items; } double Order::getTotalAmount() const { return totalAmount; } std::time_t Order::getOrderDate() const { return orderDate; } OrderStatus Order::getStatus() const { return status; } void Order::setStatus(OrderStatus status) { this->status = status; } void Order::displayInfo() const { std::cout << "\nOrder Details:" << std::endl; std::cout << "Order ID: " << orderId << std::endl; std::cout << "Customer: " << user->getUsername() << std::endl; std::cout << "Date: " << std::ctime(&orderDate); std::cout << "Status: "; switch (status) { case OrderStatus::PENDING: std::cout << "Pending"; break; case OrderStatus::CONFIRMED: std::cout << "Confirmed"; break; case OrderStatus::SHIPPED: std::cout << "Shipped"; break; case OrderStatus::DELIVERED: std::cout << "Delivered"; break; case OrderStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; std::cout << "\nItems:" << std::endl; for (const auto& item : items) { item->displayInfo(); } std::cout << "------------------------" << std::endl; std::cout << "Total Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; } ================================================ FILE: solutions/cpp/onlineshoppingservice/Order.hpp ================================================ #ifndef ORDER_HPP #define ORDER_HPP #include #include #include #include "CartItem.hpp" enum class OrderStatus { PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED }; class Order { private: std::string orderId; User* user; std::vector items; double totalAmount; std::time_t orderDate; OrderStatus status; public: Order(std::string orderId, User* user, const std::vector& items); ~Order(); std::string getOrderId() const; User* getUser() const; const std::vector& getItems() const; double getTotalAmount() const; std::time_t getOrderDate() const; OrderStatus getStatus() const; void setStatus(OrderStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/Product.cpp ================================================ #include "Product.hpp" #include #include Product::Product(std::string productId, std::string name, std::string description, double price, int stockQuantity) : productId(productId), name(name), description(description), price(price), stockQuantity(stockQuantity), available(true) {} std::string Product::getProductId() const { return productId; } std::string Product::getName() const { return name; } std::string Product::getDescription() const { return description; } double Product::getPrice() const { return price; } int Product::getStockQuantity() const { return stockQuantity; } bool Product::isAvailable() const { return available; } void Product::setPrice(double newPrice) { if (newPrice >= 0) { price = newPrice; } } void Product::setStockQuantity(int quantity) { if (quantity >= 0) { stockQuantity = quantity; available = (quantity > 0); } } void Product::setAvailable(bool status) { available = status; } bool Product::updateStock(int quantity) { if (stockQuantity + quantity >= 0) { stockQuantity += quantity; available = (stockQuantity > 0); return true; } return false; } void Product::displayInfo() const { std::cout << "Product: " << name << " (ID: " << productId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Price: $" << std::fixed << std::setprecision(2) << price << std::endl; std::cout << "Stock: " << stockQuantity << std::endl; std::cout << "Status: " << (available ? "Available" : "Out of Stock") << std::endl; } ================================================ FILE: solutions/cpp/onlineshoppingservice/Product.hpp ================================================ #ifndef PRODUCT_HPP #define PRODUCT_HPP #include class Product { private: std::string productId; std::string name; std::string description; double price; int stockQuantity; bool available; public: Product(std::string productId, std::string name, std::string description, double price, int stockQuantity); std::string getProductId() const; std::string getName() const; std::string getDescription() const; double getPrice() const; int getStockQuantity() const; bool isAvailable() const; void setPrice(double newPrice); void setStockQuantity(int quantity); void setAvailable(bool status); bool updateStock(int quantity); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/README.md ================================================ # Designing an Online Shopping System Like Amazon ## Requirements 1. The online shopping service should allow users to browse products, add them to the shopping cart, and place orders. 2. The system should support multiple product categories and provide search functionality. 3. Users should be able to manage their profiles, view order history, and track order status. 4. The system should handle inventory management and update product availability accordingly. 5. The system should support multiple payment methods and ensure secure transactions. 6. The system should handle concurrent user requests and ensure data consistency. 7. The system should be scalable to handle a large number of products and users. 8. The system should provide a user-friendly interface for a seamless shopping experience. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online shopping service, with properties such as ID, name, email, password, and a list of orders. 2. The **Product** class represents a product available for purchase, with properties like ID, name, description, price, and quantity. It provides methods to update the quantity and check product availability. 3. The **Order** class represents an order placed by a user, containing properties such as ID, user, order items, total amount, and order status. It calculates the total amount based on the order items. 4. The **OrderItem** class represents an item within an order, consisting of the product and the quantity ordered. 5. The **OrderStatus** enum represents the different statuses an order can have, such as pending, processing, shipped, delivered, or cancelled. 6. The **ShoppingCart** class represents the user's shopping cart, allowing them to add, remove, and update item quantities. It maintains a map of product IDs and order items. 7. The **Payment** interface defines the contract for processing payments, with a concrete implementation CreditCardPayment. 8. The **OnlineShoppingService** class is the central component of the online shopping service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register users, add products, search products, place orders, and retrieve order information. It handles concurrent access to shared resources using synchronization. 9. The **OnlineShoppingServiceDemo** class demonstrates the usage of the online shopping service by registering users, adding products, searching for products, placing orders, and viewing order history. ================================================ FILE: solutions/cpp/onlineshoppingservice/ShoppingDemo.cpp ================================================ #include "ShoppingSystem.hpp" #include int main() { ShoppingSystem shop; // Add products Product* laptop = shop.addProduct("Laptop", "High-performance laptop", 999.99, 10); Product* phone = shop.addProduct("Smartphone", "Latest model smartphone", 599.99, 20); Product* tablet = shop.addProduct("Tablet", "10-inch tablet", 299.99, 15); std::cout << "Initial Products:" << std::endl; shop.displayProducts(); // Register users User* user1 = shop.registerUser("john_doe", "john@email.com", "123 Main St"); User* user2 = shop.registerUser("jane_smith", "jane@email.com", "456 Oak Ave"); std::cout << "\nRegistered Users:" << std::endl; shop.displayUsers(); // Add items to cart std::cout << "\nAdding items to John's cart..." << std::endl; shop.addToCart(user1->getUserId(), laptop->getProductId(), 1); shop.addToCart(user1->getUserId(), phone->getProductId(), 2); shop.displayCart(user1->getUserId()); // Update cart std::cout << "\nUpdating phone quantity..." << std::endl; shop.updateCartItem(user1->getUserId(), phone->getProductId(), 1); shop.displayCart(user1->getUserId()); // Place order std::cout << "\nPlacing order..." << std::endl; Order* order = shop.placeOrder(user1->getUserId()); if (order) { std::cout << "Order placed successfully!" << std::endl; order->displayInfo(); // Update order status shop.updateOrderStatus(order->getOrderId(), OrderStatus::CONFIRMED); shop.updateOrderStatus(order->getOrderId(), OrderStatus::SHIPPED); std::cout << "\nUpdated order status:" << std::endl; order->displayInfo(); } // Check updated product stock std::cout << "\nUpdated product stock:" << std::endl; shop.displayProducts(); return 0; } ================================================ FILE: solutions/cpp/onlineshoppingservice/ShoppingSystem.cpp ================================================ #include "ShoppingSystem.hpp" #include #include ShoppingSystem::ShoppingSystem() : orderIdCounter(1) {} ShoppingSystem::~ShoppingSystem() { for (auto user : users) delete user; for (auto product : products) delete product; for (auto order : orders) delete order; for (auto& pair : userCarts) delete pair.second; } User* ShoppingSystem::registerUser(const std::string& username, const std::string& email, const std::string& address) { std::string userId = "U" + std::to_string(users.size() + 1); User* user = new User(userId, username, email, address); users.push_back(user); return user; } void ShoppingSystem::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { delete *it; users.erase(it); // Remove user's cart auto cartIt = userCarts.find(userId); if (cartIt != userCarts.end()) { delete cartIt->second; userCarts.erase(cartIt); } } } Product* ShoppingSystem::addProduct(const std::string& name, const std::string& description, double price, int stockQuantity) { std::string productId = "P" + std::to_string(products.size() + 1); Product* product = new Product(productId, name, description, price, stockQuantity); products.push_back(product); return product; } void ShoppingSystem::removeProduct(const std::string& productId) { auto it = std::find_if(products.begin(), products.end(), [productId](Product* product) { return product->getProductId() == productId; }); if (it != products.end()) { delete *it; products.erase(it); } } void ShoppingSystem::updateProductStock(const std::string& productId, int quantity) { if (Product* product = findProduct(productId)) { product->updateStock(quantity); } } bool ShoppingSystem::addToCart(const std::string& userId, const std::string& productId, int quantity) { User* user = findUser(userId); Product* product = findProduct(productId); if (!user || !product) return false; Cart* cart = getCart(userId); return cart->addItem(product, quantity); } bool ShoppingSystem::updateCartItem(const std::string& userId, const std::string& productId, int quantity) { User* user = findUser(userId); Product* product = findProduct(productId); if (!user || !product) return false; Cart* cart = getCart(userId); return cart->updateItemQuantity(product, quantity); } bool ShoppingSystem::removeFromCart(const std::string& userId, const std::string& productId) { User* user = findUser(userId); Product* product = findProduct(productId); if (!user || !product) return false; Cart* cart = getCart(userId); return cart->removeItem(product); } void ShoppingSystem::clearCart(const std::string& userId) { if (Cart* cart = getCart(userId)) { cart->clear(); } } Order* ShoppingSystem::placeOrder(const std::string& userId) { User* user = findUser(userId); Cart* cart = getCart(userId); if (!user || !cart || cart->getItems().empty()) return nullptr; // Check stock availability and update stock for (const auto& item : cart->getItems()) { Product* product = item->getProduct(); if (!product->updateStock(-item->getQuantity())) { return nullptr; } } // Create order std::string orderId = generateOrderId(); Order* order = new Order(orderId, user, cart->getItems()); orders.push_back(order); user->addOrder(order); // Clear cart after successful order cart->clear(); return order; } bool ShoppingSystem::updateOrderStatus(const std::string& orderId, OrderStatus status) { if (Order* order = findOrder(orderId)) { order->setStatus(status); return true; } return false; } void ShoppingSystem::displayProducts() const { std::cout << "\nAvailable Products:" << std::endl; for (const auto& product : products) { product->displayInfo(); std::cout << "------------------------" << std::endl; } } void ShoppingSystem::displayUsers() const { std::cout << "\nRegistered Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void ShoppingSystem::displayCart(const std::string& userId) const { auto it = userCarts.find(userId); if (it != userCarts.end()) { it->second->displayInfo(); } } void ShoppingSystem::displayOrders(const std::string& userId) const { if (User* user = findUser(userId)) { user->displayOrders(); } } void ShoppingSystem::displayAllOrders() const { std::cout << "\nAll Orders:" << std::endl; for (const auto& order : orders) { order->displayInfo(); std::cout << "------------------------" << std::endl; } } User* ShoppingSystem::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Product* ShoppingSystem::findProduct(const std::string& productId) const { auto it = std::find_if(products.begin(), products.end(), [productId](Product* product) { return product->getProductId() == productId; }); return it != products.end() ? *it : nullptr; } Order* ShoppingSystem::findOrder(const std::string& orderId) const { auto it = std::find_if(orders.begin(), orders.end(), [orderId](Order* order) { return order->getOrderId() == orderId; }); return it != orders.end() ? *it : nullptr; } Cart* ShoppingSystem::getCart(const std::string& userId) { auto it = userCarts.find(userId); if (it == userCarts.end()) { User* user = findUser(userId); if (!user) return nullptr; Cart* cart = new Cart(user); userCarts[userId] = cart; return cart; } return it->second; } std::string ShoppingSystem::generateOrderId() { return "O" + std::to_string(orderIdCounter++); } ================================================ FILE: solutions/cpp/onlineshoppingservice/ShoppingSystem.hpp ================================================ #ifndef SHOPPING_SYSTEM_HPP #define SHOPPING_SYSTEM_HPP #include #include #include #include "User.hpp" #include "Product.hpp" #include "Cart.hpp" #include "Order.hpp" class ShoppingSystem { private: std::vector users; std::vector products; std::vector orders; std::map userCarts; int orderIdCounter; public: ShoppingSystem(); ~ShoppingSystem(); // User management User* registerUser(const std::string& username, const std::string& email, const std::string& address); void removeUser(const std::string& userId); // Product management Product* addProduct(const std::string& name, const std::string& description, double price, int stockQuantity); void removeProduct(const std::string& productId); void updateProductStock(const std::string& productId, int quantity); // Cart operations bool addToCart(const std::string& userId, const std::string& productId, int quantity); bool updateCartItem(const std::string& userId, const std::string& productId, int quantity); bool removeFromCart(const std::string& userId, const std::string& productId); void clearCart(const std::string& userId); // Order operations Order* placeOrder(const std::string& userId); bool updateOrderStatus(const std::string& orderId, OrderStatus status); // Display functions void displayProducts() const; void displayUsers() const; void displayCart(const std::string& userId) const; void displayOrders(const std::string& userId) const; void displayAllOrders() const; private: User* findUser(const std::string& userId) const; Product* findProduct(const std::string& productId) const; Order* findOrder(const std::string& orderId) const; Cart* getCart(const std::string& userId); std::string generateOrderId(); }; #endif ================================================ FILE: solutions/cpp/onlineshoppingservice/User.cpp ================================================ #include "User.hpp" #include User::User(std::string userId, std::string username, std::string email, std::string address) : userId(userId), username(username), email(email), address(address), active(true) {} User::~User() { for (auto order : orders) { delete order; } } std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } std::string User::getAddress() const { return address; } bool User::isActive() const { return active; } const std::vector& User::getOrders() const { return orders; } void User::addOrder(Order* order) { orders.push_back(order); } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Address: " << address << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Total Orders: " << orders.size() << std::endl; } void User::displayOrders() const { std::cout << "\nOrder History for " << username << ":" << std::endl; for (const auto& order : orders) { order->displayInfo(); std::cout << "------------------------" << std::endl; } } ================================================ FILE: solutions/cpp/onlineshoppingservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include "Order.hpp" class User { private: std::string userId; std::string username; std::string email; std::string address; std::vector orders; bool active; public: User(std::string userId, std::string username, std::string email, std::string address); ~User(); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; std::string getAddress() const; bool isActive() const; const std::vector& getOrders() const; void addOrder(Order* order); void setActive(bool status); void displayInfo() const; void displayOrders() const; }; #endif ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/BrokerageDemo.cpp ================================================ #include "BrokerageSystem.hpp" #include int main() { BrokerageSystem brokerage; // Add stocks Stock* apple = brokerage.addStock("AAPL", "Apple Inc.", 150.0, 1000); Stock* google = brokerage.addStock("GOOGL", "Alphabet Inc.", 2800.0, 500); Stock* amazon = brokerage.addStock("AMZN", "Amazon.com Inc.", 3300.0, 300); std::cout << "Initial Stocks:" << std::endl; brokerage.displayStocks(); // Register users User* user1 = brokerage.registerUser("john_trader", "john@email.com"); User* user2 = brokerage.registerUser("jane_investor", "jane@email.com"); // Deposit funds brokerage.deposit(user1->getUserId(), 10000.0); brokerage.deposit(user2->getUserId(), 15000.0); std::cout << "\nUsers after deposit:" << std::endl; brokerage.displayUsers(); // Perform transactions Transaction* trans1 = brokerage.buyStock(user1->getUserId(), "AAPL", 10); if (trans1) { std::cout << "\nBuy Transaction:" << std::endl; trans1->displayInfo(); } // Update stock price brokerage.updateStockPrice("AAPL", 155.0); Transaction* trans2 = brokerage.sellStock(user1->getUserId(), "AAPL", 5); if (trans2) { std::cout << "\nSell Transaction:" << std::endl; trans2->displayInfo(); } // Display final state std::cout << "\nFinal Portfolio for John:" << std::endl; brokerage.displayUserPortfolio(user1->getUserId()); std::cout << "\nTransaction History for John:" << std::endl; brokerage.displayTransactionHistory(user1->getUserId()); return 0; } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/BrokerageSystem.cpp ================================================ #include "BrokerageSystem.hpp" #include #include BrokerageSystem::BrokerageSystem() : transactionIdCounter(1) {} BrokerageSystem::~BrokerageSystem() { for (auto user : users) delete user; for (auto& pair : stocks) delete pair.second; for (auto transaction : transactions) delete transaction; } User* BrokerageSystem::registerUser(const std::string& username, const std::string& email) { std::string userId = "U" + std::to_string(users.size() + 1); User* user = new User(userId, username, email); users.push_back(user); return user; } void BrokerageSystem::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { delete *it; users.erase(it); } } Stock* BrokerageSystem::addStock(const std::string& symbol, const std::string& companyName, double price, int shares) { Stock* stock = new Stock(symbol, companyName, price, shares); stocks[symbol] = stock; return stock; } void BrokerageSystem::updateStockPrice(const std::string& symbol, double newPrice) { if (Stock* stock = findStock(symbol)) { stock->setCurrentPrice(newPrice); updatePortfolioValues(); } } bool BrokerageSystem::deposit(const std::string& userId, double amount) { if (User* user = findUser(userId)) { return user->deposit(amount); } return false; } bool BrokerageSystem::withdraw(const std::string& userId, double amount) { if (User* user = findUser(userId)) { return user->withdraw(amount); } return false; } Transaction* BrokerageSystem::buyStock(const std::string& userId, const std::string& symbol, int quantity) { User* user = findUser(userId); Stock* stock = findStock(symbol); if (!user || !stock || !stock->isActive()) return nullptr; double totalCost = stock->getCurrentPrice() * quantity; if (user->getBalance() < totalCost || stock->getAvailableShares() < quantity) { return nullptr; } // Process transaction user->withdraw(totalCost); stock->updateShares(-quantity); user->getPortfolio()->addShares(symbol, quantity); // Create transaction record Transaction* transaction = new Transaction(generateTransactionId(), user, stock, TransactionType::BUY, quantity, stock->getCurrentPrice()); transactions.push_back(transaction); updatePortfolioValues(); return transaction; } Transaction* BrokerageSystem::sellStock(const std::string& userId, const std::string& symbol, int quantity) { User* user = findUser(userId); Stock* stock = findStock(symbol); if (!user || !stock || !stock->isActive()) return nullptr; Portfolio* portfolio = user->getPortfolio(); if (portfolio->getShareQuantity(symbol) < quantity) { return nullptr; } // Process transaction double totalAmount = stock->getCurrentPrice() * quantity; user->deposit(totalAmount); stock->updateShares(quantity); portfolio->removeShares(symbol, quantity); // Create transaction record Transaction* transaction = new Transaction(generateTransactionId(), user, stock, TransactionType::SELL, quantity, stock->getCurrentPrice()); transactions.push_back(transaction); updatePortfolioValues(); return transaction; } void BrokerageSystem::displayStocks() const { std::cout << "\nAvailable Stocks:" << std::endl; for (const auto& pair : stocks) { pair.second->displayInfo(); std::cout << "------------------------" << std::endl; } } void BrokerageSystem::displayUsers() const { std::cout << "\nRegistered Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void BrokerageSystem::displayUserPortfolio(const std::string& userId) const { if (User* user = findUser(userId)) { user->getPortfolio()->displayInfo(); } } void BrokerageSystem::displayTransactionHistory(const std::string& userId) const { std::cout << "\nTransaction History:" << std::endl; for (const auto& transaction : transactions) { if (transaction->getUser()->getUserId() == userId) { transaction->displayInfo(); std::cout << "------------------------" << std::endl; } } } User* BrokerageSystem::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Stock* BrokerageSystem::findStock(const std::string& symbol) const { auto it = stocks.find(symbol); return it != stocks.end() ? it->second : nullptr; } void BrokerageSystem::updatePortfolioValues() { for (auto user : users) { user->getPortfolio()->updateTotalValue(stocks); } } std::string BrokerageSystem::generateTransactionId() { return "T" + std::to_string(transactionIdCounter++); } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/BrokerageSystem.hpp ================================================ #ifndef BROKERAGE_SYSTEM_HPP #define BROKERAGE_SYSTEM_HPP #include #include #include #include "User.hpp" #include "Stock.hpp" #include "Transaction.hpp" class BrokerageSystem { private: std::vector users; std::map stocks; // symbol -> Stock* std::vector transactions; int transactionIdCounter; public: BrokerageSystem(); ~BrokerageSystem(); // User management User* registerUser(const std::string& username, const std::string& email); void removeUser(const std::string& userId); // Stock management Stock* addStock(const std::string& symbol, const std::string& companyName, double price, int shares); void updateStockPrice(const std::string& symbol, double newPrice); // Trading operations bool deposit(const std::string& userId, double amount); bool withdraw(const std::string& userId, double amount); Transaction* buyStock(const std::string& userId, const std::string& symbol, int quantity); Transaction* sellStock(const std::string& userId, const std::string& symbol, int quantity); // Display functions void displayStocks() const; void displayUsers() const; void displayUserPortfolio(const std::string& userId) const; void displayTransactionHistory(const std::string& userId) const; private: User* findUser(const std::string& userId) const; Stock* findStock(const std::string& symbol) const; void updatePortfolioValues(); std::string generateTransactionId(); }; #endif ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Portfolio.cpp ================================================ #include "Portfolio.hpp" #include #include Portfolio::Portfolio(std::string userId) : userId(userId), totalValue(0.0) {} std::string Portfolio::getUserId() const { return userId; } const std::map& Portfolio::getHoldings() const { return holdings; } double Portfolio::getTotalValue() const { return totalValue; } int Portfolio::getShareQuantity(const std::string& symbol) const { auto it = holdings.find(symbol); return it != holdings.end() ? it->second : 0; } void Portfolio::addShares(const std::string& symbol, int quantity) { if (quantity > 0) { holdings[symbol] += quantity; } } bool Portfolio::removeShares(const std::string& symbol, int quantity) { auto it = holdings.find(symbol); if (it != holdings.end() && it->second >= quantity) { it->second -= quantity; if (it->second == 0) { holdings.erase(it); } return true; } return false; } void Portfolio::updateTotalValue(const std::map& stocks) { totalValue = 0.0; for (const auto& holding : holdings) { auto stockIt = stocks.find(holding.first); if (stockIt != stocks.end()) { totalValue += stockIt->second->getCurrentPrice() * holding.second; } } } void Portfolio::displayInfo() const { std::cout << "\nPortfolio Holdings:" << std::endl; if (holdings.empty()) { std::cout << "No holdings" << std::endl; } else { for (const auto& holding : holdings) { std::cout << holding.first << ": " << holding.second << " shares" << std::endl; } } std::cout << "Total Value: $" << std::fixed << std::setprecision(2) << totalValue << std::endl; } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Portfolio.hpp ================================================ #ifndef PORTFOLIO_HPP #define PORTFOLIO_HPP #include #include #include "Stock.hpp" class Portfolio { private: std::string userId; std::map holdings; // symbol -> quantity double totalValue; public: Portfolio(std::string userId); std::string getUserId() const; const std::map& getHoldings() const; double getTotalValue() const; int getShareQuantity(const std::string& symbol) const; void addShares(const std::string& symbol, int quantity); bool removeShares(const std::string& symbol, int quantity); void updateTotalValue(const std::map& stocks); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/README.md ================================================ # Designing an Online Stock Brokerage System ## Requirements 1. The online stock brokerage system should allow users to create and manage their trading accounts. 2. Users should be able to buy and sell stocks, as well as view their portfolio and transaction history. 3. The system should provide real-time stock quotes and market data to users. 4. The system should handle order placement, execution, and settlement processes. 5. The system should enforce various business rules and validations, such as checking account balances and stock availability. 6. The system should handle concurrent user requests and ensure data consistency and integrity. 7. The system should be scalable and able to handle a large number of users and transactions. 8. The system should be secure and protect sensitive user information. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the stock brokerage system, with properties such as user ID, name, and email. 2. The **Account** class represents a user's trading account, with properties like account ID, associated user, and balance. It provides methods for depositing and withdrawing funds. 3. The **Stock** class represents a stock that can be traded, with properties such as symbol, name, and price. It provides a method for updating the stock price. 4. The **Order** class is an abstract base class representing an order placed by a user. It contains common properties such as order ID, associated account, stock, quantity, price, and order status. The execute() method is declared as abstract, to be implemented by concrete order classes. 5. The **BuyOrder** and **SellOrder** classes are concrete implementations of the Order class, representing buy and sell orders respectively. They provide the implementation for the execute() method specific to each order type. 6. The **OrderStatus** enum represents the possible statuses of an order, such as PENDING, EXECUTED, or REJECTED. 7. The **Portfolio** class represents a user's portfolio, which holds the stocks owned by the user. It provides methods for adding and removing stocks from the portfolio. 8. The **StockBroker** class is the central component of the stock brokerage system. It follows the Singleton pattern to ensure a single instance of the stock broker. It manages user accounts, stocks, and order processing. It provides methods for creating accounts, adding stocks, placing orders, and processing orders. 9. The **InsufficientFundsException** and **InsufficientStockException** classes are custom exceptions used to handle insufficient funds and insufficient stock scenarios respectively. 10. The **StockBrokerageSystem** class serves as the entry point of the application and demonstrates the usage of the stock brokerage system. ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Stock.cpp ================================================ #include "Stock.hpp" #include #include Stock::Stock(std::string symbol, std::string companyName, double currentPrice, int availableShares) : symbol(symbol), companyName(companyName), currentPrice(currentPrice), availableShares(availableShares), active(true) {} std::string Stock::getSymbol() const { return symbol; } std::string Stock::getCompanyName() const { return companyName; } double Stock::getCurrentPrice() const { return currentPrice; } int Stock::getAvailableShares() const { return availableShares; } bool Stock::isActive() const { return active; } void Stock::setCurrentPrice(double price) { if (price > 0) { currentPrice = price; } } void Stock::updateShares(int quantity) { if (availableShares + quantity >= 0) { availableShares += quantity; active = (availableShares > 0); } } void Stock::setActive(bool status) { active = status; } void Stock::displayInfo() const { std::cout << "Stock: " << companyName << " (" << symbol << ")" << std::endl; std::cout << "Current Price: $" << std::fixed << std::setprecision(2) << currentPrice << std::endl; std::cout << "Available Shares: " << availableShares << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Stock.hpp ================================================ #ifndef STOCK_HPP #define STOCK_HPP #include class Stock { private: std::string symbol; std::string companyName; double currentPrice; int availableShares; bool active; public: Stock(std::string symbol, std::string companyName, double currentPrice, int availableShares); std::string getSymbol() const; std::string getCompanyName() const; double getCurrentPrice() const; int getAvailableShares() const; bool isActive() const; void setCurrentPrice(double price); void updateShares(int quantity); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Transaction.cpp ================================================ #include "Transaction.hpp" #include #include Transaction::Transaction(std::string transactionId, User* user, Stock* stock, TransactionType type, int quantity, double pricePerShare) : transactionId(transactionId), user(user), stock(stock), type(type), quantity(quantity), pricePerShare(pricePerShare) { totalAmount = quantity * pricePerShare; timestamp = std::time(nullptr); } std::string Transaction::getTransactionId() const { return transactionId; } User* Transaction::getUser() const { return user; } Stock* Transaction::getStock() const { return stock; } TransactionType Transaction::getType() const { return type; } int Transaction::getQuantity() const { return quantity; } double Transaction::getPricePerShare() const { return pricePerShare; } double Transaction::getTotalAmount() const { return totalAmount; } std::time_t Transaction::getTimestamp() const { return timestamp; } void Transaction::displayInfo() const { std::cout << "\nTransaction Details:" << std::endl; std::cout << "ID: " << transactionId << std::endl; std::cout << "Type: " << (type == TransactionType::BUY ? "Buy" : "Sell") << std::endl; std::cout << "Stock: " << stock->getSymbol() << std::endl; std::cout << "Quantity: " << quantity << std::endl; std::cout << "Price per Share: $" << std::fixed << std::setprecision(2) << pricePerShare << std::endl; std::cout << "Total Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; std::cout << "Time: " << std::ctime(×tamp); } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/Transaction.hpp ================================================ #ifndef TRANSACTION_HPP #define TRANSACTION_HPP #include #include #include "Stock.hpp" #include "User.hpp" enum class TransactionType { BUY, SELL }; class Transaction { private: std::string transactionId; User* user; Stock* stock; TransactionType type; int quantity; double pricePerShare; double totalAmount; std::time_t timestamp; public: Transaction(std::string transactionId, User* user, Stock* stock, TransactionType type, int quantity, double pricePerShare); std::string getTransactionId() const; User* getUser() const; Stock* getStock() const; TransactionType getType() const; int getQuantity() const; double getPricePerShare() const; double getTotalAmount() const; std::time_t getTimestamp() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string username, std::string email) : userId(userId), username(username), email(email), balance(0.0), active(true) { portfolio = new Portfolio(userId); } User::~User() { delete portfolio; } std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } double User::getBalance() const { return balance; } Portfolio* User::getPortfolio() const { return portfolio; } bool User::isActive() const { return active; } bool User::deposit(double amount) { if (amount > 0) { balance += amount; return true; } return false; } bool User::withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; return true; } return false; } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Balance: $" << std::fixed << std::setprecision(2) << balance << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; portfolio->displayInfo(); } ================================================ FILE: solutions/cpp/onlinestockbrokeragesystem/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include "Portfolio.hpp" class User { private: std::string userId; std::string username; std::string email; double balance; Portfolio* portfolio; bool active; public: User(std::string userId, std::string username, std::string email); ~User(); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; double getBalance() const; Portfolio* getPortfolio() const; bool isActive() const; bool deposit(double amount); bool withdraw(double amount); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/parkinglot/ParkingLot.cpp ================================================ #include "ParkingLot.hpp" #include ParkingLot::ParkingLot(int numCompact, int numRegular, int numLarge) : capacity(numCompact + numRegular + numLarge), availableSpots(capacity) { int spotNumber = 1; // Create compact spots for (int i = 0; i < numCompact; i++) { spots.push_back(new ParkingSpot(spotNumber++, SpotType::COMPACT)); } // Create regular spots for (int i = 0; i < numRegular; i++) { spots.push_back(new ParkingSpot(spotNumber++, SpotType::REGULAR)); } // Create large spots for (int i = 0; i < numLarge; i++) { spots.push_back(new ParkingSpot(spotNumber++, SpotType::LARGE)); } } ParkingLot::~ParkingLot() { for (auto spot : spots) { delete spot; } } int ParkingLot::getCapacity() const { return capacity; } int ParkingLot::getAvailableSpots() const { return availableSpots; } bool ParkingLot::parkVehicle(Vehicle* vehicle) { if (!vehicle) return false; // Check if vehicle is already parked if (occupiedSpots.find(vehicle->getLicensePlate()) != occupiedSpots.end()) { return false; } ParkingSpot* spot = findAvailableSpot(vehicle); if (!spot) return false; if (spot->parkVehicle(vehicle)) { occupiedSpots[vehicle->getLicensePlate()] = spot; availableSpots--; return true; } return false; } Vehicle* ParkingLot::removeVehicle(const std::string& licensePlate) { auto it = occupiedSpots.find(licensePlate); if (it == occupiedSpots.end()) return nullptr; ParkingSpot* spot = it->second; Vehicle* vehicle = spot->removeVehicle(); if (vehicle) { occupiedSpots.erase(it); availableSpots++; } return vehicle; } ParkingSpot* ParkingLot::findVehicle(const std::string& licensePlate) const { auto it = occupiedSpots.find(licensePlate); return it != occupiedSpots.end() ? it->second : nullptr; } void ParkingLot::displayInfo() const { std::cout << "\nParking Lot Status:" << std::endl; std::cout << "Total Capacity: " << capacity << std::endl; std::cout << "Available Spots: " << availableSpots << std::endl; std::cout << "Occupied Spots: " << (capacity - availableSpots) << std::endl; } void ParkingLot::displayOccupancy() const { std::cout << "\nDetailed Occupancy:" << std::endl; for (const auto& spot : spots) { spot->displayInfo(); } } ParkingSpot* ParkingLot::findAvailableSpot(const Vehicle* vehicle) const { for (auto spot : spots) { if (spot->isAvailable() && spot->canFitVehicle(vehicle)) { return spot; } } return nullptr; } ================================================ FILE: solutions/cpp/parkinglot/ParkingLot.hpp ================================================ #ifndef PARKING_LOT_HPP #define PARKING_LOT_HPP #include #include #include #include "ParkingSpot.hpp" class ParkingLot { private: std::vector spots; std::map occupiedSpots; // licensePlate -> spot int capacity; int availableSpots; public: ParkingLot(int numCompact, int numRegular, int numLarge); ~ParkingLot(); int getCapacity() const; int getAvailableSpots() const; bool parkVehicle(Vehicle* vehicle); Vehicle* removeVehicle(const std::string& licensePlate); ParkingSpot* findVehicle(const std::string& licensePlate) const; void displayInfo() const; void displayOccupancy() const; private: ParkingSpot* findAvailableSpot(const Vehicle* vehicle) const; }; #endif ================================================ FILE: solutions/cpp/parkinglot/ParkingLotDemo.cpp ================================================ #include "ParkingLot.hpp" #include int main() { // Create parking lot with different types of spots ParkingLot parkingLot(2, 3, 2); // 2 compact, 3 regular, 2 large spots std::cout << "Initial parking lot status:" << std::endl; parkingLot.displayInfo(); // Create vehicles Vehicle* car1 = new Vehicle("CAR001", VehicleType::CAR, "Red"); Vehicle* car2 = new Vehicle("CAR002", VehicleType::CAR, "Blue"); Vehicle* motorcycle = new Vehicle("MOTO001", VehicleType::MOTORCYCLE, "Black"); Vehicle* truck = new Vehicle("TRUCK001", VehicleType::TRUCK, "White"); // Park vehicles std::cout << "\nParking vehicles..." << std::endl; if (parkingLot.parkVehicle(car1)) { std::cout << "Parked successfully: "; car1->displayInfo(); } if (parkingLot.parkVehicle(motorcycle)) { std::cout << "Parked successfully: "; motorcycle->displayInfo(); } if (parkingLot.parkVehicle(truck)) { std::cout << "Parked successfully: "; truck->displayInfo(); } // Display current status parkingLot.displayInfo(); parkingLot.displayOccupancy(); // Remove a vehicle std::cout << "\nRemoving vehicle CAR001..." << std::endl; Vehicle* removed = parkingLot.removeVehicle("CAR001"); if (removed) { std::cout << "Removed successfully: "; removed->displayInfo(); delete removed; } // Try to park another car if (parkingLot.parkVehicle(car2)) { std::cout << "Parked successfully: "; car2->displayInfo(); } // Final status std::cout << "\nFinal parking lot status:" << std::endl; parkingLot.displayInfo(); parkingLot.displayOccupancy(); // Cleanup remaining vehicles delete car2; delete motorcycle; delete truck; return 0; } ================================================ FILE: solutions/cpp/parkinglot/ParkingSpot.cpp ================================================ #include "ParkingSpot.hpp" #include ParkingSpot::ParkingSpot(int spotNumber, SpotType type) : spotNumber(spotNumber), type(type), vehicle(nullptr), available(true) {} int ParkingSpot::getSpotNumber() const { return spotNumber; } SpotType ParkingSpot::getType() const { return type; } Vehicle* ParkingSpot::getVehicle() const { return vehicle; } bool ParkingSpot::isAvailable() const { return available; } bool ParkingSpot::canFitVehicle(const Vehicle* vehicle) const { if (!vehicle) return false; switch (vehicle->getType()) { case VehicleType::MOTORCYCLE: return true; // Can park in any spot case VehicleType::CAR: return type != SpotType::COMPACT; case VehicleType::TRUCK: case VehicleType::BUS: return type == SpotType::LARGE; } return false; } bool ParkingSpot::parkVehicle(Vehicle* vehicle) { if (!available || !canFitVehicle(vehicle)) return false; this->vehicle = vehicle; available = false; return true; } Vehicle* ParkingSpot::removeVehicle() { if (!vehicle) return nullptr; Vehicle* removedVehicle = vehicle; vehicle = nullptr; available = true; return removedVehicle; } void ParkingSpot::displayInfo() const { std::cout << "Spot " << spotNumber << " ("; switch (type) { case SpotType::COMPACT: std::cout << "Compact"; break; case SpotType::REGULAR: std::cout << "Regular"; break; case SpotType::LARGE: std::cout << "Large"; break; } std::cout << "): " << (available ? "Available" : "Occupied"); if (vehicle) { std::cout << " by "; vehicle->displayInfo(); } else { std::cout << std::endl; } } ================================================ FILE: solutions/cpp/parkinglot/ParkingSpot.hpp ================================================ #ifndef PARKING_SPOT_HPP #define PARKING_SPOT_HPP #include "Vehicle.hpp" enum class SpotType { COMPACT, REGULAR, LARGE }; class ParkingSpot { private: int spotNumber; SpotType type; Vehicle* vehicle; bool available; public: ParkingSpot(int spotNumber, SpotType type); int getSpotNumber() const; SpotType getType() const; Vehicle* getVehicle() const; bool isAvailable() const; bool canFitVehicle(const Vehicle* vehicle) const; bool parkVehicle(Vehicle* vehicle); Vehicle* removeVehicle(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/parkinglot/README.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot should have multiple levels, each level with a certain number of parking spots. 2. The parking lot should support different types of vehicles, such as cars, motorcycles, and trucks. 3. Each parking spot should be able to accommodate a specific type of vehicle. 4. The system should assign a parking spot to a vehicle upon entry and release it when the vehicle exits. 5. The system should track the availability of parking spots and provide real-time information to customers. 6. The system should handle multiple entry and exit points and support concurrent access. ## Classes, Interfaces and Enumerations 1. The **ParkingLot** class follows the Singleton pattern to ensure only one instance of the parking lot exists. It maintains a list of levels and provides methods to park and unpark vehicles. 2. The **Level** class represents a level in the parking lot and contains a list of parking spots. It handles parking and unparking of vehicles within the level. 3. The **ParkingSpot** class represents an individual parking spot and tracks the availability and the parked vehicle. 4. The **Vehicle** class is an abstract base class for different types of vehicles. It is extended by Car, Motorcycle, and Truck classes. 5. The **VehicleType** enum defines the different types of vehicles supported by the parking lot. 6. Multi-threading is achieved through the use of synchronized keyword on critical sections to ensure thread safety. 7. The **Main** class demonstrates the usage of the parking lot system. ## Design Patterns Used: 1. Singleton Pattern: Ensures only one instance of the ParkingLot class. 2. Factory Pattern (optional extension): Could be used for creating vehicles based on input. 3. Observer Pattern (optional extension): Could notify customers about available spots. ================================================ FILE: solutions/cpp/parkinglot/Vehicle.cpp ================================================ #include "Vehicle.hpp" #include Vehicle::Vehicle(std::string licensePlate, VehicleType type, std::string color) : licensePlate(licensePlate), type(type), color(color) {} std::string Vehicle::getLicensePlate() const { return licensePlate; } VehicleType Vehicle::getType() const { return type; } std::string Vehicle::getColor() const { return color; } void Vehicle::displayInfo() const { std::cout << "Vehicle: " << color << " "; switch (type) { case VehicleType::CAR: std::cout << "Car"; break; case VehicleType::MOTORCYCLE: std::cout << "Motorcycle"; break; case VehicleType::TRUCK: std::cout << "Truck"; break; case VehicleType::BUS: std::cout << "Bus"; break; } std::cout << " (License: " << licensePlate << ")" << std::endl; } ================================================ FILE: solutions/cpp/parkinglot/Vehicle.hpp ================================================ #ifndef VEHICLE_HPP #define VEHICLE_HPP #include enum class VehicleType { CAR, MOTORCYCLE, TRUCK, BUS }; class Vehicle { private: std::string licensePlate; VehicleType type; std::string color; public: Vehicle(std::string licensePlate, VehicleType type, std::string color); std::string getLicensePlate() const; VehicleType getType() const; std::string getColor() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/pubsubsystem/Message.cpp ================================================ #include "Message.hpp" #include Message::Message(std::string topic, std::string content) : topic(topic), content(content) { timestamp = std::time(nullptr); } std::string Message::getTopic() const { return topic; } std::string Message::getContent() const { return content; } std::time_t Message::getTimestamp() const { return timestamp; } void Message::displayInfo() const { std::cout << "Topic: " << topic << std::endl; std::cout << "Content: " << content << std::endl; std::cout << "Time: " << std::ctime(×tamp); } ================================================ FILE: solutions/cpp/pubsubsystem/Message.hpp ================================================ #ifndef MESSAGE_HPP #define MESSAGE_HPP #include #include class Message { private: std::string topic; std::string content; std::time_t timestamp; public: Message(std::string topic, std::string content); std::string getTopic() const; std::string getContent() const; std::time_t getTimestamp() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/pubsubsystem/PubSubDemo.cpp ================================================ #include "PubSubSystem.hpp" #include #include #include int main() { PubSubSystem system; // Create topics Topic* tech = system.createTopic("Technology", "Tech news and updates"); Topic* sports = system.createTopic("Sports", "Sports news and scores"); Topic* weather = system.createTopic("Weather", "Weather updates"); std::cout << "Initial topics:" << std::endl; system.displayTopics(); // Add subscribers Subscriber* sub1 = system.addSubscriber("John"); Subscriber* sub2 = system.addSubscriber("Alice"); Subscriber* sub3 = system.addSubscriber("Bob"); // Subscribe to topics system.subscribe(sub1->getId(), "Technology"); system.subscribe(sub1->getId(), "Weather"); system.subscribe(sub2->getId(), "Sports"); system.subscribe(sub3->getId(), "Technology"); system.subscribe(sub3->getId(), "Sports"); // Publish messages std::cout << "\nPublishing messages..." << std::endl; system.publish("Technology", "New AI breakthrough!"); system.publish("Sports", "Team A wins championship!"); system.publish("Weather", "Sunny weather expected"); // Small delay to simulate time passing std::this_thread::sleep_for(std::chrono::seconds(1)); // Display messages for each subscriber std::cout << "\nChecking messages for subscribers:" << std::endl; system.displaySubscriberMessages(sub1->getId()); system.displaySubscriberMessages(sub2->getId()); system.displaySubscriberMessages(sub3->getId()); // Unsubscribe and test std::cout << "\nUnsubscribing John from Weather..." << std::endl; system.unsubscribe(sub1->getId(), "Weather"); system.publish("Weather", "Storm warning!"); std::cout << "\nJohn's updated messages:" << std::endl; system.displaySubscriberMessages(sub1->getId()); return 0; } ================================================ FILE: solutions/cpp/pubsubsystem/PubSubSystem.cpp ================================================ #include "PubSubSystem.hpp" #include #include PubSubSystem::PubSubSystem() : subscriberIdCounter(1) {} PubSubSystem::~PubSubSystem() { for (auto topic : topics) delete topic; for (auto subscriber : subscribers) delete subscriber; } Topic* PubSubSystem::createTopic(const std::string& name, const std::string& description) { if (findTopic(name)) return nullptr; Topic* topic = new Topic(name, description); topics.push_back(topic); return topic; } void PubSubSystem::removeTopic(const std::string& topicName) { auto it = std::find_if(topics.begin(), topics.end(), [topicName](Topic* topic) { return topic->getName() == topicName; }); if (it != topics.end()) { delete *it; topics.erase(it); } } Subscriber* PubSubSystem::addSubscriber(const std::string& name) { std::string id = generateSubscriberId(); Subscriber* subscriber = new Subscriber(id, name); subscribers.push_back(subscriber); return subscriber; } void PubSubSystem::removeSubscriber(const std::string& subscriberId) { // Remove from all topics first for (auto topic : topics) { topic->removeSubscriber(subscriberId); } // Remove from subscribers list auto it = std::find_if(subscribers.begin(), subscribers.end(), [subscriberId](Subscriber* sub) { return sub->getId() == subscriberId; }); if (it != subscribers.end()) { delete *it; subscribers.erase(it); } } bool PubSubSystem::subscribe(const std::string& subscriberId, const std::string& topicName) { Topic* topic = findTopic(topicName); Subscriber* subscriber = findSubscriber(subscriberId); if (!topic || !subscriber) return false; topic->addSubscriber(subscriber); return true; } bool PubSubSystem::unsubscribe(const std::string& subscriberId, const std::string& topicName) { Topic* topic = findTopic(topicName); if (!topic) return false; topic->removeSubscriber(subscriberId); return true; } bool PubSubSystem::publish(const std::string& topicName, const std::string& content) { Topic* topic = findTopic(topicName); if (!topic || !topic->isActive()) return false; Message message(topicName, content); topic->publishMessage(message); return true; } void PubSubSystem::displayTopics() const { std::cout << "\nAvailable Topics:" << std::endl; for (const auto& topic : topics) { topic->displayInfo(); std::cout << "------------------------" << std::endl; } } void PubSubSystem::displaySubscribers() const { std::cout << "\nRegistered Subscribers:" << std::endl; for (const auto& subscriber : subscribers) { subscriber->displayInfo(); std::cout << "------------------------" << std::endl; } } void PubSubSystem::displaySubscriberMessages(const std::string& subscriberId) const { if (Subscriber* subscriber = findSubscriber(subscriberId)) { subscriber->displayMessages(); } } Topic* PubSubSystem::findTopic(const std::string& topicName) const { auto it = std::find_if(topics.begin(), topics.end(), [topicName](Topic* topic) { return topic->getName() == topicName; }); return it != topics.end() ? *it : nullptr; } Subscriber* PubSubSystem::findSubscriber(const std::string& subscriberId) const { auto it = std::find_if(subscribers.begin(), subscribers.end(), [subscriberId](Subscriber* sub) { return sub->getId() == subscriberId; }); return it != subscribers.end() ? *it : nullptr; } std::string PubSubSystem::generateSubscriberId() { return "SUB" + std::to_string(subscriberIdCounter++); } ================================================ FILE: solutions/cpp/pubsubsystem/PubSubSystem.hpp ================================================ #ifndef PUB_SUB_SYSTEM_HPP #define PUB_SUB_SYSTEM_HPP #include #include #include "Topic.hpp" #include "Subscriber.hpp" class PubSubSystem { private: std::vector topics; std::vector subscribers; int subscriberIdCounter; public: PubSubSystem(); ~PubSubSystem(); Topic* createTopic(const std::string& name, const std::string& description); void removeTopic(const std::string& topicName); Subscriber* addSubscriber(const std::string& name); void removeSubscriber(const std::string& subscriberId); bool subscribe(const std::string& subscriberId, const std::string& topicName); bool unsubscribe(const std::string& subscriberId, const std::string& topicName); bool publish(const std::string& topicName, const std::string& content); void displayTopics() const; void displaySubscribers() const; void displaySubscriberMessages(const std::string& subscriberId) const; private: Topic* findTopic(const std::string& topicName) const; Subscriber* findSubscriber(const std::string& subscriberId) const; std::string generateSubscriberId(); }; #endif ================================================ FILE: solutions/cpp/pubsubsystem/README.md ================================================ # Designing a Pub-Sub System in Java ## Requirements 1. The Pub-Sub system should allow publishers to publish messages to specific topics. 2. Subscribers should be able to subscribe to topics of interest and receive messages published to those topics. 3. The system should support multiple publishers and subscribers. 4. Messages should be delivered to all subscribers of a topic in real-time. 5. The system should handle concurrent access and ensure thread safety. 6. The Pub-Sub system should be scalable and efficient in terms of message delivery. ## Classes, Interfaces and Enumerations 1. The **Message** class represents a message that can be published and received by subscribers. It contains the message content. 2. The **Topic** class represents a topic to which messages can be published. It maintains a set of subscribers and provides methods to add and remove subscribers, as well as publish messages to all subscribers. 3. The **Subscriber** interface defines the contract for subscribers. It declares the onMessage method that is invoked when a subscriber receives a message. 4. The **PrintSubscriber** class is a concrete implementation of the Subscriber interface. It receives messages and prints them to the console. 5. The **Publisher** class represents a publisher that publishes messages to a specific topic. 6. The **PubSubSystem** class is the main class that manages topics, subscribers, and message publishing. It uses a ConcurrentHashMap to store topics and an ExecutorService to handle concurrent message publishing. 7. The **PubSubDemo** class demonstrates the usage of the Pub-Sub system by creating topics, subscribers, and publishers, and publishing messages. ================================================ FILE: solutions/cpp/pubsubsystem/Subscriber.cpp ================================================ #include "Subscriber.hpp" #include Subscriber::Subscriber(std::string id, std::string name) : id(id), name(name), active(true) {} std::string Subscriber::getId() const { return id; } std::string Subscriber::getName() const { return name; } bool Subscriber::isActive() const { return active; } const std::vector& Subscriber::getMessageQueue() const { return messageQueue; } void Subscriber::receiveMessage(const Message& message) { if (active) { messageQueue.push_back(message); } } void Subscriber::displayMessages() const { std::cout << "\nMessages for " << name << ":" << std::endl; if (messageQueue.empty()) { std::cout << "No messages" << std::endl; return; } for (const auto& message : messageQueue) { message.displayInfo(); std::cout << "------------------------" << std::endl; } } void Subscriber::clearMessages() { messageQueue.clear(); } void Subscriber::setActive(bool status) { active = status; } void Subscriber::displayInfo() const { std::cout << "Subscriber: " << name << " (ID: " << id << ")" << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Pending Messages: " << messageQueue.size() << std::endl; } ================================================ FILE: solutions/cpp/pubsubsystem/Subscriber.hpp ================================================ #ifndef SUBSCRIBER_HPP #define SUBSCRIBER_HPP #include #include #include "Message.hpp" class Subscriber { private: std::string id; std::string name; std::vector messageQueue; bool active; public: Subscriber(std::string id, std::string name); std::string getId() const; std::string getName() const; bool isActive() const; const std::vector& getMessageQueue() const; void receiveMessage(const Message& message); void displayMessages() const; void clearMessages(); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/pubsubsystem/Topic.cpp ================================================ #include "Topic.hpp" #include #include Topic::Topic(std::string name, std::string description) : name(name), description(description), active(true) {} std::string Topic::getName() const { return name; } std::string Topic::getDescription() const { return description; } bool Topic::isActive() const { return active; } const std::vector& Topic::getSubscribers() const { return subscribers; } void Topic::addSubscriber(Subscriber* subscriber) { if (!subscriber) return; auto it = std::find(subscribers.begin(), subscribers.end(), subscriber); if (it == subscribers.end()) { subscribers.push_back(subscriber); } } void Topic::removeSubscriber(const std::string& subscriberId) { auto it = std::find_if(subscribers.begin(), subscribers.end(), [subscriberId](Subscriber* sub) { return sub->getId() == subscriberId; }); if (it != subscribers.end()) { subscribers.erase(it); } } void Topic::publishMessage(const Message& message) { if (!active) return; for (auto subscriber : subscribers) { subscriber->receiveMessage(message); } } void Topic::setActive(bool status) { active = status; } void Topic::displayInfo() const { std::cout << "Topic: " << name << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Subscribers: " << subscribers.size() << std::endl; } ================================================ FILE: solutions/cpp/pubsubsystem/Topic.hpp ================================================ #ifndef TOPIC_HPP #define TOPIC_HPP #include #include #include "Subscriber.hpp" class Topic { private: std::string name; std::string description; std::vector subscribers; bool active; public: Topic(std::string name, std::string description); std::string getName() const; std::string getDescription() const; bool isActive() const; const std::vector& getSubscribers() const; void addSubscriber(Subscriber* subscriber); void removeSubscriber(const std::string& subscriberId); void publishMessage(const Message& message); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/restaurantmanagementsystem/MenuItem.cpp ================================================ #include "MenuItem.hpp" #include #include MenuItem::MenuItem(std::string itemId, std::string name, std::string description, double price, Category category) : itemId(itemId), name(name), description(description), price(price), category(category), available(true) {} std::string MenuItem::getItemId() const { return itemId; } std::string MenuItem::getName() const { return name; } std::string MenuItem::getDescription() const { return description; } double MenuItem::getPrice() const { return price; } Category MenuItem::getCategory() const { return category; } bool MenuItem::isAvailable() const { return available; } void MenuItem::setPrice(double price) { if (price > 0) { this->price = price; } } void MenuItem::setAvailable(bool status) { available = status; } void MenuItem::displayInfo() const { std::cout << name << " (ID: " << itemId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Price: $" << std::fixed << std::setprecision(2) << price << std::endl; std::cout << "Category: "; switch (category) { case Category::APPETIZER: std::cout << "Appetizer"; break; case Category::MAIN_COURSE: std::cout << "Main Course"; break; case Category::DESSERT: std::cout << "Dessert"; break; case Category::BEVERAGE: std::cout << "Beverage"; break; } std::cout << std::endl; std::cout << "Status: " << (available ? "Available" : "Not Available") << std::endl; } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/MenuItem.hpp ================================================ #ifndef MENU_ITEM_HPP #define MENU_ITEM_HPP #include enum class Category { APPETIZER, MAIN_COURSE, DESSERT, BEVERAGE }; class MenuItem { private: std::string itemId; std::string name; std::string description; double price; Category category; bool available; public: MenuItem(std::string itemId, std::string name, std::string description, double price, Category category); std::string getItemId() const; std::string getName() const; std::string getDescription() const; double getPrice() const; Category getCategory() const; bool isAvailable() const; void setPrice(double price); void setAvailable(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/restaurantmanagementsystem/Order.cpp ================================================ #include "Order.hpp" #include #include #include Order::Order(std::string orderId, Table* table) : orderId(orderId), table(table), totalAmount(0.0), status(OrderStatus::PENDING) { orderTime = std::time(nullptr); } Order::~Order() { for (auto item : items) { delete item; } } std::string Order::getOrderId() const { return orderId; } Table* Order::getTable() const { return table; } const std::vector& Order::getItems() const { return items; } double Order::getTotalAmount() const { return totalAmount; } std::time_t Order::getOrderTime() const { return orderTime; } OrderStatus Order::getStatus() const { return status; } void Order::addItem(MenuItem* menuItem, int quantity) { if (!menuItem || !menuItem->isAvailable()) return; // Check if item already exists auto it = std::find_if(items.begin(), items.end(), [menuItem](OrderItem* item) { return item->getMenuItem() == menuItem; }); if (it != items.end()) { (*it)->updateQuantity((*it)->getQuantity() + quantity); } else { items.push_back(new OrderItem(menuItem, quantity)); } calculateTotal(); } void Order::removeItem(const std::string& itemId) { auto it = std::find_if(items.begin(), items.end(), [itemId](OrderItem* item) { return item->getMenuItem()->getItemId() == itemId; }); if (it != items.end()) { delete *it; items.erase(it); calculateTotal(); } } void Order::updateItemQuantity(const std::string& itemId, int quantity) { auto it = std::find_if(items.begin(), items.end(), [itemId](OrderItem* item) { return item->getMenuItem()->getItemId() == itemId; }); if (it != items.end()) { if (quantity <= 0) { removeItem(itemId); } else { (*it)->updateQuantity(quantity); calculateTotal(); } } } void Order::setStatus(OrderStatus status) { this->status = status; } void Order::calculateTotal() { totalAmount = 0.0; for (const auto& item : items) { totalAmount += item->getSubtotal(); } } void Order::displayInfo() const { std::cout << "\nOrder Details:" << std::endl; std::cout << "Order ID: " << orderId << std::endl; std::cout << "Table: " << table->getTableNumber() << std::endl; std::cout << "Time: " << std::ctime(&orderTime); std::cout << "Status: "; switch (status) { case OrderStatus::PENDING: std::cout << "Pending"; break; case OrderStatus::PREPARING: std::cout << "Preparing"; break; case OrderStatus::READY: std::cout << "Ready"; break; case OrderStatus::SERVED: std::cout << "Served"; break; case OrderStatus::PAID: std::cout << "Paid"; break; } std::cout << std::endl; std::cout << "\nItems:" << std::endl; for (const auto& item : items) { item->displayInfo(); } std::cout << "------------------------" << std::endl; std::cout << "Total Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/Order.hpp ================================================ #ifndef ORDER_HPP #define ORDER_HPP #include #include #include #include "Table.hpp" #include "OrderItem.hpp" enum class OrderStatus { PENDING, PREPARING, READY, SERVED, PAID }; class Order { private: std::string orderId; Table* table; std::vector items; double totalAmount; std::time_t orderTime; OrderStatus status; public: Order(std::string orderId, Table* table); ~Order(); std::string getOrderId() const; Table* getTable() const; const std::vector& getItems() const; double getTotalAmount() const; std::time_t getOrderTime() const; OrderStatus getStatus() const; void addItem(MenuItem* menuItem, int quantity); void removeItem(const std::string& itemId); void updateItemQuantity(const std::string& itemId, int quantity); void setStatus(OrderStatus status); void calculateTotal(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/restaurantmanagementsystem/OrderItem.cpp ================================================ #include "OrderItem.hpp" #include #include OrderItem::OrderItem(MenuItem* menuItem, int quantity) : menuItem(menuItem), quantity(quantity) { subtotal = menuItem->getPrice() * quantity; } MenuItem* OrderItem::getMenuItem() const { return menuItem; } int OrderItem::getQuantity() const { return quantity; } double OrderItem::getSubtotal() const { return subtotal; } void OrderItem::updateQuantity(int quantity) { if (quantity > 0) { this->quantity = quantity; subtotal = menuItem->getPrice() * quantity; } } void OrderItem::displayInfo() const { std::cout << menuItem->getName() << " x " << quantity << " = $" << std::fixed << std::setprecision(2) << subtotal << std::endl; } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/OrderItem.hpp ================================================ #ifndef ORDER_ITEM_HPP #define ORDER_ITEM_HPP #include "MenuItem.hpp" class OrderItem { private: MenuItem* menuItem; int quantity; double subtotal; public: OrderItem(MenuItem* menuItem, int quantity); MenuItem* getMenuItem() const; int getQuantity() const; double getSubtotal() const; void updateQuantity(int quantity); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/restaurantmanagementsystem/README.md ================================================ # Designing Restaurant Management System ## Requirements 1. The restaurant management system should allow customers to place orders, view the menu, and make reservations. 2. The system should manage the restaurant's inventory, including ingredients and menu items. 3. The system should handle order processing, including order preparation, billing, and payment. 4. The system should support multiple payment methods, such as cash, credit card, and mobile payments. 5. The system should manage staff information, including roles, schedules, and performance tracking. 6. The system should generate reports and analytics for management, such as sales reports and inventory analysis. 7. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **MenuItem** class represents a menu item in the restaurant, with properties such as ID, name, description, price, and availability. 2. The **Order** class represents an order placed by a customer, with properties such as ID, list of menu items, total amount, order status, and timestamp. 3. The **OrderStatus** enum represents the different statuses an order can have, such as pending, preparing, ready, completed, or cancelled. 4. The **Reservation** class represents a reservation made by a customer, with properties such as ID, customer name, contact number, party size, and reservation time. 5. The **Payment** class represents a payment made for an order, with properties such as ID, amount, payment method, and payment status. 6. The **PaymentMethod** enum represents the different payment methods supported by the restaurant, such as cash, credit card, or mobile payment. 7. The **PaymentStatus** enum represents the status of a payment, which can be pending, completed, or failed. 8. The Staff class represents a staff member of the restaurant, with properties such as ID, name, role, and contact number. 9. The **Restaurant** class is the main class that manages the restaurant operations. It follows the Singleton pattern to ensure only one instance of the restaurant exists. 10. The Restaurant class provides methods for managing menu items, placing orders, updating order status, making reservations, processing payments, and managing staff. 11. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as orders and reservations. 12. The notifyKitchen and notifyStaff methods are placeholders for notifying relevant staff about order updates and status changes. 13. The **RestaurantManagementDemo** class demonstrates the usage of the restaurant management system by adding menu items, placing an order, making a reservation, processing a payment, updating order status, adding staff, and retrieving the menu. ================================================ FILE: solutions/cpp/restaurantmanagementsystem/RestaurantDemo.cpp ================================================ #include "RestaurantSystem.hpp" #include #include #include int main() { RestaurantSystem restaurant; // Add menu items MenuItem* burger = restaurant.addMenuItem("Burger", "Classic beef burger", 12.99, Category::MAIN_COURSE); MenuItem* fries = restaurant.addMenuItem("Fries", "Crispy french fries", 4.99, Category::APPETIZER); MenuItem* salad = restaurant.addMenuItem("Salad", "Fresh garden salad", 8.99, Category::APPETIZER); MenuItem* soda = restaurant.addMenuItem("Soda", "Carbonated drink", 2.99, Category::BEVERAGE); MenuItem* cake = restaurant.addMenuItem("Cake", "Chocolate cake", 6.99, Category::DESSERT); // Add tables restaurant.addTable(2); // Table 1: 2 seats restaurant.addTable(4); // Table 2: 4 seats restaurant.addTable(6); // Table 3: 6 seats std::cout << "Initial restaurant status:" << std::endl; restaurant.displayMenu(); restaurant.displayTables(); // Create an order Order* order1 = restaurant.createOrder(1); // Order for table 1 if (order1) { std::cout << "\nCreated new order: " << order1->getOrderId() << std::endl; // Add items to order restaurant.addToOrder(order1->getOrderId(), burger->getItemId(), 2); restaurant.addToOrder(order1->getOrderId(), fries->getItemId(), 1); restaurant.addToOrder(order1->getOrderId(), soda->getItemId(), 2); // Display order restaurant.displayOrder(order1->getOrderId()); // Update order status std::cout << "\nUpdating order status..." << std::endl; restaurant.updateOrderStatus(order1->getOrderId(), OrderStatus::PREPARING); std::this_thread::sleep_for(std::chrono::seconds(1)); restaurant.updateOrderStatus(order1->getOrderId(), OrderStatus::READY); std::this_thread::sleep_for(std::chrono::seconds(1)); restaurant.updateOrderStatus(order1->getOrderId(), OrderStatus::SERVED); // Update order items std::cout << "\nAdding dessert to order..." << std::endl; restaurant.addToOrder(order1->getOrderId(), cake->getItemId(), 2); // Display final order restaurant.displayOrder(order1->getOrderId()); // Complete order std::cout << "\nCompleting order..." << std::endl; restaurant.updateOrderStatus(order1->getOrderId(), OrderStatus::PAID); } // Display final restaurant status std::cout << "\nFinal restaurant status:" << std::endl; restaurant.displayTables(); restaurant.displayOrders(); return 0; } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/RestaurantSystem.cpp ================================================ #include "RestaurantSystem.hpp" #include #include RestaurantSystem::RestaurantSystem() : orderIdCounter(1) {} RestaurantSystem::~RestaurantSystem() { for (auto item : menu) delete item; for (auto table : tables) delete table; for (auto order : orders) delete order; } MenuItem* RestaurantSystem::addMenuItem(const std::string& name, const std::string& description, double price, Category category) { std::string itemId = "ITEM" + std::to_string(menu.size() + 1); MenuItem* item = new MenuItem(itemId, name, description, price, category); menu.push_back(item); return item; } void RestaurantSystem::removeMenuItem(const std::string& itemId) { auto it = std::find_if(menu.begin(), menu.end(), [itemId](MenuItem* item) { return item->getItemId() == itemId; }); if (it != menu.end()) { delete *it; menu.erase(it); } } void RestaurantSystem::updateItemAvailability(const std::string& itemId, bool available) { if (MenuItem* item = findMenuItem(itemId)) { item->setAvailable(available); } } Table* RestaurantSystem::addTable(int capacity) { int tableNumber = tables.size() + 1; Table* table = new Table(tableNumber, capacity); tables.push_back(table); return table; } void RestaurantSystem::updateTableStatus(int tableNumber, TableStatus status) { if (Table* table = findTable(tableNumber)) { table->setStatus(status); } } Order* RestaurantSystem::createOrder(int tableNumber) { Table* table = findTable(tableNumber); if (!table || table->getStatus() != TableStatus::AVAILABLE) return nullptr; std::string orderId = generateOrderId(); Order* order = new Order(orderId, table); orders.push_back(order); table->setStatus(TableStatus::OCCUPIED); return order; } bool RestaurantSystem::addToOrder(const std::string& orderId, const std::string& itemId, int quantity) { Order* order = findOrder(orderId); MenuItem* item = findMenuItem(itemId); if (!order || !item) return false; order->addItem(item, quantity); return true; } bool RestaurantSystem::updateOrderItem(const std::string& orderId, const std::string& itemId, int quantity) { Order* order = findOrder(orderId); if (!order) return false; order->updateItemQuantity(itemId, quantity); return true; } bool RestaurantSystem::updateOrderStatus(const std::string& orderId, OrderStatus status) { Order* order = findOrder(orderId); if (!order) return false; order->setStatus(status); if (status == OrderStatus::PAID) { order->getTable()->setStatus(TableStatus::AVAILABLE); } return true; } void RestaurantSystem::displayMenu() const { std::cout << "\n=== Restaurant Menu ===" << std::endl; for (const auto& item : menu) { item->displayInfo(); std::cout << "------------------------" << std::endl; } } void RestaurantSystem::displayTables() const { std::cout << "\n=== Tables Status ===" << std::endl; for (const auto& table : tables) { table->displayInfo(); std::cout << "------------------------" << std::endl; } } void RestaurantSystem::displayOrders() const { std::cout << "\n=== Current Orders ===" << std::endl; for (const auto& order : orders) { order->displayInfo(); } } void RestaurantSystem::displayOrder(const std::string& orderId) const { if (Order* order = findOrder(orderId)) { order->displayInfo(); } } MenuItem* RestaurantSystem::findMenuItem(const std::string& itemId) const { auto it = std::find_if(menu.begin(), menu.end(), [itemId](MenuItem* item) { return item->getItemId() == itemId; }); return it != menu.end() ? *it : nullptr; } Table* RestaurantSystem::findTable(int tableNumber) const { auto it = std::find_if(tables.begin(), tables.end(), [tableNumber](Table* table) { return table->getTableNumber() == tableNumber; }); return it != tables.end() ? *it : nullptr; } Order* RestaurantSystem::findOrder(const std::string& orderId) const { auto it = std::find_if(orders.begin(), orders.end(), [orderId](Order* order) { return order->getOrderId() == orderId; }); return it != orders.end() ? *it : nullptr; } std::string RestaurantSystem::generateOrderId() { return "ORD" + std::to_string(orderIdCounter++); } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/RestaurantSystem.hpp ================================================ #ifndef RESTAURANT_SYSTEM_HPP #define RESTAURANT_SYSTEM_HPP #include #include #include "MenuItem.hpp" #include "Table.hpp" #include "Order.hpp" class RestaurantSystem { private: std::vector menu; std::vector tables; std::vector orders; int orderIdCounter; public: RestaurantSystem(); ~RestaurantSystem(); // Menu management MenuItem* addMenuItem(const std::string& name, const std::string& description, double price, Category category); void removeMenuItem(const std::string& itemId); void updateItemAvailability(const std::string& itemId, bool available); // Table management Table* addTable(int capacity); void updateTableStatus(int tableNumber, TableStatus status); // Order management Order* createOrder(int tableNumber); bool addToOrder(const std::string& orderId, const std::string& itemId, int quantity); bool updateOrderItem(const std::string& orderId, const std::string& itemId, int quantity); bool updateOrderStatus(const std::string& orderId, OrderStatus status); // Display functions void displayMenu() const; void displayTables() const; void displayOrders() const; void displayOrder(const std::string& orderId) const; private: MenuItem* findMenuItem(const std::string& itemId) const; Table* findTable(int tableNumber) const; Order* findOrder(const std::string& orderId) const; std::string generateOrderId(); }; #endif ================================================ FILE: solutions/cpp/restaurantmanagementsystem/Table.cpp ================================================ #include "Table.hpp" #include Table::Table(int tableNumber, int capacity) : tableNumber(tableNumber), capacity(capacity), status(TableStatus::AVAILABLE) {} int Table::getTableNumber() const { return tableNumber; } int Table::getCapacity() const { return capacity; } TableStatus Table::getStatus() const { return status; } void Table::setStatus(TableStatus status) { this->status = status; } void Table::displayInfo() const { std::cout << "Table " << tableNumber << std::endl; std::cout << "Capacity: " << capacity << " persons" << std::endl; std::cout << "Status: "; switch (status) { case TableStatus::AVAILABLE: std::cout << "Available"; break; case TableStatus::OCCUPIED: std::cout << "Occupied"; break; case TableStatus::RESERVED: std::cout << "Reserved"; break; } std::cout << std::endl; } ================================================ FILE: solutions/cpp/restaurantmanagementsystem/Table.hpp ================================================ #ifndef TABLE_HPP #define TABLE_HPP enum class TableStatus { AVAILABLE, OCCUPIED, RESERVED }; class Table { private: int tableNumber; int capacity; TableStatus status; public: Table(int tableNumber, int capacity); int getTableNumber() const; int getCapacity() const; TableStatus getStatus() const; void setStatus(TableStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/ridesharingservice/Location.cpp ================================================ #include "Location.hpp" #include #include Location::Location(double latitude, double longitude, std::string address) : latitude(latitude), longitude(longitude), address(address) {} double Location::getLatitude() const { return latitude; } double Location::getLongitude() const { return longitude; } std::string Location::getAddress() const { return address; } double Location::calculateDistance(const Location& other) const { // Simple Euclidean distance for demonstration double dx = latitude - other.latitude; double dy = longitude - other.longitude; return std::sqrt(dx * dx + dy * dy); } void Location::displayInfo() const { std::cout << "Location: " << address << std::endl; std::cout << "Coordinates: (" << latitude << ", " << longitude << ")" << std::endl; } ================================================ FILE: solutions/cpp/ridesharingservice/Location.hpp ================================================ #ifndef LOCATION_HPP #define LOCATION_HPP #include class Location { private: double latitude; double longitude; std::string address; public: Location(double latitude, double longitude, std::string address); double getLatitude() const; double getLongitude() const; std::string getAddress() const; double calculateDistance(const Location& other) const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/ridesharingservice/README.md ================================================ # Designing a Ride-Sharing Service Like Uber ## Requirements 1. The ride sharing service should allow passengers to request rides and drivers to accept and fulfill those ride requests. 2. Passengers should be able to specify their pickup location, destination, and desired ride type (e.g., regular, premium). 3. Drivers should be able to see available ride requests and choose to accept or decline them. 4. The system should match ride requests with available drivers based on proximity and other factors. 5. The system should calculate the fare for each ride based on distance, time, and ride type. 6. The system should handle payments and process transactions between passengers and drivers. 7. The system should provide real-time tracking of ongoing rides and notify passengers and drivers about ride status updates. 8. The system should handle concurrent requests and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Passenger** class represents a passenger in the ride sharing service, with properties such as ID, name, contact information, and location. 2. The **Driver** class represents a driver in the ride sharing service, with properties such as ID, name, contact information, license plate, location, and status (available or busy). 3. The **Ride** class represents a ride requested by a passenger and accepted by a driver, with properties such as ID, passenger, driver, source location, destination location, status, and fare. 4. The **Location** class represents a geographical location with latitude and longitude coordinates. 5. The **Payment** class represents a payment made for a ride, with properties such as ID, ride, amount, and payment status. 6. The **RideService** class is the main class that manages the ride sharing service. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The RideService class provides methods for adding passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. 8. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and ConcurrentLinkedQueue) to handle concurrent access to shared data, such as ride requests and driver availability. 9. The notifyDrivers, notifyPassenger, and notifyDriver methods are placeholders for notifying relevant parties about ride status updates. 10. The calculateFare and processPayment methods are placeholders for calculating ride fares and processing payments, respectively. 11. The **RideSharingDemo** class demonstrates the usage of the ride sharing service by creating passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. ================================================ FILE: solutions/cpp/ridesharingservice/Ride.cpp ================================================ #include "Ride.hpp" #include #include Ride::Ride(std::string rideId, User* rider, Location* pickup, Location* dropoff) : rideId(rideId), rider(rider), driver(nullptr), pickup(pickup), dropoff(dropoff), distance(0.0), fare(0.0), status(RideStatus::REQUESTED) { requestTime = std::time(nullptr); completionTime = 0; distance = pickup->calculateDistance(*dropoff); } Ride::~Ride() { delete pickup; delete dropoff; } std::string Ride::getRideId() const { return rideId; } User* Ride::getRider() const { return rider; } User* Ride::getDriver() const { return driver; } Location* Ride::getPickup() const { return pickup; } Location* Ride::getDropoff() const { return dropoff; } double Ride::getDistance() const { return distance; } double Ride::getFare() const { return fare; } std::time_t Ride::getRequestTime() const { return requestTime; } std::time_t Ride::getCompletionTime() const { return completionTime; } RideStatus Ride::getStatus() const { return status; } void Ride::assignDriver(User* driver) { if (driver && driver->getType() == UserType::DRIVER) { this->driver = driver; status = RideStatus::ACCEPTED; } } void Ride::calculateFare() { // Simple fare calculation: base fare + distance-based fare const double BASE_FARE = 5.0; const double RATE_PER_KM = 2.0; fare = BASE_FARE + (distance * RATE_PER_KM); } void Ride::updateStatus(RideStatus status) { this->status = status; if (status == RideStatus::COMPLETED) { completionTime = std::time(nullptr); calculateFare(); } } void Ride::displayInfo() const { std::cout << "\nRide Details:" << std::endl; std::cout << "ID: " << rideId << std::endl; std::cout << "Rider: " << rider->getName() << std::endl; if (driver) { std::cout << "Driver: " << driver->getName() << std::endl; } std::cout << "Status: "; switch (status) { case RideStatus::REQUESTED: std::cout << "Requested"; break; case RideStatus::ACCEPTED: std::cout << "Accepted"; break; case RideStatus::IN_PROGRESS: std::cout << "In Progress"; break; case RideStatus::COMPLETED: std::cout << "Completed"; break; case RideStatus::CANCELLED: std::cout << "Cancelled"; break; } std::cout << std::endl; std::cout << "Pickup: " << pickup->getAddress() << std::endl; std::cout << "Dropoff: " << dropoff->getAddress() << std::endl; std::cout << "Distance: " << std::fixed << std::setprecision(2) << distance << " km" << std::endl; if (status == RideStatus::COMPLETED) { std::cout << "Fare: $" << std::fixed << std::setprecision(2) << fare << std::endl; std::cout << "Request Time: " << std::ctime(&requestTime); std::cout << "Completion Time: " << std::ctime(&completionTime); } } ================================================ FILE: solutions/cpp/ridesharingservice/Ride.hpp ================================================ #ifndef RIDE_HPP #define RIDE_HPP #include #include #include "User.hpp" #include "Location.hpp" enum class RideStatus { REQUESTED, ACCEPTED, IN_PROGRESS, COMPLETED, CANCELLED }; class Ride { private: std::string rideId; User* rider; User* driver; Location* pickup; Location* dropoff; double distance; double fare; std::time_t requestTime; std::time_t completionTime; RideStatus status; public: Ride(std::string rideId, User* rider, Location* pickup, Location* dropoff); ~Ride(); std::string getRideId() const; User* getRider() const; User* getDriver() const; Location* getPickup() const; Location* getDropoff() const; double getDistance() const; double getFare() const; std::time_t getRequestTime() const; std::time_t getCompletionTime() const; RideStatus getStatus() const; void assignDriver(User* driver); void calculateFare(); void updateStatus(RideStatus status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/ridesharingservice/RideDemo.cpp ================================================ #include "RideService.hpp" #include #include #include int main() { RideService service; // Register users User* rider1 = service.registerUser("John", "123-456-7890", UserType::RIDER, new Location(40.7128, -74.0060, "New York City")); User* rider2 = service.registerUser("Alice", "123-456-7891", UserType::RIDER, new Location(34.0522, -118.2437, "Los Angeles")); User* driver1 = service.registerUser("Bob", "123-456-7892", UserType::DRIVER, new Location(40.7300, -74.0100, "Near NYC")); User* driver2 = service.registerUser("Carol", "123-456-7893", UserType::DRIVER, new Location(34.0500, -118.2400, "Near LA")); std::cout << "Initial users:" << std::endl; service.displayUsers(); // Request rides Location* pickup1 = new Location(40.7128, -74.0060, "NYC Downtown"); Location* dropoff1 = new Location(40.7589, -73.9851, "Central Park"); std::cout << "\nRequesting ride..." << std::endl; Ride* ride1 = service.requestRide(rider1->getUserId(), pickup1, dropoff1); if (ride1) { std::cout << "Ride requested successfully:" << std::endl; ride1->displayInfo(); // Update ride status std::cout << "\nUpdating ride status..." << std::endl; service.updateRideStatus(ride1->getRideId(), RideStatus::IN_PROGRESS); std::this_thread::sleep_for(std::chrono::seconds(1)); service.updateRideStatus(ride1->getRideId(), RideStatus::COMPLETED); // Rate users std::cout << "\nRating users..." << std::endl; service.rateUser(ride1->getDriver()->getUserId(), 5.0); // Rate driver service.rateUser(ride1->getRider()->getUserId(), 4.5); // Rate rider } // Display final status std::cout << "\nFinal user status:" << std::endl; service.displayUsers(); std::cout << "\nRide history:" << std::endl; service.displayRides(); return 0; } ================================================ FILE: solutions/cpp/ridesharingservice/RideService.cpp ================================================ #include "RideService.hpp" #include #include RideService::RideService() : userIdCounter(1), rideIdCounter(1) {} RideService::~RideService() { for (auto user : users) delete user; for (auto ride : rides) delete ride; } User* RideService::registerUser(const std::string& name, const std::string& phone, UserType type, Location* location) { std::string userId = generateUserId(); User* user = new User(userId, name, phone, type, location); users.push_back(user); return user; } void RideService::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { delete *it; users.erase(it); } } Ride* RideService::requestRide(const std::string& riderId, Location* pickup, Location* dropoff) { User* rider = findUser(riderId); if (!rider || rider->getType() != UserType::RIDER) return nullptr; std::string rideId = generateRideId(); Ride* ride = new Ride(rideId, rider, pickup, dropoff); rides.push_back(ride); // Try to find and assign nearest driver User* driver = findNearestDriver(*pickup); if (driver) { ride->assignDriver(driver); } return ride; } bool RideService::assignDriver(const std::string& rideId, const std::string& driverId) { Ride* ride = findRide(rideId); User* driver = findUser(driverId); if (!ride || !driver || driver->getType() != UserType::DRIVER) return false; ride->assignDriver(driver); return true; } bool RideService::updateRideStatus(const std::string& rideId, RideStatus status) { Ride* ride = findRide(rideId); if (!ride) return false; ride->updateStatus(status); return true; } bool RideService::rateUser(const std::string& userId, double rating) { User* user = findUser(userId); if (!user) return false; user->updateRating(rating); return true; } void RideService::displayUsers() const { std::cout << "\n=== Registered Users ===" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void RideService::displayRides() const { std::cout << "\n=== All Rides ===" << std::endl; for (const auto& ride : rides) { ride->displayInfo(); } } void RideService::displayUserHistory(const std::string& userId) const { std::cout << "\n=== Ride History for User " << userId << " ===" << std::endl; for (const auto& ride : rides) { if ((ride->getRider()->getUserId() == userId) || (ride->getDriver() && ride->getDriver()->getUserId() == userId)) { ride->displayInfo(); } } } User* RideService::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Ride* RideService::findRide(const std::string& rideId) const { auto it = std::find_if(rides.begin(), rides.end(), [rideId](Ride* ride) { return ride->getRideId() == rideId; }); return it != rides.end() ? *it : nullptr; } User* RideService::findNearestDriver(const Location& pickup) const { User* nearestDriver = nullptr; double minDistance = std::numeric_limits::max(); for (auto user : users) { if (user->getType() == UserType::DRIVER && user->isActive()) { double distance = pickup.calculateDistance(*user->getCurrentLocation()); if (distance < minDistance) { minDistance = distance; nearestDriver = user; } } } return nearestDriver; } std::string RideService::generateUserId() { return "U" + std::to_string(userIdCounter++); } std::string RideService::generateRideId() { return "R" + std::to_string(rideIdCounter++); } ================================================ FILE: solutions/cpp/ridesharingservice/RideService.hpp ================================================ #ifndef RIDE_SERVICE_HPP #define RIDE_SERVICE_HPP #include #include #include "User.hpp" #include "Ride.hpp" class RideService { private: std::vector users; std::vector rides; int userIdCounter; int rideIdCounter; public: RideService(); ~RideService(); User* registerUser(const std::string& name, const std::string& phone, UserType type, Location* location); void removeUser(const std::string& userId); Ride* requestRide(const std::string& riderId, Location* pickup, Location* dropoff); bool assignDriver(const std::string& rideId, const std::string& driverId); bool updateRideStatus(const std::string& rideId, RideStatus status); bool rateUser(const std::string& userId, double rating); void displayUsers() const; void displayRides() const; void displayUserHistory(const std::string& userId) const; private: User* findUser(const std::string& userId) const; Ride* findRide(const std::string& rideId) const; User* findNearestDriver(const Location& pickup) const; std::string generateUserId(); std::string generateRideId(); }; #endif ================================================ FILE: solutions/cpp/ridesharingservice/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string name, std::string phone, UserType type, Location* location) : userId(userId), name(name), phone(phone), type(type), currentLocation(location), active(true), rating(5.0), totalRatings(0) {} User::~User() { delete currentLocation; } std::string User::getUserId() const { return userId; } std::string User::getName() const { return name; } std::string User::getPhone() const { return phone; } UserType User::getType() const { return type; } Location* User::getCurrentLocation() const { return currentLocation; } bool User::isActive() const { return active; } double User::getRating() const { return rating; } void User::updateLocation(Location* location) { delete currentLocation; currentLocation = location; } void User::setActive(bool status) { active = status; } void User::updateRating(double newRating) { if (newRating >= 1.0 && newRating <= 5.0) { rating = ((rating * totalRatings) + newRating) / (totalRatings + 1); totalRatings++; } } void User::displayInfo() const { std::cout << "User: " << name << " (ID: " << userId << ")" << std::endl; std::cout << "Type: " << (type == UserType::RIDER ? "Rider" : "Driver") << std::endl; std::cout << "Phone: " << phone << std::endl; std::cout << "Rating: " << std::fixed << std::setprecision(1) << rating << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; if (currentLocation) { currentLocation->displayInfo(); } } ================================================ FILE: solutions/cpp/ridesharingservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include "Location.hpp" enum class UserType { RIDER, DRIVER }; class User { private: std::string userId; std::string name; std::string phone; UserType type; Location* currentLocation; bool active; double rating; int totalRatings; public: User(std::string userId, std::string name, std::string phone, UserType type, Location* location); ~User(); std::string getUserId() const; std::string getName() const; std::string getPhone() const; UserType getType() const; Location* getCurrentLocation() const; bool isActive() const; double getRating() const; void updateLocation(Location* location); void setActive(bool status); void updateRating(double newRating); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/snakeandladdergame/Board.cpp ================================================ #include "Board.hpp" #include Board::Board(int size) : size(size) {} int Board::getSize() const { return size; } void Board::addSnake(int start, int end) { if (start > end && start < size) { snakes[start] = end; } } void Board::addLadder(int start, int end) { if (end > start && end <= size) { ladders[start] = end; } } int Board::getNextPosition(int currentPos) const { // Check for snakes auto snakeIt = snakes.find(currentPos); if (snakeIt != snakes.end()) { std::cout << "Oops! Snake at position " << currentPos << ". Moving down to " << snakeIt->second << std::endl; return snakeIt->second; } // Check for ladders auto ladderIt = ladders.find(currentPos); if (ladderIt != ladders.end()) { std::cout << "Yay! Ladder at position " << currentPos << ". Moving up to " << ladderIt->second << std::endl; return ladderIt->second; } return currentPos; } void Board::displayInfo() const { std::cout << "\nBoard Information:" << std::endl; std::cout << "Size: " << size << " squares" << std::endl; std::cout << "\nSnakes:" << std::endl; for (const auto& snake : snakes) { std::cout << "From " << snake.first << " to " << snake.second << std::endl; } std::cout << "\nLadders:" << std::endl; for (const auto& ladder : ladders) { std::cout << "From " << ladder.first << " to " << ladder.second << std::endl; } } ================================================ FILE: solutions/cpp/snakeandladdergame/Board.hpp ================================================ #ifndef BOARD_HPP #define BOARD_HPP #include class Board { private: int size; std::map snakes; // start -> end std::map ladders; // start -> end public: Board(int size = 100); int getSize() const; void addSnake(int start, int end); void addLadder(int start, int end); int getNextPosition(int currentPos) const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/snakeandladdergame/Dice.cpp ================================================ #include "Dice.hpp" #include #include Dice::Dice(int sides) : sides(sides) { std::srand(static_cast(std::time(nullptr))); } int Dice::roll() const { return (std::rand() % sides) + 1; } ================================================ FILE: solutions/cpp/snakeandladdergame/Dice.hpp ================================================ #ifndef DICE_HPP #define DICE_HPP class Dice { private: int sides; public: Dice(int sides = 6); int roll() const; }; #endif ================================================ FILE: solutions/cpp/snakeandladdergame/Game.cpp ================================================ #include "Game.hpp" #include #include #include Game::Game(int boardSize) : board(boardSize), currentPlayerIndex(0), gameOver(false) {} Game::~Game() { for (auto player : players) { delete player; } } void Game::addPlayer(const std::string& name) { players.push_back(new Player(name)); } void Game::setupBoard() { // Add snakes board.addSnake(99, 10); board.addSnake(95, 75); board.addSnake(92, 88); board.addSnake(89, 68); board.addSnake(74, 53); board.addSnake(62, 19); board.addSnake(46, 25); board.addSnake(49, 11); // Add ladders board.addLadder(2, 38); board.addLadder(7, 14); board.addLadder(8, 31); board.addLadder(15, 26); board.addLadder(21, 42); board.addLadder(28, 84); board.addLadder(36, 44); board.addLadder(51, 67); board.addLadder(71, 91); board.addLadder(78, 98); board.displayInfo(); } bool Game::makeMove() { if (gameOver || players.empty()) return false; Player* currentPlayer = getCurrentPlayer(); std::cout << "\n" << currentPlayer->getName() << "'s turn" << std::endl; int roll = dice.roll(); std::cout << "Rolled: " << roll << std::endl; movePlayer(currentPlayer, roll); if (checkWin(currentPlayer)) { currentPlayer->setWinner(true); gameOver = true; std::cout << "\nCongratulations! " << currentPlayer->getName() << " wins!" << std::endl; return false; } currentPlayerIndex = (currentPlayerIndex + 1) % players.size(); return true; } void Game::play() { if (players.empty()) { std::cout << "No players in the game!" << std::endl; return; } std::cout << "\nStarting the game..." << std::endl; while (makeMove()) { displayStatus(); std::this_thread::sleep_for(std::chrono::seconds(1)); } } void Game::displayStatus() const { std::cout << "\nCurrent Game Status:" << std::endl; for (const auto& player : players) { std::cout << player->getName() << " at position " << player->getPosition() << std::endl; } } void Game::movePlayer(Player* player, int steps) { int newPosition = player->getPosition() + steps; if (newPosition > board.getSize()) { std::cout << "Cannot move, need exact number to finish" << std::endl; return; } newPosition = board.getNextPosition(newPosition); player->setPosition(newPosition); std::cout << player->getName() << " moved to position " << newPosition << std::endl; } bool Game::checkWin(Player* player) const { return player->getPosition() == board.getSize(); } Player* Game::getCurrentPlayer() const { return players[currentPlayerIndex]; } ================================================ FILE: solutions/cpp/snakeandladdergame/Game.hpp ================================================ #ifndef GAME_HPP #define GAME_HPP #include #include "Board.hpp" #include "Player.hpp" #include "Dice.hpp" class Game { private: Board board; std::vector players; Dice dice; int currentPlayerIndex; bool gameOver; public: Game(int boardSize = 100); ~Game(); void addPlayer(const std::string& name); void setupBoard(); bool makeMove(); void play(); void displayStatus() const; private: void movePlayer(Player* player, int steps); bool checkWin(Player* player) const; Player* getCurrentPlayer() const; }; #endif ================================================ FILE: solutions/cpp/snakeandladdergame/GameDemo.cpp ================================================ #include "Game.hpp" #include int main() { Game game; // Add players game.addPlayer("Player 1"); game.addPlayer("Player 2"); game.addPlayer("Player 3"); // Setup board with snakes and ladders game.setupBoard(); // Start the game game.play(); return 0; } ================================================ FILE: solutions/cpp/snakeandladdergame/Player.cpp ================================================ #include "Player.hpp" #include Player::Player(std::string name) : name(name), position(0), winner(false) {} std::string Player::getName() const { return name; } int Player::getPosition() const { return position; } bool Player::isWinner() const { return winner; } void Player::setPosition(int position) { this->position = position; } void Player::setWinner(bool status) { winner = status; } void Player::displayInfo() const { std::cout << "Player: " << name << std::endl; std::cout << "Position: " << position << std::endl; std::cout << "Status: " << (winner ? "Winner!" : "Playing") << std::endl; } ================================================ FILE: solutions/cpp/snakeandladdergame/Player.hpp ================================================ #ifndef PLAYER_HPP #define PLAYER_HPP #include class Player { private: std::string name; int position; bool winner; public: Player(std::string name); std::string getName() const; int getPosition() const; bool isWinner() const; void setPosition(int position); void setWinner(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/snakeandladdergame/README.md ================================================ # Designing Snake and Ladder Game ## Requirements 1. The game should be played on a board with numbered cells, typically with 100 cells. 2. The board should have a predefined set of snakes and ladders, connecting certain cells. 3. The game should support multiple players, each represented by a unique game piece. 4. Players should take turns rolling a dice to determine the number of cells to move forward. 5. If a player lands on a cell with the head of a snake, they should slide down to the cell with the tail of the snake. 6. If a player lands on a cell with the base of a ladder, they should climb up to the cell at the top of the ladder. 7. The game should continue until one of the players reaches the final cell on the board. 8. The game should handle multiple game sessions concurrently, allowing different groups of players to play independently. ## Classes, Interfaces and Enumerations 1. The **Board** class represents the game board with a fixed size (e.g., 100 cells). It contains the positions of snakes and ladders and provides methods to initialize them and retrieve the new position after encountering a snake or ladder. 2. The **Player** class represents a player in the game, with properties such as name and current position on the board. 3. The **Snake** class represents a snake on the board, with properties for the start and end positions. 4. The **Ladder** class represents a ladder on the board, with properties for the start and end positions. 5. The **Dice** class represents a dice used in the game, with a method to roll the dice and return a random value between 1 and 6. 6. The **SnakeAndLadderGame** class represents a single game session. It initializes the game with a board, a list of players, and a dice. The play method handles the game loop, where players take turns rolling the dice and moving their positions on the board. It checks for snakes and ladders and updates the player's position accordingly. The game continues until a player reaches the final position on the board. 7. The **GameManager** class is a singleton that manages multiple game sessions. It maintains a list of active games and provides a method to start a new game with a list of player names. Each game is started in a separate thread to allow concurrent game sessions. 8. The **SnakeAndLadderDemo** class demonstrates the usage of the game by creating an instance of the GameManager and starting two separate game sessions with different sets of players. ================================================ FILE: solutions/cpp/socialnetworkingservice/Post.cpp ================================================ #include "Post.hpp" #include #include Post::Post(std::string postId, std::string userId, std::string content) : postId(postId), userId(userId), content(content) { timestamp = std::time(nullptr); } std::string Post::getPostId() const { return postId; } std::string Post::getUserId() const { return userId; } std::string Post::getContent() const { return content; } std::time_t Post::getTimestamp() const { return timestamp; } const std::vector& Post::getLikes() const { return likes; } const std::vector& Post::getComments() const { return comments; } void Post::addLike(const std::string& userId) { if (std::find(likes.begin(), likes.end(), userId) == likes.end()) { likes.push_back(userId); } } void Post::removeLike(const std::string& userId) { auto it = std::find(likes.begin(), likes.end(), userId); if (it != likes.end()) { likes.erase(it); } } void Post::addComment(const std::string& comment) { comments.push_back(comment); } void Post::displayInfo() const { std::cout << "\nPost ID: " << postId << std::endl; std::cout << "Content: " << content << std::endl; std::cout << "Time: " << std::ctime(×tamp); std::cout << "Likes: " << likes.size() << std::endl; if (!comments.empty()) { std::cout << "Comments:" << std::endl; for (const auto& comment : comments) { std::cout << "- " << comment << std::endl; } } } ================================================ FILE: solutions/cpp/socialnetworkingservice/Post.hpp ================================================ #ifndef POST_HPP #define POST_HPP #include #include #include class Post { private: std::string postId; std::string userId; std::string content; std::time_t timestamp; std::vector likes; // Vector of userIds who liked std::vector comments; public: Post(std::string postId, std::string userId, std::string content); std::string getPostId() const; std::string getUserId() const; std::string getContent() const; std::time_t getTimestamp() const; const std::vector& getLikes() const; const std::vector& getComments() const; void addLike(const std::string& userId); void removeLike(const std::string& userId); void addComment(const std::string& comment); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/socialnetworkingservice/README.md ================================================ # Designing a Social Network Like Facebook ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their personal information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their information, such as profile picture, bio, and interests. - Users should be able to update their profile information. #### Friend Connections: - Users should be able to send friend requests to other users. - Users should be able to accept or decline friend requests. - Users should be able to view their list of friends. #### Posts and Newsfeed: - Users should be able to create posts with text, images, or videos. - Users should be able to view a newsfeed consisting of posts from their friends and their own posts. - The newsfeed should be sorted in reverse chronological order. #### Likes and Comments: - Users should be able to like and comment on posts. - Users should be able to view the list of likes and comments on a post. #### Privacy and Security: - Users should be able to control the visibility of their posts and profile information. - The system should enforce secure access control to ensure data privacy. #### Notifications: - Users should receive notifications for events such as friend requests, likes, comments, and mentions. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the social networking system, containing properties such as ID, name, email, password, profile picture, bio, list of friends, and list of posts. 2. The **Post** class represents a post created by a user, containing properties such as ID, user ID, content, image URLs, video URLs, timestamp, likes, and comments. 3. The **Comment** class represents a comment made by a user on a post, containing properties such as ID, user ID, post ID, content, and timestamp. 4. The **Notification** class represents a notification generated for a user, containing properties such as ID, user ID, notification type, content, and timestamp. 5. The **NotificationType** enum defines the different types of notifications, such as friend request, friend request accepted, like, comment, and mention. 6. The **SocialNetworkingService** class is the main class that manages the social networking system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SocialNetworkingService class provides methods for user registration, login, profile updates, friend requests, post creation, newsfeed generation, likes, comments, and notifications. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SocialNetworkingDemo** class demonstrates the usage of the social networking system by registering users, logging in, sending friend requests, creating posts, liking posts, commenting on posts, and retrieving newsfeed and notifications. ================================================ FILE: solutions/cpp/socialnetworkingservice/SocialNetwork.cpp ================================================ #include "SocialNetwork.hpp" #include #include SocialNetwork::SocialNetwork() : userIdCounter(1), postIdCounter(1) {} SocialNetwork::~SocialNetwork() { for (auto user : users) delete user; for (auto post : posts) delete post; } User* SocialNetwork::registerUser(const std::string& username, const std::string& email) { std::string userId = generateUserId(); User* user = new User(userId, username, email); users.push_back(user); return user; } void SocialNetwork::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { // Remove user from friends lists for (auto user : users) { user->removeFriend(userId); } // Remove user's posts posts.erase( std::remove_if(posts.begin(), posts.end(), [userId](Post* post) { return post->getUserId() == userId; }), posts.end() ); delete *it; users.erase(it); } } bool SocialNetwork::addFriend(const std::string& userId1, const std::string& userId2) { User* user1 = findUser(userId1); User* user2 = findUser(userId2); if (!user1 || !user2 || userId1 == userId2) return false; user1->addFriend(userId2); user2->addFriend(userId1); return true; } bool SocialNetwork::removeFriend(const std::string& userId1, const std::string& userId2) { User* user1 = findUser(userId1); User* user2 = findUser(userId2); if (!user1 || !user2) return false; user1->removeFriend(userId2); user2->removeFriend(userId1); return true; } Post* SocialNetwork::createPost(const std::string& userId, const std::string& content) { if (!findUser(userId)) return nullptr; std::string postId = generatePostId(); Post* post = new Post(postId, userId, content); posts.push_back(post); return post; } bool SocialNetwork::likePost(const std::string& userId, const std::string& postId) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post) return false; post->addLike(userId); return true; } bool SocialNetwork::unlikePost(const std::string& userId, const std::string& postId) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post) return false; post->removeLike(userId); return true; } bool SocialNetwork::addComment(const std::string& postId, const std::string& comment) { Post* post = findPost(postId); if (!post) return false; post->addComment(comment); return true; } void SocialNetwork::displayUserProfile(const std::string& userId) const { User* user = findUser(userId); if (user) { std::cout << "\nUser Profile:" << std::endl; user->displayInfo(); } } void SocialNetwork::displayUserFriends(const std::string& userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nFriends of " << user->getUsername() << ":" << std::endl; for (const auto& friendId : user->getFriends()) { if (User* friend_ = findUser(friendId)) { std::cout << "- " << friend_->getUsername() << std::endl; } } } void SocialNetwork::displayUserPosts(const std::string& userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nPosts by " << user->getUsername() << ":" << std::endl; for (const auto& post : posts) { if (post->getUserId() == userId) { post->displayInfo(); } } } void SocialNetwork::displayAllUsers() const { std::cout << "\nAll Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void SocialNetwork::displayAllPosts() const { std::cout << "\nAll Posts:" << std::endl; for (const auto& post : posts) { post->displayInfo(); std::cout << "------------------------" << std::endl; } } User* SocialNetwork::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Post* SocialNetwork::findPost(const std::string& postId) const { auto it = std::find_if(posts.begin(), posts.end(), [postId](Post* post) { return post->getPostId() == postId; }); return it != posts.end() ? *it : nullptr; } std::string SocialNetwork::generateUserId() { return "U" + std::to_string(userIdCounter++); } std::string SocialNetwork::generatePostId() { return "P" + std::to_string(postIdCounter++); } ================================================ FILE: solutions/cpp/socialnetworkingservice/SocialNetwork.hpp ================================================ #ifndef SOCIAL_NETWORK_HPP #define SOCIAL_NETWORK_HPP #include #include #include "User.hpp" #include "Post.hpp" class SocialNetwork { private: std::vector users; std::vector posts; int userIdCounter; int postIdCounter; public: SocialNetwork(); ~SocialNetwork(); // User management User* registerUser(const std::string& username, const std::string& email); void removeUser(const std::string& userId); bool addFriend(const std::string& userId1, const std::string& userId2); bool removeFriend(const std::string& userId1, const std::string& userId2); // Post management Post* createPost(const std::string& userId, const std::string& content); bool likePost(const std::string& userId, const std::string& postId); bool unlikePost(const std::string& userId, const std::string& postId); bool addComment(const std::string& postId, const std::string& comment); // Display functions void displayUserProfile(const std::string& userId) const; void displayUserFriends(const std::string& userId) const; void displayUserPosts(const std::string& userId) const; void displayAllUsers() const; void displayAllPosts() const; private: User* findUser(const std::string& userId) const; Post* findPost(const std::string& postId) const; std::string generateUserId(); std::string generatePostId(); }; #endif ================================================ FILE: solutions/cpp/socialnetworkingservice/SocialNetworkDemo.cpp ================================================ #include "SocialNetwork.hpp" #include #include #include int main() { SocialNetwork network; // Register users User* user1 = network.registerUser("john_doe", "john@email.com"); User* user2 = network.registerUser("jane_smith", "jane@email.com"); User* user3 = network.registerUser("bob_wilson", "bob@email.com"); std::cout << "Initial users:" << std::endl; network.displayAllUsers(); // Add friends network.addFriend(user1->getUserId(), user2->getUserId()); network.addFriend(user2->getUserId(), user3->getUserId()); // Create posts Post* post1 = network.createPost(user1->getUserId(), "Hello, world!"); Post* post2 = network.createPost(user2->getUserId(), "Having a great day!"); // Like and comment on posts network.likePost(user2->getUserId(), post1->getPostId()); network.likePost(user3->getUserId(), post1->getPostId()); network.addComment(post1->getPostId(), "Great post!"); network.likePost(user1->getUserId(), post2->getPostId()); network.addComment(post2->getPostId(), "Glad to hear that!"); // Display user profiles and posts std::cout << "\nUser Profiles and Posts:" << std::endl; network.displayUserProfile(user1->getUserId()); network.displayUserFriends(user1->getUserId()); network.displayUserPosts(user1->getUserId()); network.displayUserProfile(user2->getUserId()); network.displayUserFriends(user2->getUserId()); network.displayUserPosts(user2->getUserId()); // Remove a friend and display updated info network.removeFriend(user1->getUserId(), user2->getUserId()); std::cout << "\nAfter removing friendship:" << std::endl; network.displayUserFriends(user1->getUserId()); return 0; } ================================================ FILE: solutions/cpp/socialnetworkingservice/User.cpp ================================================ #include "User.hpp" #include User::User(std::string userId, std::string username, std::string email) : userId(userId), username(username), email(email), active(true) {} std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } const std::set& User::getFriends() const { return friends; } bool User::isActive() const { return active; } void User::addFriend(const std::string& friendId) { friends.insert(friendId); } void User::removeFriend(const std::string& friendId) { friends.erase(friendId); } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Friends: " << friends.size() << std::endl; } ================================================ FILE: solutions/cpp/socialnetworkingservice/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include #include class User { private: std::string userId; std::string username; std::string email; std::set friends; // Set of friend userIds bool active; public: User(std::string userId, std::string username, std::string email); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; const std::set& getFriends() const; bool isActive() const; void addFriend(const std::string& friendId); void removeFriend(const std::string& friendId); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/splitwise/Expense.cpp ================================================ #include "Expense.hpp" #include #include Expense::Expense(std::string expenseId, std::string description, double totalAmount, std::string paidBy, const std::vector& participants, ExpenseType type) : expenseId(expenseId), description(description), totalAmount(totalAmount), paidBy(paidBy), participants(participants), type(type) { timestamp = std::time(nullptr); if (type == ExpenseType::EQUAL) { calculateEqualShares(); } } std::string Expense::getExpenseId() const { return expenseId; } std::string Expense::getDescription() const { return description; } double Expense::getTotalAmount() const { return totalAmount; } std::string Expense::getPaidBy() const { return paidBy; } const std::vector& Expense::getParticipants() const { return participants; } const std::map& Expense::getShares() const { return shares; } ExpenseType Expense::getType() const { return type; } std::time_t Expense::getTimestamp() const { return timestamp; } void Expense::setShares(const std::map& shares) { this->shares = shares; } void Expense::calculateEqualShares() { double equalShare = totalAmount / participants.size(); for (const auto& participant : participants) { shares[participant] = equalShare; } } void Expense::displayInfo() const { std::cout << "\nExpense Details:" << std::endl; std::cout << "ID: " << expenseId << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Amount: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl; std::cout << "Paid by: " << paidBy << std::endl; std::cout << "Type: "; switch (type) { case ExpenseType::EQUAL: std::cout << "Equal"; break; case ExpenseType::EXACT: std::cout << "Exact"; break; case ExpenseType::PERCENT: std::cout << "Percent"; break; } std::cout << std::endl; std::cout << "Shares:" << std::endl; for (const auto& share : shares) { std::cout << share.first << ": $" << std::fixed << std::setprecision(2) << share.second << std::endl; } std::cout << "Time: " << std::ctime(×tamp); } ================================================ FILE: solutions/cpp/splitwise/Expense.hpp ================================================ #ifndef EXPENSE_HPP #define EXPENSE_HPP #include #include #include #include enum class ExpenseType { EQUAL, EXACT, PERCENT }; class Expense { private: std::string expenseId; std::string description; double totalAmount; std::string paidBy; std::vector participants; std::map shares; // userId -> share amount ExpenseType type; std::time_t timestamp; public: Expense(std::string expenseId, std::string description, double totalAmount, std::string paidBy, const std::vector& participants, ExpenseType type); std::string getExpenseId() const; std::string getDescription() const; double getTotalAmount() const; std::string getPaidBy() const; const std::vector& getParticipants() const; const std::map& getShares() const; ExpenseType getType() const; std::time_t getTimestamp() const; void setShares(const std::map& shares); void calculateEqualShares(); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/splitwise/README.md ================================================ # Designing Splitwise ## Requirements 1. The system should allow users to create accounts and manage their profile information. 2. Users should be able to create groups and add other users to the groups. 3. Users should be able to add expenses within a group, specifying the amount, description, and participants. 4. The system should automatically split the expenses among the participants based on their share. 5. Users should be able to view their individual balances with other users and settle up the balances. 6. The system should support different split methods, such as equal split, percentage split, and exact amounts. 7. Users should be able to view their transaction history and group expenses. 8. The system should handle concurrent transactions and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the Splitwise system, with properties such as ID, name, email, and a map to store balances with other users. 2. The **Group** class represents a group in Splitwise, containing a list of member users and a list of expenses. 3. The **Expense** class represents an expense within a group, with properties such as ID, amount, description, the user who paid, and a list of splits. 4. The **Split** class is an abstract class representing the split of an expense. It is extended by EqualSplit, PercentSplit, and ExactSplit classes to handle different split methods. 5. The **Transaction** class represents a transaction between two users, with properties such as ID, sender, receiver, and amount. 6. The **SplitwiseService** class is the main class that manages the Splitwise system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SplitwiseService class provides methods for adding users, groups, and expenses, splitting expenses, updating balances, settling balances, and creating transactions. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SplitwiseDemo** class demonstrates the usage of the Splitwise system by creating users, a group, adding an expense, settling balances, and printing user balances. ================================================ FILE: solutions/cpp/splitwise/SplitwiseDemo.cpp ================================================ #include "SplitwiseSystem.hpp" #include int main() { SplitwiseSystem splitwise; // Register users User* user1 = splitwise.registerUser("John", "john@email.com"); User* user2 = splitwise.registerUser("Alice", "alice@email.com"); User* user3 = splitwise.registerUser("Bob", "bob@email.com"); std::cout << "Initial users:" << std::endl; splitwise.displayUsers(); // Add expenses std::vector participants = { user1->getUserId(), user2->getUserId(), user3->getUserId() }; // Equal split expense Expense* dinner = splitwise.addExpense("Dinner", 300.0, user1->getUserId(), participants); // Custom split expense std::vector movieParticipants = { user1->getUserId(), user2->getUserId() }; Expense* movie = splitwise.addExpense("Movie", 100.0, user2->getUserId(), movieParticipants, ExpenseType::EXACT); std::map movieShares = { {user1->getUserId(), 60.0}, {user2->getUserId(), 40.0} }; splitwise.setExpenseShares(movie->getExpenseId(), movieShares); // Display expenses std::cout << "\nAll expenses:" << std::endl; splitwise.displayExpenses(); // Show balances std::cout << "\nBalances after expenses:" << std::endl; splitwise.showAllBalances(); // Show individual expenses std::cout << "\nJohn's expenses:" << std::endl; splitwise.displayUserExpenses(user1->getUserId()); return 0; } ================================================ FILE: solutions/cpp/splitwise/SplitwiseSystem.cpp ================================================ #include "SplitwiseSystem.hpp" #include #include #include SplitwiseSystem::SplitwiseSystem() : userIdCounter(1), expenseIdCounter(1) {} SplitwiseSystem::~SplitwiseSystem() { for (auto user : users) delete user; for (auto expense : expenses) delete expense; } User* SplitwiseSystem::registerUser(const std::string& name, const std::string& email) { std::string userId = generateUserId(); User* user = new User(userId, name, email); users.push_back(user); return user; } void SplitwiseSystem::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { delete *it; users.erase(it); } } Expense* SplitwiseSystem::addExpense(const std::string& description, double amount, const std::string& paidBy, const std::vector& participants, ExpenseType type) { if (!findUser(paidBy)) return nullptr; std::string expenseId = generateExpenseId(); Expense* expense = new Expense(expenseId, description, amount, paidBy, participants, type); expenses.push_back(expense); if (type == ExpenseType::EQUAL) { settleExpense(expenseId); } return expense; } bool SplitwiseSystem::setExpenseShares(const std::string& expenseId, const std::map& shares) { Expense* expense = findExpense(expenseId); if (!expense) return false; // Validate total shares equals expense amount double totalShares = std::accumulate(shares.begin(), shares.end(), 0.0, [](double sum, const auto& pair) { return sum + pair.second; }); if (std::abs(totalShares - expense->getTotalAmount()) > 0.01) return false; expense->setShares(shares); settleExpense(expenseId); return true; } void SplitwiseSystem::settleExpense(const std::string& expenseId) { Expense* expense = findExpense(expenseId); if (!expense) return; const std::string& paidBy = expense->getPaidBy(); const auto& shares = expense->getShares(); for (const auto& share : shares) { if (share.first != paidBy) { // Update balances for both users User* payer = findUser(paidBy); User* participant = findUser(share.first); if (payer && participant) { payer->updateBalance(share.first, share.second); participant->updateBalance(paidBy, -share.second); } } } } void SplitwiseSystem::showBalance(const std::string& userId) const { User* user = findUser(userId); if (!user) return; user->displayBalances(); } void SplitwiseSystem::showAllBalances() const { std::cout << "\nAll Balances:" << std::endl; for (const auto& user : users) { user->displayBalances(); } } void SplitwiseSystem::displayUsers() const { std::cout << "\nRegistered Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } void SplitwiseSystem::displayExpenses() const { std::cout << "\nAll Expenses:" << std::endl; for (const auto& expense : expenses) { expense->displayInfo(); std::cout << "------------------------" << std::endl; } } void SplitwiseSystem::displayUserExpenses(const std::string& userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nExpenses for " << user->getName() << ":" << std::endl; for (const auto& expense : expenses) { if (expense->getPaidBy() == userId || std::find(expense->getParticipants().begin(), expense->getParticipants().end(), userId) != expense->getParticipants().end()) { expense->displayInfo(); std::cout << "------------------------" << std::endl; } } } User* SplitwiseSystem::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Expense* SplitwiseSystem::findExpense(const std::string& expenseId) const { auto it = std::find_if(expenses.begin(), expenses.end(), [expenseId](Expense* expense) { return expense->getExpenseId() == expenseId; }); return it != expenses.end() ? *it : nullptr; } std::string SplitwiseSystem::generateUserId() { return "U" + std::to_string(userIdCounter++); } std::string SplitwiseSystem::generateExpenseId() { return "E" + std::to_string(expenseIdCounter++); } ================================================ FILE: solutions/cpp/splitwise/SplitwiseSystem.hpp ================================================ #ifndef SPLITWISE_SYSTEM_HPP #define SPLITWISE_SYSTEM_HPP #include #include #include "User.hpp" #include "Expense.hpp" class SplitwiseSystem { private: std::vector users; std::vector expenses; int userIdCounter; int expenseIdCounter; public: SplitwiseSystem(); ~SplitwiseSystem(); // User management User* registerUser(const std::string& name, const std::string& email); void removeUser(const std::string& userId); // Expense management Expense* addExpense(const std::string& description, double amount, const std::string& paidBy, const std::vector& participants, ExpenseType type = ExpenseType::EQUAL); bool setExpenseShares(const std::string& expenseId, const std::map& shares); // Balance management void settleExpense(const std::string& expenseId); void showBalance(const std::string& userId) const; void showAllBalances() const; // Display functions void displayUsers() const; void displayExpenses() const; void displayUserExpenses(const std::string& userId) const; private: User* findUser(const std::string& userId) const; Expense* findExpense(const std::string& expenseId) const; void updateBalances(Expense* expense); std::string generateUserId(); std::string generateExpenseId(); }; #endif ================================================ FILE: solutions/cpp/splitwise/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string name, std::string email) : userId(userId), name(name), email(email), active(true) {} std::string User::getUserId() const { return userId; } std::string User::getName() const { return name; } std::string User::getEmail() const { return email; } bool User::isActive() const { return active; } double User::getBalanceWith(const std::string& userId) const { auto it = balances.find(userId); return it != balances.end() ? it->second : 0.0; } const std::map& User::getBalances() const { return balances; } void User::updateBalance(const std::string& userId, double amount) { balances[userId] += amount; } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << name << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; } void User::displayBalances() const { std::cout << "\nBalances for " << name << ":" << std::endl; for (const auto& balance : balances) { std::cout << "With " << balance.first << ": $" << std::fixed << std::setprecision(2) << balance.second << std::endl; } } ================================================ FILE: solutions/cpp/splitwise/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include class User { private: std::string userId; std::string name; std::string email; std::map balances; // userId -> amount bool active; public: User(std::string userId, std::string name, std::string email); std::string getUserId() const; std::string getName() const; std::string getEmail() const; bool isActive() const; double getBalanceWith(const std::string& userId) const; const std::map& getBalances() const; void updateBalance(const std::string& userId, double amount); void setActive(bool status); void displayInfo() const; void displayBalances() const; }; #endif ================================================ FILE: solutions/cpp/stackoverflow/Comment.cpp ================================================ #include "Comment.hpp" #include Comment::Comment(std::string commentId, std::string userId, std::string content) : commentId(commentId), userId(userId), content(content) { timestamp = std::time(nullptr); } std::string Comment::getCommentId() const { return commentId; } std::string Comment::getUserId() const { return userId; } std::string Comment::getContent() const { return content; } std::time_t Comment::getTimestamp() const { return timestamp; } void Comment::displayInfo() const { std::cout << "- " << content << " (by User " << userId << ")" << std::endl; } ================================================ FILE: solutions/cpp/stackoverflow/Comment.hpp ================================================ #ifndef COMMENT_HPP #define COMMENT_HPP #include #include class Comment { private: std::string commentId; std::string userId; std::string content; std::time_t timestamp; public: Comment(std::string commentId, std::string userId, std::string content); std::string getCommentId() const; std::string getUserId() const; std::string getContent() const; std::time_t getTimestamp() const; void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/stackoverflow/Post.cpp ================================================ #include "Post.hpp" #include #include Post::Post(std::string postId, std::string userId, std::string content, const std::vector& tags, PostType type) : postId(postId), userId(userId), content(content), tags(tags), score(0), accepted(false), type(type) { timestamp = std::time(nullptr); } Post::~Post() { for (auto comment : comments) { delete comment; } } std::string Post::getPostId() const { return postId; } std::string Post::getUserId() const { return userId; } std::string Post::getContent() const { return content; } const std::vector& Post::getTags() const { return tags; } const std::vector& Post::getComments() const { return comments; } int Post::getScore() const { return score; } bool Post::isAccepted() const { return accepted; } PostType Post::getType() const { return type; } std::time_t Post::getTimestamp() const { return timestamp; } void Post::addComment(Comment* comment) { comments.push_back(comment); } bool Post::addVote(const std::string& userId) { if (std::find(votes.begin(), votes.end(), userId) == votes.end()) { votes.push_back(userId); score++; return true; } return false; } bool Post::removeVote(const std::string& userId) { auto it = std::find(votes.begin(), votes.end(), userId); if (it != votes.end()) { votes.erase(it); score--; return true; } return false; } void Post::setAccepted(bool status) { accepted = status; } void Post::displayInfo() const { std::cout << "\nPost ID: " << postId << std::endl; std::cout << "Type: " << (type == PostType::QUESTION ? "Question" : "Answer") << std::endl; std::cout << "Content: " << content << std::endl; std::cout << "Score: " << score << std::endl; std::cout << "Status: " << (accepted ? "Accepted" : "Not Accepted") << std::endl; if (!tags.empty()) { std::cout << "Tags: "; for (const auto& tag : tags) { std::cout << tag << " "; } std::cout << std::endl; } if (!comments.empty()) { std::cout << "Comments:" << std::endl; for (const auto& comment : comments) { comment->displayInfo(); } } std::cout << "Time: " << std::ctime(×tamp); } ================================================ FILE: solutions/cpp/stackoverflow/Post.hpp ================================================ #ifndef POST_HPP #define POST_HPP #include #include #include #include "Comment.hpp" enum class PostType { QUESTION, ANSWER }; class Post { private: std::string postId; std::string userId; std::string content; std::vector tags; std::vector comments; std::vector votes; // userIds who voted int score; bool accepted; PostType type; std::time_t timestamp; public: Post(std::string postId, std::string userId, std::string content, const std::vector& tags, PostType type); ~Post(); std::string getPostId() const; std::string getUserId() const; std::string getContent() const; const std::vector& getTags() const; const std::vector& getComments() const; int getScore() const; bool isAccepted() const; PostType getType() const; std::time_t getTimestamp() const; void addComment(Comment* comment); bool addVote(const std::string& userId); bool removeVote(const std::string& userId); void setAccepted(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/stackoverflow/README.md ================================================ # Designing Stack Overflow ## Requirements 1. Users can post questions, answer questions, and comment on questions and answers. 2. Users can vote on questions and answers. 3. Questions should have tags associated with them. 4. Users can search for questions based on keywords, tags, or user profiles. 5. The system should assign reputation score to users based on their activity and the quality of their contributions. 6. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the Stack Overflow system, with properties such as id, username, email, and reputation. 2. The **Question** class represents a question posted by a user, with properties such as id, title, content, author, answers, comments, tags, votes and creation date. 3. The **Answer** class represents an answer to a question, with properties such as id, content, author, associated question, comments, votes and creation date. 4. The **Comment** class represents a comment on a question or an answer, with properties such as id, content, author, and creation date. 5. The **Tag** class represents a tag associated with a question, with properties such as id and name. 6. The **Vote** class represents vote associated with a question/answer. 7. The **StackOverflow** class is the main class that manages the Stack Overflow system. It provides methods for creating user, posting questions, answers, and comments, voting on questions and answers, searching for questions, and retrieving questions by tags and users. 8. The **StackOverflowDemo** class demonstrates the usage of the Stack Overflow system by creating users, posting questions and answers, voting, searching for questions, and retrieving questions by tags and users. ================================================ FILE: solutions/cpp/stackoverflow/StackOverflow.cpp ================================================ #include "StackOverflow.hpp" #include #include StackOverflow::StackOverflow() : userIdCounter(1), postIdCounter(1), commentIdCounter(1) {} StackOverflow::~StackOverflow() { for (auto user : users) delete user; for (auto post : posts) delete post; } User* StackOverflow::registerUser(const std::string& username, const std::string& email) { std::string userId = generateUserId(); User* user = new User(userId, username, email); users.push_back(user); return user; } void StackOverflow::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { delete *it; users.erase(it); } } Post* StackOverflow::addQuestion(const std::string& userId, const std::string& content, const std::vector& tags) { if (!findUser(userId)) return nullptr; std::string postId = generatePostId(); Post* question = new Post(postId, userId, content, tags, PostType::QUESTION); posts.push_back(question); return question; } Post* StackOverflow::addAnswer(const std::string& userId, const std::string& questionId, const std::string& content) { if (!findUser(userId)) return nullptr; Post* question = findPost(questionId); if (!question || question->getType() != PostType::QUESTION) return nullptr; std::string postId = generatePostId(); Post* answer = new Post(postId, userId, content, std::vector(), PostType::ANSWER); posts.push_back(answer); return answer; } Comment* StackOverflow::addComment(const std::string& userId, const std::string& postId, const std::string& content) { if (!findUser(userId)) return nullptr; Post* post = findPost(postId); if (!post) return nullptr; std::string commentId = generateCommentId(); Comment* comment = new Comment(commentId, userId, content); post->addComment(comment); return comment; } bool StackOverflow::votePost(const std::string& userId, const std::string& postId) { User* user = findUser(userId); Post* post = findPost(postId); if (!user || !post || userId == post->getUserId()) return false; if (post->addVote(userId)) { updateUserReputation(post->getUserId(), 10); // +10 for upvote return true; } return false; } bool StackOverflow::unvotePost(const std::string& userId, const std::string& postId) { Post* post = findPost(postId); if (!post) return false; if (post->removeVote(userId)) { updateUserReputation(post->getUserId(), -10); // -10 for removed upvote return true; } return false; } bool StackOverflow::acceptAnswer(const std::string& userId, const std::string& answerId) { Post* answer = findPost(answerId); if (!answer || answer->getType() != PostType::ANSWER) return false; answer->setAccepted(true); updateUserReputation(answer->getUserId(), 15); // +15 for accepted answer return true; } std::vector StackOverflow::searchQuestions(const std::string& tag) const { std::vector results; for (const auto& post : posts) { if (post->getType() == PostType::QUESTION) { const auto& tags = post->getTags(); if (std::find(tags.begin(), tags.end(), tag) != tags.end()) { results.push_back(post); } } } return results; } void StackOverflow::displayUserProfile(const std::string& userId) const { User* user = findUser(userId); if (!user) return; user->displayInfo(); std::cout << "\nPosts by " << user->getUsername() << ":" << std::endl; for (const auto& post : posts) { if (post->getUserId() == userId) { post->displayInfo(); } } } void StackOverflow::displayQuestion(const std::string& questionId) const { Post* question = findPost(questionId); if (!question || question->getType() != PostType::QUESTION) return; question->displayInfo(); std::cout << "\nAnswers:" << std::endl; for (const auto& post : posts) { if (post->getType() == PostType::ANSWER) { post->displayInfo(); } } } void StackOverflow::displayAllQuestions() const { std::cout << "\nAll Questions:" << std::endl; for (const auto& post : posts) { if (post->getType() == PostType::QUESTION) { post->displayInfo(); std::cout << "------------------------" << std::endl; } } } User* StackOverflow::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Post* StackOverflow::findPost(const std::string& postId) const { auto it = std::find_if(posts.begin(), posts.end(), [postId](Post* post) { return post->getPostId() == postId; }); return it != posts.end() ? *it : nullptr; } void StackOverflow::updateUserReputation(const std::string& userId, int points) { if (User* user = findUser(userId)) { user->updateReputation(points); } } std::string StackOverflow::generateUserId() { return "U" + std::to_string(userIdCounter++); } std::string StackOverflow::generatePostId() { return "P" + std::to_string(postIdCounter++); } std::string StackOverflow::generateCommentId() { return "C" + std::to_string(commentIdCounter++); } ================================================ FILE: solutions/cpp/stackoverflow/StackOverflow.hpp ================================================ #ifndef STACK_OVERFLOW_HPP #define STACK_OVERFLOW_HPP #include #include #include "User.hpp" #include "Post.hpp" #include "Comment.hpp" class StackOverflow { private: std::vector users; std::vector posts; int userIdCounter; int postIdCounter; int commentIdCounter; public: StackOverflow(); ~StackOverflow(); // User management User* registerUser(const std::string& username, const std::string& email); void removeUser(const std::string& userId); // Post management Post* addQuestion(const std::string& userId, const std::string& content, const std::vector& tags); Post* addAnswer(const std::string& userId, const std::string& questionId, const std::string& content); Comment* addComment(const std::string& userId, const std::string& postId, const std::string& content); // Voting and acceptance bool votePost(const std::string& userId, const std::string& postId); bool unvotePost(const std::string& userId, const std::string& postId); bool acceptAnswer(const std::string& userId, const std::string& answerId); // Search and display std::vector searchQuestions(const std::string& tag) const; void displayUserProfile(const std::string& userId) const; void displayQuestion(const std::string& questionId) const; void displayAllQuestions() const; private: User* findUser(const std::string& userId) const; Post* findPost(const std::string& postId) const; void updateUserReputation(const std::string& userId, int points); std::string generateUserId(); std::string generatePostId(); std::string generateCommentId(); }; #endif ================================================ FILE: solutions/cpp/stackoverflow/StackOverflowDemo.cpp ================================================ #include "StackOverflow.hpp" #include int main() { StackOverflow stackoverflow; // Register users User* user1 = stackoverflow.registerUser("john_doe", "john@email.com"); User* user2 = stackoverflow.registerUser("alice_smith", "alice@email.com"); User* user3 = stackoverflow.registerUser("bob_wilson", "bob@email.com"); std::cout << "Initial users:" << std::endl; stackoverflow.displayUserProfile(user1->getUserId()); // Add questions std::vector tags = {"c++", "programming"}; Post* question1 = stackoverflow.addQuestion( user1->getUserId(), "How do I use smart pointers in C++?", tags ); // Add answers Post* answer1 = stackoverflow.addAnswer( user2->getUserId(), question1->getPostId(), "Smart pointers automatically manage memory for you..." ); Post* answer2 = stackoverflow.addAnswer( user3->getUserId(), question1->getPostId(), "There are three main types of smart pointers..." ); // Add comments stackoverflow.addComment( user1->getUserId(), answer1->getPostId(), "Thanks, that's helpful!" ); // Vote on posts stackoverflow.votePost(user2->getUserId(), question1->getPostId()); stackoverflow.votePost(user3->getUserId(), answer1->getPostId()); stackoverflow.votePost(user1->getUserId(), answer2->getPostId()); // Accept answer stackoverflow.acceptAnswer(user1->getUserId(), answer1->getPostId()); // Display results std::cout << "\nQuestion with answers:" << std::endl; stackoverflow.displayQuestion(question1->getPostId()); std::cout << "\nUser profiles after activity:" << std::endl; stackoverflow.displayUserProfile(user1->getUserId()); stackoverflow.displayUserProfile(user2->getUserId()); // Search questions std::cout << "\nSearching for C++ questions:" << std::endl; auto results = stackoverflow.searchQuestions("c++"); for (const auto& question : results) { question->displayInfo(); } return 0; } ================================================ FILE: solutions/cpp/stackoverflow/User.cpp ================================================ #include "User.hpp" #include User::User(std::string userId, std::string username, std::string email) : userId(userId), username(username), email(email), reputation(1), active(true) {} std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } int User::getReputation() const { return reputation; } const std::vector& User::getBadges() const { return badges; } bool User::isActive() const { return active; } void User::updateReputation(int points) { reputation += points; } void User::addBadge(const std::string& badge) { badges.push_back(badge); } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Reputation: " << reputation << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; if (!badges.empty()) { std::cout << "Badges:" << std::endl; for (const auto& badge : badges) { std::cout << "- " << badge << std::endl; } } } ================================================ FILE: solutions/cpp/stackoverflow/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include class User { private: std::string userId; std::string username; std::string email; int reputation; std::vector badges; bool active; public: User(std::string userId, std::string username, std::string email); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; int getReputation() const; const std::vector& getBadges() const; bool isActive() const; void updateReputation(int points); void addBadge(const std::string& badge); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/taskmanagementsystem/README.md ================================================ # Designing a Task Management System ## Requirements 1. The task management system should allow users to create, update, and delete tasks. 2. Each task should have a title, description, due date, priority, and status (e.g., pending, in progress, completed). 3. Users should be able to assign tasks to other users and set reminders for tasks. 4. The system should support searching and filtering tasks based on various criteria (e.g., priority, due date, assigned user). 5. Users should be able to mark tasks as completed and view their task history. 6. The system should handle concurrent access to tasks and ensure data consistency. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the task management system, with properties such as id, name, and email. 2. The **TaskStatus** enum defines the possible states of a task, such as pending, in progress, and completed. 3. The **Task** class represents a task in the system, with properties like id, title, description, due date, priority, status, and assigned user. 4. The **TaskManager** class is the core of the task management system and follows the Singleton pattern to ensure a single instance of the task manager. 5. The TaskManager class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to tasks and ensure thread safety. 6. The TaskManager class provides methods for creating, updating, deleting, searching, and filtering tasks, as well as marking tasks as completed and retrieving task history for a user. 7. The **TaskManagementSystem** class serves as the entry point of the application and demonstrates the usage of the task management system. ================================================ FILE: solutions/cpp/taskmanagementsystem/Task.cpp ================================================ #include "Task.hpp" #include #include #include Task::Task(std::string taskId, std::string title, std::string description, TaskPriority priority) : taskId(taskId), title(title), description(description), status(TaskStatus::TODO), priority(priority) { dueDate = 0; // No due date set } std::string Task::getTaskId() const { return taskId; } std::string Task::getTitle() const { return title; } std::string Task::getDescription() const { return description; } std::string Task::getAssignedTo() const { return assignedTo; } TaskStatus Task::getStatus() const { return status; } TaskPriority Task::getPriority() const { return priority; } std::time_t Task::getDueDate() const { return dueDate; } const std::vector& Task::getDependencies() const { return dependencies; } const std::vector& Task::getComments() const { return comments; } void Task::setAssignedTo(const std::string& userId) { assignedTo = userId; } void Task::setStatus(TaskStatus status) { this->status = status; } void Task::setPriority(TaskPriority priority) { this->priority = priority; } void Task::setDueDate(std::time_t dueDate) { this->dueDate = dueDate; } void Task::addDependency(const std::string& taskId) { if (std::find(dependencies.begin(), dependencies.end(), taskId) == dependencies.end()) { dependencies.push_back(taskId); } } void Task::removeDependency(const std::string& taskId) { auto it = std::find(dependencies.begin(), dependencies.end(), taskId); if (it != dependencies.end()) { dependencies.erase(it); } } void Task::addComment(const std::string& comment) { comments.push_back(comment); } void Task::displayInfo() const { std::cout << "\nTask: " << title << " (ID: " << taskId << ")" << std::endl; std::cout << "Description: " << description << std::endl; std::cout << "Assigned to: " << (assignedTo.empty() ? "Unassigned" : assignedTo) << std::endl; std::cout << "Status: "; switch (status) { case TaskStatus::TODO: std::cout << "To Do"; break; case TaskStatus::IN_PROGRESS: std::cout << "In Progress"; break; case TaskStatus::COMPLETED: std::cout << "Completed"; break; case TaskStatus::BLOCKED: std::cout << "Blocked"; break; } std::cout << std::endl; std::cout << "Priority: "; switch (priority) { case TaskPriority::LOW: std::cout << "Low"; break; case TaskPriority::MEDIUM: std::cout << "Medium"; break; case TaskPriority::HIGH: std::cout << "High"; break; case TaskPriority::URGENT: std::cout << "Urgent"; break; } std::cout << std::endl; if (dueDate != 0) { std::cout << "Due Date: " << std::ctime(&dueDate); } if (!dependencies.empty()) { std::cout << "Dependencies: "; for (const auto& dep : dependencies) { std::cout << dep << " "; } std::cout << std::endl; } if (!comments.empty()) { std::cout << "Comments:" << std::endl; for (const auto& comment : comments) { std::cout << "- " << comment << std::endl; } } } ================================================ FILE: solutions/cpp/taskmanagementsystem/Task.hpp ================================================ #ifndef TASK_HPP #define TASK_HPP #include #include #include enum class TaskStatus { TODO, IN_PROGRESS, COMPLETED, BLOCKED }; enum class TaskPriority { LOW, MEDIUM, HIGH, URGENT }; class Task { private: std::string taskId; std::string title; std::string description; std::string assignedTo; TaskStatus status; TaskPriority priority; std::time_t dueDate; std::vector dependencies; // Task IDs std::vector comments; public: Task(std::string taskId, std::string title, std::string description, TaskPriority priority = TaskPriority::MEDIUM); std::string getTaskId() const; std::string getTitle() const; std::string getDescription() const; std::string getAssignedTo() const; TaskStatus getStatus() const; TaskPriority getPriority() const; std::time_t getDueDate() const; const std::vector& getDependencies() const; const std::vector& getComments() const; void setAssignedTo(const std::string& userId); void setStatus(TaskStatus status); void setPriority(TaskPriority priority); void setDueDate(std::time_t dueDate); void addDependency(const std::string& taskId); void removeDependency(const std::string& taskId); void addComment(const std::string& comment); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/taskmanagementsystem/TaskManager.cpp ================================================ #include "TaskManager.hpp" #include #include TaskManager::TaskManager() : taskIdCounter(1), userIdCounter(1) {} TaskManager::~TaskManager() { for (auto user : users) delete user; for (auto task : tasks) delete task; } User* TaskManager::registerUser(const std::string& username, const std::string& email) { std::string userId = generateUserId(); User* user = new User(userId, username, email); users.push_back(user); return user; } void TaskManager::removeUser(const std::string& userId) { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); if (it != users.end()) { // Unassign all tasks from this user for (auto task : tasks) { if (task->getAssignedTo() == userId) { task->setAssignedTo(""); } } delete *it; users.erase(it); } } Task* TaskManager::createTask(const std::string& title, const std::string& description, TaskPriority priority) { std::string taskId = generateTaskId(); Task* task = new Task(taskId, title, description, priority); tasks.push_back(task); return task; } void TaskManager::removeTask(const std::string& taskId) { auto it = std::find_if(tasks.begin(), tasks.end(), [taskId](Task* task) { return task->getTaskId() == taskId; }); if (it != tasks.end()) { // Remove task from user's assigned tasks if (!(*it)->getAssignedTo().empty()) { if (User* user = findUser((*it)->getAssignedTo())) { user->removeTask(taskId); } } // Remove task from dependencies for (auto task : tasks) { task->removeDependency(taskId); } delete *it; tasks.erase(it); } } bool TaskManager::assignTask(const std::string& taskId, const std::string& userId) { Task* task = findTask(taskId); User* user = findUser(userId); if (!task || !user) return false; // Remove task from previous assignee if (!task->getAssignedTo().empty()) { if (User* prevUser = findUser(task->getAssignedTo())) { prevUser->removeTask(taskId); } } task->setAssignedTo(userId); user->addTask(taskId); return true; } bool TaskManager::updateTaskStatus(const std::string& taskId, TaskStatus status) { Task* task = findTask(taskId); if (!task) return false; if (status == TaskStatus::IN_PROGRESS && !checkDependenciesMet(task)) { std::cout << "Cannot start task: dependencies not met" << std::endl; return false; } task->setStatus(status); return true; } bool TaskManager::addTaskDependency(const std::string& taskId, const std::string& dependencyId) { Task* task = findTask(taskId); Task* dependency = findTask(dependencyId); if (!task || !dependency || taskId == dependencyId) return false; task->addDependency(dependencyId); return true; } bool TaskManager::addTaskComment(const std::string& taskId, const std::string& comment) { Task* task = findTask(taskId); if (!task) return false; task->addComment(comment); return true; } void TaskManager::displayUserTasks(const std::string& userId) const { User* user = findUser(userId); if (!user) return; std::cout << "\nTasks assigned to " << user->getUsername() << ":" << std::endl; for (const auto& taskId : user->getAssignedTasks()) { if (Task* task = findTask(taskId)) { task->displayInfo(); } } } void TaskManager::displayAllTasks() const { std::cout << "\nAll Tasks:" << std::endl; for (const auto& task : tasks) { task->displayInfo(); std::cout << "------------------------" << std::endl; } } void TaskManager::displayAllUsers() const { std::cout << "\nAll Users:" << std::endl; for (const auto& user : users) { user->displayInfo(); std::cout << "------------------------" << std::endl; } } std::vector TaskManager::getTasksByStatus(TaskStatus status) const { std::vector result; std::copy_if(tasks.begin(), tasks.end(), std::back_inserter(result), [status](Task* task) { return task->getStatus() == status; }); return result; } std::vector TaskManager::getTasksByPriority(TaskPriority priority) const { std::vector result; std::copy_if(tasks.begin(), tasks.end(), std::back_inserter(result), [priority](Task* task) { return task->getPriority() == priority; }); return result; } User* TaskManager::findUser(const std::string& userId) const { auto it = std::find_if(users.begin(), users.end(), [userId](User* user) { return user->getUserId() == userId; }); return it != users.end() ? *it : nullptr; } Task* TaskManager::findTask(const std::string& taskId) const { auto it = std::find_if(tasks.begin(), tasks.end(), [taskId](Task* task) { return task->getTaskId() == taskId; }); return it != tasks.end() ? *it : nullptr; } bool TaskManager::checkDependenciesMet(const Task* task) const { for (const auto& depId : task->getDependencies()) { Task* dependency = findTask(depId); if (!dependency || dependency->getStatus() != TaskStatus::COMPLETED) { return false; } } return true; } std::string TaskManager::generateTaskId() { return "T" + std::to_string(taskIdCounter++); } std::string TaskManager::generateUserId() { return "U" + std::to_string(userIdCounter++); } ================================================ FILE: solutions/cpp/taskmanagementsystem/TaskManager.hpp ================================================ #ifndef TASK_MANAGER_HPP #define TASK_MANAGER_HPP #include #include #include "Task.hpp" #include "User.hpp" class TaskManager { private: std::vector tasks; std::vector users; int taskIdCounter; int userIdCounter; public: TaskManager(); ~TaskManager(); // User management User* registerUser(const std::string& username, const std::string& email); void removeUser(const std::string& userId); // Task management Task* createTask(const std::string& title, const std::string& description, TaskPriority priority = TaskPriority::MEDIUM); void removeTask(const std::string& taskId); bool assignTask(const std::string& taskId, const std::string& userId); bool updateTaskStatus(const std::string& taskId, TaskStatus status); bool addTaskDependency(const std::string& taskId, const std::string& dependencyId); bool addTaskComment(const std::string& taskId, const std::string& comment); // Display functions void displayUserTasks(const std::string& userId) const; void displayAllTasks() const; void displayAllUsers() const; std::vector getTasksByStatus(TaskStatus status) const; std::vector getTasksByPriority(TaskPriority priority) const; private: User* findUser(const std::string& userId) const; Task* findTask(const std::string& taskId) const; bool checkDependenciesMet(const Task* task) const; std::string generateTaskId(); std::string generateUserId(); }; #endif ================================================ FILE: solutions/cpp/taskmanagementsystem/TaskManagerDemo.cpp ================================================ #include "TaskManager.hpp" #include int main() { TaskManager manager; // Register users User* user1 = manager.registerUser("john_doe", "john@email.com"); User* user2 = manager.registerUser("alice_smith", "alice@email.com"); std::cout << "Initial users:" << std::endl; manager.displayAllUsers(); // Create tasks Task* task1 = manager.createTask("Design Database", "Create database schema", TaskPriority::HIGH); Task* task2 = manager.createTask("Implement API", "Develop REST API endpoints", TaskPriority::MEDIUM); Task* task3 = manager.createTask("Write Tests", "Create unit tests", TaskPriority::MEDIUM); // Add dependencies manager.addTaskDependency(task2->getTaskId(), task1->getTaskId()); // API depends on DB manager.addTaskDependency(task3->getTaskId(), task2->getTaskId()); // Tests depend on API // Assign tasks manager.assignTask(task1->getTaskId(), user1->getUserId()); manager.assignTask(task2->getTaskId(), user2->getUserId()); manager.assignTask(task3->getTaskId(), user2->getUserId()); // Update task status manager.updateTaskStatus(task1->getTaskId(), TaskStatus::IN_PROGRESS); manager.addTaskComment(task1->getTaskId(), "Started working on schema design"); // Try to start dependent task (should fail) manager.updateTaskStatus(task2->getTaskId(), TaskStatus::IN_PROGRESS); // Complete first task manager.updateTaskStatus(task1->getTaskId(), TaskStatus::COMPLETED); manager.addTaskComment(task1->getTaskId(), "Database schema completed"); // Now can start dependent task manager.updateTaskStatus(task2->getTaskId(), TaskStatus::IN_PROGRESS); // Display current state std::cout << "\nAll tasks:" << std::endl; manager.displayAllTasks(); std::cout << "\nTasks by user:" << std::endl; manager.displayUserTasks(user1->getUserId()); manager.displayUserTasks(user2->getUserId()); // Display tasks by status std::cout << "\nIn Progress Tasks:" << std::endl; auto inProgressTasks = manager.getTasksByStatus(TaskStatus::IN_PROGRESS); for (const auto& task : inProgressTasks) { task->displayInfo(); } return 0; } ================================================ FILE: solutions/cpp/taskmanagementsystem/User.cpp ================================================ #include "User.hpp" #include #include User::User(std::string userId, std::string username, std::string email) : userId(userId), username(username), email(email), active(true) {} std::string User::getUserId() const { return userId; } std::string User::getUsername() const { return username; } std::string User::getEmail() const { return email; } const std::vector& User::getAssignedTasks() const { return assignedTasks; } bool User::isActive() const { return active; } void User::addTask(const std::string& taskId) { if (std::find(assignedTasks.begin(), assignedTasks.end(), taskId) == assignedTasks.end()) { assignedTasks.push_back(taskId); } } void User::removeTask(const std::string& taskId) { auto it = std::find(assignedTasks.begin(), assignedTasks.end(), taskId); if (it != assignedTasks.end()) { assignedTasks.erase(it); } } void User::setActive(bool status) { active = status; } void User::displayInfo() const { std::cout << "User: " << username << " (ID: " << userId << ")" << std::endl; std::cout << "Email: " << email << std::endl; std::cout << "Status: " << (active ? "Active" : "Inactive") << std::endl; std::cout << "Assigned Tasks: " << assignedTasks.size() << std::endl; } ================================================ FILE: solutions/cpp/taskmanagementsystem/User.hpp ================================================ #ifndef USER_HPP #define USER_HPP #include #include class User { private: std::string userId; std::string username; std::string email; std::vector assignedTasks; // Task IDs bool active; public: User(std::string userId, std::string username, std::string email); std::string getUserId() const; std::string getUsername() const; std::string getEmail() const; const std::vector& getAssignedTasks() const; bool isActive() const; void addTask(const std::string& taskId); void removeTask(const std::string& taskId); void setActive(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/tictactoe/Board.cpp ================================================ #include "Board.hpp" #include #include Board::Board(int size) : size(size), EMPTY('-') { reset(); } int Board::getSize() const { return size; } char Board::getCell(int row, int col) const { return grid[row][col]; } bool Board::isEmpty(int row, int col) const { return grid[row][col] == EMPTY; } bool Board::isValidPosition(int row, int col) const { return row >= 0 && row < size && col >= 0 && col < size; } bool Board::makeMove(int row, int col, char symbol) { if (!isValidPosition(row, col) || !isEmpty(row, col)) { return false; } grid[row][col] = symbol; return true; } bool Board::isFull() const { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (isEmpty(i, j)) return false; } } return true; } bool Board::checkWin(char symbol) const { return checkRows(symbol) || checkColumns(symbol) || checkDiagonals(symbol); } void Board::display() const { std::cout << "\nCurrent Board:" << std::endl; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { std::cout << std::setw(3) << grid[i][j]; } std::cout << std::endl; } std::cout << std::endl; } void Board::reset() { grid.resize(size, std::vector(size, EMPTY)); } bool Board::checkRows(char symbol) const { for (int i = 0; i < size; i++) { bool win = true; for (int j = 0; j < size; j++) { if (grid[i][j] != symbol) { win = false; break; } } if (win) return true; } return false; } bool Board::checkColumns(char symbol) const { for (int j = 0; j < size; j++) { bool win = true; for (int i = 0; i < size; i++) { if (grid[i][j] != symbol) { win = false; break; } } if (win) return true; } return false; } bool Board::checkDiagonals(char symbol) const { // Check main diagonal bool win = true; for (int i = 0; i < size; i++) { if (grid[i][i] != symbol) { win = false; break; } } if (win) return true; // Check other diagonal win = true; for (int i = 0; i < size; i++) { if (grid[i][size-1-i] != symbol) { win = false; break; } } return win; } ================================================ FILE: solutions/cpp/tictactoe/Board.hpp ================================================ #ifndef BOARD_HPP #define BOARD_HPP #include #include class Board { private: std::vector> grid; const int size; const char EMPTY; public: Board(int size = 3); int getSize() const; char getCell(int row, int col) const; bool isEmpty(int row, int col) const; bool isValidPosition(int row, int col) const; bool makeMove(int row, int col, char symbol); bool isFull() const; bool checkWin(char symbol) const; void display() const; void reset(); private: bool checkRows(char symbol) const; bool checkColumns(char symbol) const; bool checkDiagonals(char symbol) const; }; #endif ================================================ FILE: solutions/cpp/tictactoe/Game.cpp ================================================ #include "Game.hpp" #include #include #include #include Game::Game(int boardSize) : board(boardSize), gameOver(false) { player1 = nullptr; player2 = nullptr; currentPlayer = nullptr; std::srand(static_cast(std::time(nullptr))); } Game::~Game() { delete player1; delete player2; } void Game::initializePlayers(const std::string& p1Name, const std::string& p2Name) { player1 = new Player(p1Name, 'X'); player2 = new Player(p2Name, 'O', false); // Computer player currentPlayer = player1; } void Game::play() { while (!gameOver) { board.display(); if (currentPlayer->isHumanPlayer()) { int row, col; std::cout << currentPlayer->getName() << "'s turn (symbol: " << currentPlayer->getSymbol() << ")" << std::endl; std::cout << "Enter row (0-" << board.getSize()-1 << "): "; std::cin >> row; std::cout << "Enter column (0-" << board.getSize()-1 << "): "; std::cin >> col; makeMove(row, col); } else { std::cout << "Computer's turn..." << std::endl; computerMove(); } } displayResult(); } void Game::makeMove(int row, int col) { if (!board.isValidPosition(row, col)) { std::cout << "Invalid position!" << std::endl; return; } if (!board.isEmpty(row, col)) { std::cout << "Position already taken!" << std::endl; return; } board.makeMove(row, col, currentPlayer->getSymbol()); if (board.checkWin(currentPlayer->getSymbol())) { gameOver = true; return; } if (board.isFull()) { gameOver = true; currentPlayer = nullptr; return; } switchPlayer(); } void Game::switchPlayer() { currentPlayer = (currentPlayer == player1) ? player2 : player1; } void Game::displayResult() const { board.display(); if (currentPlayer) { std::cout << currentPlayer->getName() << " wins!" << std::endl; } else { std::cout << "It's a draw!" << std::endl; } } bool Game::isGameOver() const { return gameOver; } Player* Game::getCurrentPlayer() const { return currentPlayer; } void Game::computerMove() { auto [row, col] = findBestMove(); makeMove(row, col); } std::pair Game::findBestMove() const { int bestScore = std::numeric_limits::min(); std::pair bestMove = {0, 0}; for (int i = 0; i < board.getSize(); i++) { for (int j = 0; j < board.getSize(); j++) { if (board.isEmpty(i, j)) { Board tempBoard = board; // Create a copy tempBoard.makeMove(i, j, player2->getSymbol()); int score = minimax(false, 0); if (score > bestScore) { bestScore = score; bestMove = {i, j}; } } } } return bestMove; } int Game::minimax(bool isMax, int depth) const { if (board.checkWin(player2->getSymbol())) return 10 - depth; if (board.checkWin(player1->getSymbol())) return depth - 10; if (board.isFull()) return 0; int bestScore = isMax ? std::numeric_limits::min() : std::numeric_limits::max(); for (int i = 0; i < board.getSize(); i++) { for (int j = 0; j < board.getSize(); j++) { if (board.isEmpty(i, j)) { Board tempBoard = board; // Create a copy tempBoard.makeMove(i, j, isMax ? player2->getSymbol() : player1->getSymbol()); int score = minimax(!isMax, depth + 1); bestScore = isMax ? std::max(score, bestScore) : std::min(score, bestScore); } } } return bestScore; } ================================================ FILE: solutions/cpp/tictactoe/Game.hpp ================================================ #ifndef GAME_HPP #define GAME_HPP #include "Board.hpp" #include "Player.hpp" class Game { private: Board board; Player* player1; Player* player2; Player* currentPlayer; bool gameOver; public: Game(int boardSize = 3); ~Game(); void initializePlayers(const std::string& p1Name, const std::string& p2Name); void play(); void makeMove(int row, int col); void switchPlayer(); void displayResult() const; bool isGameOver() const; Player* getCurrentPlayer() const; private: void computerMove(); std::pair findBestMove() const; int minimax(bool isMax, int depth) const; }; #endif ================================================ FILE: solutions/cpp/tictactoe/Player.cpp ================================================ #include "Player.hpp" Player::Player(std::string name, char symbol, bool isHuman) : name(name), symbol(symbol), isHuman(isHuman) {} std::string Player::getName() const { return name; } char Player::getSymbol() const { return symbol; } bool Player::isHumanPlayer() const { return isHuman; } ================================================ FILE: solutions/cpp/tictactoe/Player.hpp ================================================ #ifndef PLAYER_HPP #define PLAYER_HPP #include class Player { private: std::string name; char symbol; bool isHuman; public: Player(std::string name, char symbol, bool isHuman = true); std::string getName() const; char getSymbol() const; bool isHumanPlayer() const; }; #endif ================================================ FILE: solutions/cpp/tictactoe/README.md ================================================ # Designing a Tic Tac Toe Game ## Requirements 1. The Tic-Tac-Toe game should be played on a 3x3 grid. 2. Two players take turns marking their symbols (X or O) on the grid. 3. The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins the game. 4. If all the cells on the grid are filled and no player has won, the game ends in a draw. 5. The game should have a user interface to display the grid and allow players to make their moves. 6. The game should handle player turns and validate moves to ensure they are legal. 7. The game should detect and announce the winner or a draw at the end of the game. ## Classes, Interfaces and Enumerations 1. The **Player** class represents a player in the game, with a name and a symbol (X or O). 2. The **Board** class represents the game board, which is a 3x3 grid. It provides methods to make moves, check for a winner, and check if the board is full. 3. The **Game** class manages the game flow and player interactions. It handles player turns, validates moves, and determines the winner or a draw. 4. The **TicTacToe** class is the entry point of the application and creates instances of the players and the game. ================================================ FILE: solutions/cpp/tictactoe/TicTacToeDemo.cpp ================================================ #include "Game.hpp" #include int main() { std::cout << "Welcome to Tic Tac Toe!" << std::endl; Game game; game.initializePlayers("Human", "Computer"); game.play(); return 0; } ================================================ FILE: solutions/cpp/trafficsignalsystem/Intersection.cpp ================================================ #include "Intersection.hpp" #include #include Intersection::Intersection(std::string intersectionId) : intersectionId(intersectionId), isOperational(true) {} Intersection::~Intersection() { for (auto signal : signals) { delete signal; } } std::string Intersection::getIntersectionId() const { return intersectionId; } bool Intersection::isWorking() const { return isOperational; } void Intersection::addSignal(Signal* signal) { signals.push_back(signal); } void Intersection::removeSignal(const std::string& signalId) { auto it = std::find_if(signals.begin(), signals.end(), [signalId](Signal* signal) { return signal->getSignalId() == signalId; }); if (it != signals.end()) { delete *it; signals.erase(it); } } void Intersection::updateSignals(int timeElapsed) { if (!isOperational) return; for (auto signal : signals) { signal->updateSignal(timeElapsed); } } void Intersection::setOperational(bool status) { isOperational = status; for (auto signal : signals) { signal->setWorking(status); } } void Intersection::synchronizeSignals() { for (auto signal : signals) { signal->reset(); } } void Intersection::displayStatus() const { std::cout << "\nIntersection " << intersectionId << " Status:" << std::endl; std::cout << "Operational: " << (isOperational ? "Yes" : "No") << std::endl; std::cout << "Signals:" << std::endl; for (const auto& signal : signals) { signal->displayStatus(); } } Signal* Intersection::findSignal(const std::string& signalId) const { auto it = std::find_if(signals.begin(), signals.end(), [signalId](Signal* signal) { return signal->getSignalId() == signalId; }); return it != signals.end() ? *it : nullptr; } ================================================ FILE: solutions/cpp/trafficsignalsystem/Intersection.hpp ================================================ #ifndef INTERSECTION_HPP #define INTERSECTION_HPP #include #include #include "Signal.hpp" class Intersection { private: std::string intersectionId; std::vector signals; bool isOperational; public: Intersection(std::string intersectionId); ~Intersection(); std::string getIntersectionId() const; bool isWorking() const; void addSignal(Signal* signal); void removeSignal(const std::string& signalId); void updateSignals(int timeElapsed); void setOperational(bool status); void synchronizeSignals(); void displayStatus() const; private: Signal* findSignal(const std::string& signalId) const; }; #endif ================================================ FILE: solutions/cpp/trafficsignalsystem/README.md ================================================ # Designing a Traffic Signal Control System ## Requirements 1. The traffic signal system should control the flow of traffic at an intersection with multiple roads. 2. The system should support different types of signals, such as red, yellow, and green. 3. The duration of each signal should be configurable and adjustable based on traffic conditions. 4. The system should handle the transition between signals smoothly, ensuring safe and efficient traffic flow. 5. The system should be able to detect and handle emergency situations, such as an ambulance or fire truck approaching the intersection. 6. The system should be scalable and extensible to support additional features and functionality. ## Classes, Interfaces and Enumerations 1. The **Signal** enum represents the different states of a traffic light: red, yellow, and green. 2. The **Road** class represents a road in the traffic signal system, with properties such as ID, name, and an associated traffic light. 3. The **TrafficLight** class represents a traffic light, with properties such as ID, current signal, and durations for each signal state. It provides methods to change the signal and notify observers (e.g., roads) about signal changes. 4. The **TrafficController** class serves as the central controller for the traffic signal system. It follows the Singleton pattern to ensure a single instance of the controller. It manages the roads and their associated traffic lights, starts the traffic control process, and handles emergency situations. 5. The **TrafficSignalSystemDemo** class is the main entry point of the application. It demonstrates the usage of the traffic signal system by creating roads, traffic lights, assigning traffic lights to roads, and starting the traffic control process. ================================================ FILE: solutions/cpp/trafficsignalsystem/Signal.cpp ================================================ #include "Signal.hpp" #include Signal::Signal(std::string signalId, int greenDuration, int yellowDuration, int redDuration) : signalId(signalId), currentColor(SignalColor::RED), greenDuration(greenDuration), yellowDuration(yellowDuration), redDuration(redDuration), isWorking(true) { reset(); } std::string Signal::getSignalId() const { return signalId; } SignalColor Signal::getCurrentColor() const { return currentColor; } int Signal::getTimeRemaining() const { return timeRemaining; } bool Signal::isOperational() const { return isWorking; } void Signal::setDurations(int green, int yellow, int red) { greenDuration = green; yellowDuration = yellow; redDuration = red; reset(); } void Signal::updateSignal(int timeElapsed) { if (!isWorking) return; timeRemaining -= timeElapsed; if (timeRemaining <= 0) { switchColor(); } } void Signal::switchColor() { switch (currentColor) { case SignalColor::RED: currentColor = SignalColor::GREEN; timeRemaining = greenDuration; break; case SignalColor::GREEN: currentColor = SignalColor::YELLOW; timeRemaining = yellowDuration; break; case SignalColor::YELLOW: currentColor = SignalColor::RED; timeRemaining = redDuration; break; } } void Signal::setWorking(bool status) { isWorking = status; } void Signal::reset() { currentColor = SignalColor::RED; timeRemaining = redDuration; } void Signal::displayStatus() const { std::cout << "Signal " << signalId << ": "; std::cout << "Color = "; switch (currentColor) { case SignalColor::RED: std::cout << "RED"; break; case SignalColor::YELLOW: std::cout << "YELLOW"; break; case SignalColor::GREEN: std::cout << "GREEN"; break; } std::cout << ", Time Remaining: " << timeRemaining << "s"; std::cout << ", Status: " << (isWorking ? "Working" : "Not Working") << std::endl; } ================================================ FILE: solutions/cpp/trafficsignalsystem/Signal.hpp ================================================ #ifndef SIGNAL_HPP #define SIGNAL_HPP #include enum class SignalColor { RED, YELLOW, GREEN }; class Signal { private: std::string signalId; SignalColor currentColor; int greenDuration; int yellowDuration; int redDuration; int timeRemaining; bool isWorking; public: Signal(std::string signalId, int greenDuration = 30, int yellowDuration = 5, int redDuration = 30); std::string getSignalId() const; SignalColor getCurrentColor() const; int getTimeRemaining() const; bool isOperational() const; void setDurations(int green, int yellow, int red); void updateSignal(int timeElapsed); void switchColor(); void setWorking(bool status); void reset(); void displayStatus() const; }; #endif ================================================ FILE: solutions/cpp/trafficsignalsystem/TrafficSystem.cpp ================================================ #include "TrafficSystem.hpp" #include #include TrafficSystem::TrafficSystem() : intersectionIdCounter(1), signalIdCounter(1) {} TrafficSystem::~TrafficSystem() { for (auto intersection : intersections) { delete intersection; } } Intersection* TrafficSystem::createIntersection() { std::string intersectionId = generateIntersectionId(); Intersection* intersection = new Intersection(intersectionId); intersections.push_back(intersection); return intersection; } void TrafficSystem::removeIntersection(const std::string& intersectionId) { auto it = std::find_if(intersections.begin(), intersections.end(), [intersectionId](Intersection* intersection) { return intersection->getIntersectionId() == intersectionId; }); if (it != intersections.end()) { delete *it; intersections.erase(it); } } Signal* TrafficSystem::addSignal(const std::string& intersectionId, int greenDuration, int yellowDuration, int redDuration) { Intersection* intersection = findIntersection(intersectionId); if (!intersection) return nullptr; std::string signalId = generateSignalId(); Signal* signal = new Signal(signalId, greenDuration, yellowDuration, redDuration); intersection->addSignal(signal); return signal; } void TrafficSystem::removeSignal(const std::string& intersectionId, const std::string& signalId) { if (Intersection* intersection = findIntersection(intersectionId)) { intersection->removeSignal(signalId); } } void TrafficSystem::updateSystem(int timeElapsed) { for (auto intersection : intersections) { intersection->updateSignals(timeElapsed); } } void TrafficSystem::setIntersectionStatus(const std::string& intersectionId, bool operational) { if (Intersection* intersection = findIntersection(intersectionId)) { intersection->setOperational(operational); } } void TrafficSystem::synchronizeIntersection(const std::string& intersectionId) { if (Intersection* intersection = findIntersection(intersectionId)) { intersection->synchronizeSignals(); } } void TrafficSystem::displaySystemStatus() const { std::cout << "\nTraffic System Status:" << std::endl; std::cout << "Number of Intersections: " << intersections.size() << std::endl; for (const auto& intersection : intersections) { intersection->displayStatus(); } } Intersection* TrafficSystem::findIntersection(const std::string& intersectionId) const { auto it = std::find_if(intersections.begin(), intersections.end(), [intersectionId](Intersection* intersection) { return intersection->getIntersectionId() == intersectionId; }); return it != intersections.end() ? *it : nullptr; } std::string TrafficSystem::generateIntersectionId() { return "I" + std::to_string(intersectionIdCounter++); } std::string TrafficSystem::generateSignalId() { return "S" + std::to_string(signalIdCounter++); } ================================================ FILE: solutions/cpp/trafficsignalsystem/TrafficSystem.hpp ================================================ #ifndef TRAFFIC_SYSTEM_HPP #define TRAFFIC_SYSTEM_HPP #include #include #include "Intersection.hpp" class TrafficSystem { private: std::vector intersections; int intersectionIdCounter; int signalIdCounter; public: TrafficSystem(); ~TrafficSystem(); Intersection* createIntersection(); void removeIntersection(const std::string& intersectionId); Signal* addSignal(const std::string& intersectionId, int greenDuration = 30, int yellowDuration = 5, int redDuration = 30); void removeSignal(const std::string& intersectionId, const std::string& signalId); void updateSystem(int timeElapsed); void setIntersectionStatus(const std::string& intersectionId, bool operational); void synchronizeIntersection(const std::string& intersectionId); void displaySystemStatus() const; private: Intersection* findIntersection(const std::string& intersectionId) const; std::string generateIntersectionId(); std::string generateSignalId(); }; #endif ================================================ FILE: solutions/cpp/trafficsignalsystem/TrafficSystemDemo.cpp ================================================ #include "TrafficSystem.hpp" #include #include #include int main() { TrafficSystem system; // Create an intersection Intersection* intersection1 = system.createIntersection(); // Add signals to the intersection Signal* signal1 = system.addSignal(intersection1->getIntersectionId(), 20, 5, 25); Signal* signal2 = system.addSignal(intersection1->getIntersectionId(), 20, 5, 25); // Display initial status system.displaySystemStatus(); // Simulate traffic system for a few cycles for (int i = 0; i < 10; i++) { std::cout << "\nTime step " << i + 1 << ":" << std::endl; system.updateSystem(5); // Update every 5 seconds system.displaySystemStatus(); std::this_thread::sleep_for(std::chrono::seconds(1)); } // Simulate intersection failure std::cout << "\nSimulating intersection failure..." << std::endl; system.setIntersectionStatus(intersection1->getIntersectionId(), false); system.displaySystemStatus(); // Restore intersection std::cout << "\nRestoring intersection..." << std::endl; system.setIntersectionStatus(intersection1->getIntersectionId(), true); system.synchronizeIntersection(intersection1->getIntersectionId()); system.displaySystemStatus(); return 0; } ================================================ FILE: solutions/cpp/vendingmachine/Product.cpp ================================================ #include "Product.hpp" #include #include Product::Product(std::string productId, std::string name, double price, int quantity) : productId(productId), name(name), price(price), quantity(quantity), available(true) {} std::string Product::getProductId() const { return productId; } std::string Product::getName() const { return name; } double Product::getPrice() const { return price; } int Product::getQuantity() const { return quantity; } bool Product::isAvailable() const { return available && quantity > 0; } void Product::setPrice(double price) { this->price = price; } void Product::setQuantity(int quantity) { this->quantity = quantity; } void Product::setAvailable(bool status) { available = status; } void Product::addQuantity(int amount) { quantity += amount; } bool Product::removeQuantity(int amount) { if (amount <= quantity) { quantity -= amount; return true; } return false; } void Product::displayInfo() const { std::cout << "Product: " << name << " (ID: " << productId << ")" << std::endl; std::cout << "Price: $" << std::fixed << std::setprecision(2) << price << std::endl; std::cout << "Quantity: " << quantity << std::endl; std::cout << "Status: " << (isAvailable() ? "Available" : "Not Available") << std::endl; } ================================================ FILE: solutions/cpp/vendingmachine/Product.hpp ================================================ #ifndef PRODUCT_HPP #define PRODUCT_HPP #include class Product { private: std::string productId; std::string name; double price; int quantity; bool available; public: Product(std::string productId, std::string name, double price, int quantity = 0); std::string getProductId() const; std::string getName() const; double getPrice() const; int getQuantity() const; bool isAvailable() const; void setPrice(double price); void setQuantity(int quantity); void setAvailable(bool status); void addQuantity(int amount); bool removeQuantity(int amount); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/vendingmachine/README.md ================================================ # Designing a Vending Machine ## Requirements 1. The vending machine should support multiple products with different prices and quantities. 1. The machine should accept coins and notes of different denominations. 1. The machine should dispense the selected product and return change if necessary. 1. The machine should keep track of the available products and their quantities. 1. The machine should handle multiple transactions concurrently and ensure data consistency. 1. The machine should provide an interface for restocking products and collecting money. 1. The machine should handle exceptional scenarios, such as insufficient funds or out-of-stock products. ## Classes, Interfaces and Enumerations 1. The **Product** class represents a product in the vending machine, with properties such as name and price. 2. The **Coin** and **Note** enums represent the different denominations of coins and notes accepted by the vending machine. 3. The **Inventory** class manages the available products and their quantities in the vending machine. It uses a concurrent hash map to ensure thread safety. 4. The **VendingMachineState** interface defines the behavior of the vending machine in different states, such as idle, ready, and dispense. 5. The **IdleState**, **ReadyState**, and **DispenseState** classes implement the VendingMachineState interface and define the specific behaviors for each state. 6. The **VendingMachine** class is the main class that represents the vending machine. It follows the Singleton pattern to ensure only one instance of the vending machine exists. 7. The VendingMachine class maintains the current state, selected product, total payment, and provides methods for state transitions and payment handling. 8. The **VendingMachineDemo** class demonstrates the usage of the vending machine by adding products to the inventory, selecting products, inserting coins and notes, dispensing products, and returning change. ================================================ FILE: solutions/cpp/vendingmachine/Transaction.cpp ================================================ #include "Transaction.hpp" #include #include Transaction::Transaction(std::string transactionId, std::string productId, int quantity, double amount) : transactionId(transactionId), productId(productId), quantity(quantity), amount(amount), successful(false) { timestamp = std::time(nullptr); } std::string Transaction::getTransactionId() const { return transactionId; } std::string Transaction::getProductId() const { return productId; } int Transaction::getQuantity() const { return quantity; } double Transaction::getAmount() const { return amount; } std::time_t Transaction::getTimestamp() const { return timestamp; } bool Transaction::isSuccessful() const { return successful; } void Transaction::setSuccessful(bool status) { successful = status; } void Transaction::displayInfo() const { std::cout << "Transaction " << transactionId << ":" << std::endl; std::cout << "Product ID: " << productId << std::endl; std::cout << "Quantity: " << quantity << std::endl; std::cout << "Amount: $" << std::fixed << std::setprecision(2) << amount << std::endl; std::cout << "Status: " << (successful ? "Successful" : "Failed") << std::endl; std::cout << "Time: " << std::ctime(×tamp); } ================================================ FILE: solutions/cpp/vendingmachine/Transaction.hpp ================================================ #ifndef TRANSACTION_HPP #define TRANSACTION_HPP #include #include class Transaction { private: std::string transactionId; std::string productId; int quantity; double amount; std::time_t timestamp; bool successful; public: Transaction(std::string transactionId, std::string productId, int quantity, double amount); std::string getTransactionId() const; std::string getProductId() const; int getQuantity() const; double getAmount() const; std::time_t getTimestamp() const; bool isSuccessful() const; void setSuccessful(bool status); void displayInfo() const; }; #endif ================================================ FILE: solutions/cpp/vendingmachine/VendingMachine.cpp ================================================ #include "VendingMachine.hpp" #include #include #include VendingMachine::VendingMachine(std::string machineId) : machineId(machineId), cashBalance(0.0), operational(true), productIdCounter(1), transactionIdCounter(1) {} VendingMachine::~VendingMachine() { for (auto product : products) delete product; for (auto transaction : transactions) delete transaction; } std::string VendingMachine::getMachineId() const { return machineId; } double VendingMachine::getCashBalance() const { return cashBalance; } bool VendingMachine::isOperational() const { return operational; } Product* VendingMachine::addProduct(const std::string& name, double price, int quantity) { std::string productId = generateProductId(); Product* product = new Product(productId, name, price, quantity); products.push_back(product); return product; } void VendingMachine::removeProduct(const std::string& productId) { auto it = std::find_if(products.begin(), products.end(), [productId](Product* product) { return product->getProductId() == productId; }); if (it != products.end()) { delete *it; products.erase(it); } } bool VendingMachine::restockProduct(const std::string& productId, int quantity) { Product* product = findProduct(productId); if (!product) return false; product->addQuantity(quantity); return true; } bool VendingMachine::updatePrice(const std::string& productId, double price) { Product* product = findProduct(productId); if (!product) return false; product->setPrice(price); return true; } Transaction* VendingMachine::purchaseProduct(const std::string& productId, int quantity, double payment) { if (!operational) return nullptr; Product* product = findProduct(productId); if (!product || !product->isAvailable() || product->getQuantity()getPrice() * quantity; if (payment < totalCost) return nullptr; std::string transactionId = generateTransactionId(); Transaction* transaction = new Transaction(transactionId, productId, quantity, totalCost); if (product->removeQuantity(quantity)) { cashBalance += totalCost; transaction->setSuccessful(true); transactions.push_back(transaction); return transaction; } delete transaction; return nullptr; } void VendingMachine::addCash(double amount) { cashBalance += amount; } bool VendingMachine::withdrawCash(double amount) { if (amount <= cashBalance) { cashBalance -= amount; return true; } return false; } void VendingMachine::setOperational(bool status) { operational = status; } void VendingMachine::displayInventory() const { std::cout << "\nCurrent Inventory:" << std::endl; for (const auto& product : products) { product->displayInfo(); std::cout << "------------------------" << std::endl; } } void VendingMachine::displayTransactions() const { std::cout << "\nTransaction History:" << std::endl; for (const auto& transaction : transactions) { transaction->displayInfo(); std::cout << "------------------------" << std::endl; } } void VendingMachine::displayMachineInfo() const { std::cout << "\nVending Machine Info:" << std::endl; std::cout << "ID: " << machineId << std::endl; std::cout << "Status: " << (operational ? "Operational" : "Out of Service") << std::endl; std::cout << "Cash Balance: $" << std::fixed << std::setprecision(2) << cashBalance << std::endl; std::cout << "Products Available: " << products.size() << std::endl; std::cout << "Total Transactions: " << transactions.size() << std::endl; } Product* VendingMachine::findProduct(const std::string& productId) const { auto it = std::find_if(products.begin(), products.end(), [productId](Product* product) { return product->getProductId() == productId; }); return it != products.end() ? *it : nullptr; } std::string VendingMachine::generateProductId() { return "P" + std::to_string(productIdCounter++); } std::string VendingMachine::generateTransactionId() { return "T" + std::to_string(transactionIdCounter++); } ================================================ FILE: solutions/cpp/vendingmachine/VendingMachine.hpp ================================================ #ifndef VENDING_MACHINE_HPP #define VENDING_MACHINE_HPP #include #include #include "Product.hpp" #include "Transaction.hpp" class VendingMachine { private: std::string machineId; std::vector products; std::vector transactions; double cashBalance; bool operational; int productIdCounter; int transactionIdCounter; public: VendingMachine(std::string machineId); ~VendingMachine(); std::string getMachineId() const; double getCashBalance() const; bool isOperational() const; Product* addProduct(const std::string& name, double price, int quantity = 0); void removeProduct(const std::string& productId); bool restockProduct(const std::string& productId, int quantity); bool updatePrice(const std::string& productId, double price); Transaction* purchaseProduct(const std::string& productId, int quantity, double payment); void addCash(double amount); bool withdrawCash(double amount); void setOperational(bool status); void displayInventory() const; void displayTransactions() const; void displayMachineInfo() const; private: Product* findProduct(const std::string& productId) const; std::string generateProductId(); std::string generateTransactionId(); }; #endif ================================================ FILE: solutions/cpp/vendingmachine/VendingMachineDemo.cpp ================================================ #include "VendingMachine.hpp" #include int main() { VendingMachine machine("VM001"); // Add products Product* cola = machine.addProduct("Cola", 2.50, 10); Product* chips = machine.addProduct("Chips", 1.50, 15); Product* candy = machine.addProduct("Candy", 1.00, 20); // Display initial inventory std::cout << "Initial machine status:" << std::endl; machine.displayMachineInfo(); machine.displayInventory(); // Make some purchases std::cout << "\nMaking purchases..." << std::endl; Transaction* t1 = machine.purchaseProduct(cola->getProductId(), 2, 5.00); Transaction* t2 = machine.purchaseProduct(chips->getProductId(), 3, 5.00); // Display transactions machine.displayTransactions(); // Restock a product std::cout << "\nRestocking Cola..." << std::endl; machine.restockProduct(cola->getProductId(), 5); // Update price std::cout << "\nUpdating Candy price..." << std::endl; machine.updatePrice(candy->getProductId(), 1.25); // Display final status std::cout << "\nFinal machine status:" << std::endl; machine.displayMachineInfo(); machine.displayInventory(); return 0; } ================================================ FILE: solutions/cpp/votingsystem/README.md ================================================ ### Airline Management System This is a simple airline management system that allows you to manage flights, passengers, and bookings. ================================================ FILE: solutions/csharp/LLDRunner.cs ================================================ using AirlineManagementSystem; using ATM; using CarRentalSystem; using ChessGame; using CoffeeVendingMachine; using ConcertBookingSystem; using CourseRegistrationSystem; using Cricinfo; using DigitalWallet; using ElevatorSystem; using FoodDeliveryService; using HotelManagement; using LibraryManagementSystem; using LinkedInNamespace; //using LoggingFramework; using LRUCacheNamespace; using MovieTicketBookingSystem; using MusicStreamingService; using OnlineAuctionSystem; using OnlineShopping; using OnlineStockBrokerageSystem; using ParkingLot; using PubSubSystem; using RestaurantManagementSystem; using RideSharingService; using SnakeAndLadderGame; using SocialNetworkingService; using Splitwise; using StackOverflow; using TaskManagementSystem; using TicTacToe; using TrafficSignalSystem; using VendingMachineApp; namespace MyCSharpProject { class Program { static void Main(string[] args) { // Uncomment the LLD problem you want to run with sample input defined in the corresponding Demo class. //AirlineManagementSystemDemo.Run(); //ATMDemo.Run(); //CarRentalSystemDemo.Run(); //ChessGameDemo.Run(); //CoffeeVendingMachineDemo.Run(); //ConcertTicketBookingSystemDemo.Run(); //CourseRegistrationDemo.Run(); //CricinfoDemo.Run(); //DigitalWalletDemo.Run(); //ElevatorSystemDemo.Run(); //FoodDeliveryServiceDemo.Run(); //HotelManagementSystemDemo.Run(); //LibraryManagementSystemDemo.Run(); //LinkedInDemo.Run(); //LoggingFrameworkDemo.Run(); //LRUCacheDemo.Run(); //MovieTicketBookingDemo.Run(); //MusicStreamingServiceDemo.Run(); //AuctionSystemDemo.Run(); //OnlineShoppingServiceDemo.Run(); //StockBrokerageSystemDemo.Run(); //ParkingLotDemo.Run(); //PubSubSystemDemo.Run(); //RestaurantManagementDemo.Run(); //RideSharingServiceDemo.Run(); //SnakeAndLadderDemo.Run(); //SocialNetworkingServiceDemo.Run(); //SplitwiseDemo.Run(); //StackOverflowDemo.Run(); //TaskManagementSystemDemo.Run(); //TicTacToeDemo.Run(); //TrafficSignalSystemDemo.Run(); //VendingMachineDemo.Run(); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/Aircraft.cs ================================================ namespace AirlineManagementSystem { public class Aircraft { public string TailNumber { get; } public string Model { get; } public int TotalSeats { get; } public Aircraft(string tailNumber, string model, int totalSeats) { TailNumber = tailNumber; Model = model; TotalSeats = totalSeats; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/AirlineManagementSystem.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace AirlineManagementSystem { public class AirlineManagementSystem { private readonly List flights; private readonly List aircrafts; private readonly FlightSearch flightSearch; private readonly BookingManager bookingManager; private readonly PaymentProcessor paymentProcessor; public AirlineManagementSystem() { flights = new List(); aircrafts = new List(); flightSearch = new FlightSearch(flights); bookingManager = BookingManager.Instance; paymentProcessor = PaymentProcessor.Instance; } public void AddFlight(Flight flight) { flights.Add(flight); } public void AddAircraft(Aircraft aircraft) { aircrafts.Add(aircraft); } public List SearchFlights(string source, string destination, DateTime date) { return flightSearch.SearchFlights(source, destination, date); } public Booking BookFlight(Flight flight, Passenger passenger, Seat seat, double price) { return bookingManager.CreateBooking(flight, passenger, seat, price); } public void CancelBooking(string bookingNumber) { bookingManager.CancelBooking(bookingNumber); } public void ProcessPayment(Payment payment) { paymentProcessor.ProcessPayment(payment); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/AirlineManagementSystemDemo.cs ================================================ using System; using System.Collections.Generic; namespace AirlineManagementSystem { public class AirlineManagementSystemDemo { public static void Run() { var airlineManagementSystem = new AirlineManagementSystem(); // Create users var passenger1 = new Passenger("U001", "John Doe", "john@example.com", "1234567890"); // Create flights var departureTime1 = DateTime.Now.AddDays(1); var arrivalTime1 = departureTime1.AddHours(2); var flight1 = new Flight("F001", "New York", "London", departureTime1, arrivalTime1); var departureTime2 = DateTime.Now.AddDays(3); var arrivalTime2 = departureTime2.AddHours(5); var flight2 = new Flight("F002", "Paris", "Tokyo", departureTime2, arrivalTime2); airlineManagementSystem.AddFlight(flight1); airlineManagementSystem.AddFlight(flight2); // Create aircrafts var aircraft1 = new Aircraft("A001", "Boeing 747", 300); var aircraft2 = new Aircraft("A002", "Airbus A380", 500); airlineManagementSystem.AddAircraft(aircraft1); airlineManagementSystem.AddAircraft(aircraft2); // Search flights var searchResults = airlineManagementSystem.SearchFlights("New York", "London", DateTime.Now.AddDays(1)); Console.WriteLine("Search Results:"); foreach (var flight in searchResults) { Console.WriteLine($"Flight: {flight.FlightNumber} - {flight.Source} to {flight.Destination}"); } var seat = new Seat("25A", SeatType.ECONOMY); // Book a flight var booking = airlineManagementSystem.BookFlight(flight1, passenger1, seat, 100); if (booking != null) { Console.WriteLine("Booking successful. Booking ID: " + booking.BookingNumber); } else { Console.WriteLine("Booking failed."); } // Cancel a booking airlineManagementSystem.CancelBooking(booking.BookingNumber); Console.WriteLine("Booking cancelled."); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/Booking.cs ================================================ using System; namespace AirlineManagementSystem { public class Booking { public string BookingNumber { get; } public Flight Flight { get; } public Passenger Passenger { get; } public Seat Seat { get; } public double Price { get; } public BookingStatus Status { get; private set; } public Booking(string bookingNumber, Flight flight, Passenger passenger, Seat seat, double price) { BookingNumber = bookingNumber; Flight = flight; Passenger = passenger; Seat = seat; Price = price; Status = BookingStatus.CONFIRMED; } public void Cancel() { Status = BookingStatus.CANCELLED; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/BookingManager.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Threading; namespace AirlineManagementSystem { public class BookingManager { private static BookingManager instance; private readonly Dictionary bookings = new Dictionary(); private readonly object lockObject = new object(); private static int bookingCounter = 0; private BookingManager() { } public static BookingManager Instance { get { if (instance == null) { instance = new BookingManager(); } return instance; } } public Booking CreateBooking(Flight flight, Passenger passenger, Seat seat, double price) { string bookingNumber = GenerateBookingNumber(); var booking = new Booking(bookingNumber, flight, passenger, seat, price); lock (lockObject) { bookings[bookingNumber] = booking; } return booking; } public void CancelBooking(string bookingNumber) { lock (lockObject) { if (bookings.TryGetValue(bookingNumber, out var booking)) { booking.Cancel(); } } } private string GenerateBookingNumber() { int bookingId = Interlocked.Increment(ref bookingCounter); string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture); return $"BKG{timestamp}{bookingId:D6}"; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/BookingStatus.cs ================================================ namespace AirlineManagementSystem { public enum BookingStatus { CONFIRMED, CANCELLED, PENDING, EXPIRED } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/Flight.cs ================================================ using System; using System.Collections.Generic; namespace AirlineManagementSystem { public class Flight { public string FlightNumber { get; } public string Source { get; } public string Destination { get; } public DateTime DepartureTime { get; } public DateTime ArrivalTime { get; } public List AvailableSeats { get; } public Flight(string flightNumber, string source, string destination, DateTime departureTime, DateTime arrivalTime) { FlightNumber = flightNumber; Source = source; Destination = destination; DepartureTime = departureTime; ArrivalTime = arrivalTime; AvailableSeats = new List(); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/FlightSearch.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace AirlineManagementSystem { public class FlightSearch { private readonly List flights; public FlightSearch(List flights) { this.flights = flights; } public List SearchFlights(string source, string destination, DateTime date) { return flights.Where(flight => flight.Source.Equals(source, StringComparison.OrdinalIgnoreCase) && flight.Destination.Equals(destination, StringComparison.OrdinalIgnoreCase) && flight.DepartureTime.Date == date.Date).ToList(); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/Passenger.cs ================================================ namespace AirlineManagementSystem { public class Passenger { public string Id { get; } public string Name { get; } public string Email { get; } public string Phone { get; } public Passenger(string id, string name, string email, string phone) { Id = id; Name = name; Email = email; Phone = phone; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/Payment.cs ================================================ namespace AirlineManagementSystem { public class Payment { public string PaymentId { get; } public string PaymentMethod { get; } public double Amount { get; } public PaymentStatus Status { get; private set; } public Payment(string paymentId, string paymentMethod, double amount) { PaymentId = paymentId; PaymentMethod = paymentMethod; Amount = amount; Status = PaymentStatus.PENDING; } public void ProcessPayment() { // Process payment logic here Status = PaymentStatus.COMPLETED; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/PaymentProcessor.cs ================================================ namespace AirlineManagementSystem { public class PaymentProcessor { private static PaymentProcessor instance; private PaymentProcessor() { } public static PaymentProcessor Instance { get { if (instance == null) { instance = new PaymentProcessor(); } return instance; } } public void ProcessPayment(Payment payment) { payment.ProcessPayment(); } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/PaymentStatus.cs ================================================ namespace AirlineManagementSystem { public enum PaymentStatus { PENDING, COMPLETED, FAILED, REFUNDED } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/README.md ================================================ # Designing an Airline Management System ## Requirements 1. The airline management system should allow users to search for flights based on source, destination, and date. 2. Users should be able to book flights, select seats, and make payments. 3. The system should manage flight schedules, aircraft assignments, and crew assignments. 4. The system should handle passenger information, including personal details and baggage information. 5. The system should support different types of users, such as passengers, airline staff, and administrators. 6. The system should be able to handle cancellations, refunds, and flight changes. 7. The system should ensure data consistency and handle concurrent access to shared resources. 8. The system should be scalable and extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Flight** class represents a flight in the airline management system, with properties such as flight number, source, destination, departure time, arrival time, and available seats. 2. The **Aircraft** class represents an aircraft, with properties like tail number, model, and total seats. 3. The **Passenger** class represents a passenger, with properties such as ID, name, email, and phone number. 4. The **Booking** class represents a booking made by a passenger for a specific flight and seat, with properties such as booking number, flight, passenger, seat, price, and booking status. 5. The **Seat** class represents a seat on a flight, with properties like seat number, seat type, and seat status. 6. The **Payment** class represents a payment made for a booking, with properties such as payment ID, payment method, amount, and payment status. 7. The **FlightSearch** class provides functionality to search for flights based on source, destination, and date. 8. The **BookingManager** class manages the creation and cancellation of bookings. It follows the Singleton pattern to ensure a single instance of the booking manager. 9. The **PaymentProcessor** class handles the processing of payments. It follows the Singleton pattern to ensure a single instance of the payment processor. 10. The **AirlineManagementSystem** class serves as the main entry point of the system, combining all the components and providing methods for flight management, booking, payment processing, and other operations. ================================================ FILE: solutions/csharp/airlinemanagementsystem/Seat.cs ================================================ namespace AirlineManagementSystem { public class Seat { public string SeatNumber { get; } public SeatType Type { get; } public SeatStatus Status { get; private set; } public Seat(string seatNumber, SeatType type) { SeatNumber = seatNumber; Type = type; Status = SeatStatus.AVAILABLE; } public void Reserve() { Status = SeatStatus.RESERVED; } public void Release() { Status = SeatStatus.AVAILABLE; } } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/SeatStatus.cs ================================================ namespace AirlineManagementSystem { public enum SeatStatus { AVAILABLE, RESERVED, OCCUPIED } } ================================================ FILE: solutions/csharp/airlinemanagementsystem/SeatType.cs ================================================ namespace AirlineManagementSystem { public enum SeatType { ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST_CLASS } } ================================================ FILE: solutions/csharp/atm/ATM.cs ================================================ class ATM { private static ATM instance; private static readonly object lockObject = new object(); private readonly BankService bankService; private readonly CashDispenser cashDispenser; private static long transactionCounter = 0; private IATMState currentState; private Card currentCard; private ATM() { currentState = new IdleState(); bankService = new BankService(); // Setup the dispenser chain IDispenseChain c1 = new NoteDispenser100(10); // 10 x $100 notes IDispenseChain c2 = new NoteDispenser50(20); // 20 x $50 notes IDispenseChain c3 = new NoteDispenser20(30); // 30 x $20 notes c1.SetNextChain(c2); c2.SetNextChain(c3); cashDispenser = new CashDispenser(c1); } public static ATM GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new ATM(); } } } return instance; } public void ChangeState(IATMState newState) { currentState = newState; } public void SetCurrentCard(Card card) { currentCard = card; } public void InsertCard(string cardNumber) { currentState.InsertCard(this, cardNumber); } public void EnterPin(string pin) { currentState.EnterPin(this, pin); } public void SelectOperation(OperationType op, int amount = 0) { currentState.SelectOperation(this, op, amount); } public void CheckBalance() { double balance = bankService.GetBalance(currentCard); Console.WriteLine($"Your current account balance is: ${balance:F2}"); } public void WithdrawCash(int amount) { if (!cashDispenser.CanDispenseCash(amount)) { throw new InvalidOperationException("Insufficient cash available in the ATM."); } bankService.WithdrawMoney(currentCard, amount); try { cashDispenser.DispenseCash(amount); } catch (Exception) { bankService.DepositMoney(currentCard, amount); // Deposit back if dispensing fails throw; } } public void DepositCash(int amount) { bankService.DepositMoney(currentCard, amount); } public Card GetCurrentCard() => currentCard; public BankService GetBankService() => bankService; } ================================================ FILE: solutions/csharp/atm/ATMDemo.cs ================================================ using System; using System.Collections.Generic; using System.Threading; public class ATMDemo { public static void Main(string[] args) { ATM atm = ATM.GetInstance(); // Perform Check Balance operation atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("1234"); atm.SelectOperation(OperationType.CHECK_BALANCE); // $1000 // Perform Withdraw Cash operation atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("1234"); atm.SelectOperation(OperationType.WITHDRAW_CASH, 570); // Perform Deposit Cash operation atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("1234"); atm.SelectOperation(OperationType.DEPOSIT_CASH, 200); // Perform Check Balance operation atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("1234"); atm.SelectOperation(OperationType.CHECK_BALANCE); // $630 // Perform Withdraw Cash more than balance atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("1234"); atm.SelectOperation(OperationType.WITHDRAW_CASH, 700); // Insufficient balance // Insert Incorrect PIN atm.InsertCard("1234-5678-9012-3456"); atm.EnterPin("3425"); } } ================================================ FILE: solutions/csharp/atm/DispenserChain/CashDispenser.cs ================================================ class CashDispenser { private readonly IDispenseChain chain; private readonly object dispenserLock = new object(); public CashDispenser(IDispenseChain chain) { this.chain = chain; } public void DispenseCash(int amount) { lock (dispenserLock) { chain.Dispense(amount); } } public bool CanDispenseCash(int amount) { lock (dispenserLock) { if (amount % 10 != 0) { return false; } return chain.CanDispense(amount); } } } ================================================ FILE: solutions/csharp/atm/DispenserChain/IDispenseChain.cs ================================================ interface IDispenseChain { void SetNextChain(IDispenseChain nextChain); void Dispense(int amount); bool CanDispense(int amount); } ================================================ FILE: solutions/csharp/atm/DispenserChain/NoteDispenser.cs ================================================ abstract class NoteDispenser : IDispenseChain { private IDispenseChain nextChain; private readonly int noteValue; private int numNotes; private readonly object dispenserLock = new object(); public NoteDispenser(int noteValue, int numNotes) { this.noteValue = noteValue; this.numNotes = numNotes; } public void SetNextChain(IDispenseChain nextChain) { this.nextChain = nextChain; } public void Dispense(int amount) { lock (dispenserLock) { if (amount >= noteValue) { int numToDispense = Math.Min(amount / noteValue, numNotes); int remainingAmount = amount - (numToDispense * noteValue); if (numToDispense > 0) { Console.WriteLine($"Dispensing {numToDispense} x ${noteValue} note(s)"); numNotes -= numToDispense; } if (remainingAmount > 0 && nextChain != null) { nextChain.Dispense(remainingAmount); } } else if (nextChain != null) { nextChain.Dispense(amount); } } } public bool CanDispense(int amount) { lock (dispenserLock) { if (amount < 0) return false; if (amount == 0) return true; int numToUse = Math.Min(amount / noteValue, numNotes); int remainingAmount = amount - (numToUse * noteValue); if (remainingAmount == 0) return true; if (nextChain != null) { return nextChain.CanDispense(remainingAmount); } return false; } } } ================================================ FILE: solutions/csharp/atm/DispenserChain/NoteDispenser100.cs ================================================ class NoteDispenser100 : NoteDispenser { public NoteDispenser100(int numNotes) : base(100, numNotes) { } } ================================================ FILE: solutions/csharp/atm/DispenserChain/NoteDispenser20.cs ================================================ class NoteDispenser20 : NoteDispenser { public NoteDispenser20(int numNotes) : base(20, numNotes) { } } ================================================ FILE: solutions/csharp/atm/DispenserChain/NoteDispenser50.cs ================================================ class NoteDispenser50 : NoteDispenser { public NoteDispenser50(int numNotes) : base(50, numNotes) { } } ================================================ FILE: solutions/csharp/atm/Enums/OperationType.cs ================================================ enum OperationType { CHECK_BALANCE, WITHDRAW_CASH, DEPOSIT_CASH } ================================================ FILE: solutions/csharp/atm/Models/Account.cs ================================================ class Account { private readonly string accountNumber; private double balance; private readonly Dictionary cards; private readonly object accountLock = new object(); public Account(string accountNumber, double balance) { this.accountNumber = accountNumber; this.balance = balance; this.cards = new Dictionary(); } public string GetAccountNumber() => accountNumber; public double GetBalance() => balance; public Dictionary GetCards() => cards; public void Deposit(double amount) { lock (accountLock) { balance += amount; } } public bool Withdraw(double amount) { lock (accountLock) { if (balance >= amount) { balance -= amount; return true; } return false; } } } ================================================ FILE: solutions/csharp/atm/Models/Card.cs ================================================ class Card { private readonly string cardNumber; private readonly string pin; public Card(string cardNumber, string pin) { this.cardNumber = cardNumber; this.pin = pin; } public string GetCardNumber() => cardNumber; public string GetPin() => pin; } ================================================ FILE: solutions/csharp/atm/README.md ================================================ # Designing an ATM System ## Requirements 1. The ATM system should support basic operations such as balance inquiry, cash withdrawal, and cash deposit. 2. Users should be able to authenticate themselves using a card and a PIN (Personal Identification Number). 3. The system should interact with a bank's backend system to validate user accounts and perform transactions. 4. The ATM should have a cash dispenser to dispense cash to users. 5. The system should handle concurrent access and ensure data consistency. 6. The ATM should have a user-friendly interface for users to interact with. ## Classes, Interfaces and Enumerations 1. The **Card** class represents an ATM card with a card number and PIN. 2. The **Account** class represents a bank account with an account number and balance. It provides methods to debit and credit the account balance. 3. The **Transaction** class is an abstract base class for different types of transactions, such as withdrawal and deposit. It is extended by WithdrawalTransaction and DepositTransaction classes. 4. The **BankingService** class manages the bank accounts and processes transactions. It uses a thread-safe ConcurrentHashMap to store and retrieve account information. 5. The **CashDispenser** class represents the ATM's cash dispenser and handles the dispensing of cash. It uses synchronization to ensure thread safety when dispensing cash. 6. The **ATM** class serves as the main interface for ATM operations. It interacts with the BankingService and CashDispenser to perform user authentication, balance inquiry, cash withdrawal, and cash deposit. 7. The **ATMDriver** class demonstrates the usage of the ATM system by creating sample accounts and performing ATM operations. ================================================ FILE: solutions/csharp/atm/Service/BankService.cs ================================================ class BankService { private readonly Dictionary accounts = new Dictionary(); private readonly Dictionary cards = new Dictionary(); private readonly Dictionary cardAccountMap = new Dictionary(); public BankService() { // Create sample accounts and cards Account account1 = CreateAccount("1234567890", 1000.0); Card card1 = CreateCard("1234-5678-9012-3456", "1234"); LinkCardToAccount(card1, account1); Account account2 = CreateAccount("9876543210", 500.0); Card card2 = CreateCard("9876-5432-1098-7654", "4321"); LinkCardToAccount(card2, account2); } public Account CreateAccount(string accountNumber, double initialBalance) { Account account = new Account(accountNumber, initialBalance); accounts[accountNumber] = account; return account; } public Card CreateCard(string cardNumber, string pin) { Card card = new Card(cardNumber, pin); cards[cardNumber] = card; return card; } public bool Authenticate(Card card, string pin) { return card.GetPin() == pin; } public Card AuthenticateCard(string cardNumber) { return cards.TryGetValue(cardNumber, out Card card) ? card : null; } public double GetBalance(Card card) { return cardAccountMap[card].GetBalance(); } public void WithdrawMoney(Card card, double amount) { cardAccountMap[card].Withdraw(amount); } public void DepositMoney(Card card, double amount) { cardAccountMap[card].Deposit(amount); } public void LinkCardToAccount(Card card, Account account) { account.GetCards()[card.GetCardNumber()] = card; cardAccountMap[card] = account; } } ================================================ FILE: solutions/csharp/atm/State/AuthenticatedState.cs ================================================ class AuthenticatedState : IATMState { public void InsertCard(ATM atm, string cardNumber) { Console.WriteLine("Error: A card is already inserted and a session is active."); } public void EnterPin(ATM atm, string pin) { Console.WriteLine("Error: PIN has already been entered and authenticated."); } public void SelectOperation(ATM atm, OperationType op, int amount = 0) { switch (op) { case OperationType.CHECK_BALANCE: atm.CheckBalance(); break; case OperationType.WITHDRAW_CASH: if (amount <= 0) { Console.WriteLine("Error: Invalid withdrawal amount specified."); break; } double accountBalance = atm.GetBankService().GetBalance(atm.GetCurrentCard()); if (amount > accountBalance) { Console.WriteLine("Error: Insufficient balance."); break; } Console.WriteLine($"Processing withdrawal for ${amount}"); atm.WithdrawCash(amount); break; case OperationType.DEPOSIT_CASH: if (amount <= 0) { Console.WriteLine("Error: Invalid deposit amount specified."); break; } Console.WriteLine($"Processing deposit for ${amount}"); atm.DepositCash(amount); break; default: Console.WriteLine("Error: Invalid operation selected."); break; } // End the session after one transaction Console.WriteLine("Transaction complete."); EjectCard(atm); } public void EjectCard(ATM atm) { Console.WriteLine("Ending session. Card has been ejected. Thank you for using our ATM."); atm.SetCurrentCard(null); atm.ChangeState(new IdleState()); } } ================================================ FILE: solutions/csharp/atm/State/HasCardState.cs ================================================ class HasCardState : IATMState { public void InsertCard(ATM atm, string cardNumber) { Console.WriteLine("Error: A card is already inserted. Cannot insert another card."); } public void EnterPin(ATM atm, string pin) { Console.WriteLine("Authenticating PIN..."); Card card = atm.GetCurrentCard(); bool isAuthenticated = atm.GetBankService().Authenticate(card, pin); if (isAuthenticated) { Console.WriteLine("Authentication successful."); atm.ChangeState(new AuthenticatedState()); } else { Console.WriteLine("Authentication failed: Incorrect PIN."); EjectCard(atm); } } public void SelectOperation(ATM atm, OperationType op, int amount = 0) { Console.WriteLine("Error: Please enter your PIN first to select an operation."); } public void EjectCard(ATM atm) { Console.WriteLine("Card has been ejected. Thank you for using our ATM."); atm.SetCurrentCard(null); atm.ChangeState(new IdleState()); } } ================================================ FILE: solutions/csharp/atm/State/IATMState.cs ================================================ interface IATMState { void InsertCard(ATM atm, string cardNumber); void EnterPin(ATM atm, string pin); void SelectOperation(ATM atm, OperationType op, int amount = 0); void EjectCard(ATM atm); } ================================================ FILE: solutions/csharp/atm/State/IdleState.cs ================================================ class IdleState : IATMState { public void InsertCard(ATM atm, string cardNumber) { Console.WriteLine("\nCard has been inserted."); Card card = atm.GetBankService().AuthenticateCard(cardNumber); if (card == null) { EjectCard(atm); } else { atm.SetCurrentCard(card); atm.ChangeState(new HasCardState()); } } public void EnterPin(ATM atm, string pin) { Console.WriteLine("Error: Please insert a card first."); } public void SelectOperation(ATM atm, OperationType op, int amount = 0) { Console.WriteLine("Error: Please insert a card first."); } public void EjectCard(ATM atm) { Console.WriteLine("Error: Card not found."); atm.SetCurrentCard(null); } } ================================================ FILE: solutions/csharp/atm/atm.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/bin/Debug/net8.0/c#.deps.json ================================================ { "runtimeTarget": { "name": ".NETCoreApp,Version=v8.0", "signature": "" }, "compilationOptions": {}, "targets": { ".NETCoreApp,Version=v8.0": { "c#/1.0.0": { "runtime": { "c#.dll": {} } } } }, "libraries": { "c#/1.0.0": { "type": "project", "serviceable": false, "sha512": "" } } } ================================================ FILE: solutions/csharp/bin/Debug/net8.0/c#.runtimeconfig.json ================================================ { "runtimeOptions": { "tfm": "net8.0", "framework": { "name": "Microsoft.NETCore.App", "version": "8.0.0" }, "configProperties": { "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false } } } ================================================ FILE: solutions/csharp/c#.csproj ================================================  Exe net8.0 c_ enable enable ================================================ FILE: solutions/csharp/c#.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "c#", "c#.csproj", "{78F1799C-B97B-471D-9B45-7D9E16A511E6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {78F1799C-B97B-471D-9B45-7D9E16A511E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {78F1799C-B97B-471D-9B45-7D9E16A511E6}.Debug|Any CPU.Build.0 = Debug|Any CPU {78F1799C-B97B-471D-9B45-7D9E16A511E6}.Release|Any CPU.ActiveCfg = Release|Any CPU {78F1799C-B97B-471D-9B45-7D9E16A511E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4CD4CD58-F1CA-4727-A9E3-D71FA3EF319D} EndGlobalSection EndGlobal ================================================ FILE: solutions/csharp/carrentalsystem/Car.cs ================================================ namespace CarRentalSystem { public class Car { public string Make { get; } public string Model { get; } public int Year { get; } public string LicensePlate { get; } public double RentalPricePerDay { get; } public bool Available { get; private set; } public Car(string make, string model, int year, string licensePlate, double rentalPricePerDay) { Make = make; Model = model; Year = year; LicensePlate = licensePlate; RentalPricePerDay = rentalPricePerDay; Available = true; } public void SetAvailable(bool available) { Available = available; } } } ================================================ FILE: solutions/csharp/carrentalsystem/CarRentalSystemDemo.cs ================================================ using System; using System.Collections.Generic; namespace CarRentalSystem { public class CarRentalSystemDemo { public static void Run() { var rentalSystem = RentalSystem.Instance; // Add cars to the rental system rentalSystem.AddCar(new Car("Toyota", "Camry", 2022, "ABC123", 50.0)); rentalSystem.AddCar(new Car("Honda", "Civic", 2021, "XYZ789", 45.0)); rentalSystem.AddCar(new Car("Ford", "Mustang", 2023, "DEF456", 80.0)); // Create customers var customer1 = new Customer("John Doe", "john@example.com", "DL1234"); // Make reservations var startDate = DateTime.Now; var endDate = startDate.AddDays(3); List availableCars = rentalSystem.SearchCars("Toyota", "Camry", startDate, endDate); if (availableCars.Count > 0) { Car selectedCar = availableCars[0]; var reservation = rentalSystem.MakeReservation(customer1, selectedCar, startDate, endDate); if (reservation != null) { bool paymentSuccess = rentalSystem.ProcessPayment(reservation); if (paymentSuccess) { Console.WriteLine("Reservation successful. Reservation ID: " + reservation.ReservationId); } else { Console.WriteLine("Payment failed. Reservation canceled."); rentalSystem.CancelReservation(reservation.ReservationId); } } else { Console.WriteLine("Selected car is not available for the given dates."); } } else { Console.WriteLine("No available cars found for the given criteria."); } } } } ================================================ FILE: solutions/csharp/carrentalsystem/CreditCardPaymentProcessor.cs ================================================ namespace CarRentalSystem { public class CreditCardPaymentProcessor : IPaymentProcessor { public bool ProcessPayment(double amount) { // Simulate processing payment // Actual implementation would involve integrating with a payment gateway return true; } } } ================================================ FILE: solutions/csharp/carrentalsystem/Customer.cs ================================================ namespace CarRentalSystem { public class Customer { public string Name { get; } public string ContactInfo { get; } public string DriversLicenseNumber { get; } public Customer(string name, string contactInfo, string driversLicenseNumber) { Name = name; ContactInfo = contactInfo; DriversLicenseNumber = driversLicenseNumber; } } } ================================================ FILE: solutions/csharp/carrentalsystem/IPaymentProcessor.cs ================================================ namespace CarRentalSystem { public interface IPaymentProcessor { bool ProcessPayment(double amount); } } ================================================ FILE: solutions/csharp/carrentalsystem/PayPalPaymentProcessor.cs ================================================ namespace CarRentalSystem { public class PayPalPaymentProcessor : IPaymentProcessor { public bool ProcessPayment(double amount) { // Simulate processing PayPal payment return true; } } } ================================================ FILE: solutions/csharp/carrentalsystem/README.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: solutions/csharp/carrentalsystem/RentalSystem.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace CarRentalSystem { public class RentalSystem { private static RentalSystem instance; private readonly Dictionary cars; private readonly Dictionary reservations; private readonly IPaymentProcessor paymentProcessor; private RentalSystem() { cars = new Dictionary(); reservations = new Dictionary(); paymentProcessor = new CreditCardPaymentProcessor(); // Default to credit card payment processor } public static RentalSystem Instance { get { if (instance == null) { instance = new RentalSystem(); } return instance; } } public void AddCar(Car car) { cars[car.LicensePlate] = car; } public void RemoveCar(string licensePlate) { cars.Remove(licensePlate); } public List SearchCars(string make, string model, DateTime startDate, DateTime endDate) { return cars.Values .Where(car => car.Make.Equals(make, StringComparison.OrdinalIgnoreCase) && car.Model.Equals(model, StringComparison.OrdinalIgnoreCase) && car.Available && IsCarAvailable(car, startDate, endDate)) .ToList(); } private bool IsCarAvailable(Car car, DateTime startDate, DateTime endDate) { return reservations.Values .Where(reservation => reservation.Car == car) .All(reservation => endDate < reservation.StartDate || startDate > reservation.EndDate); } public Reservation MakeReservation(Customer customer, Car car, DateTime startDate, DateTime endDate) { if (IsCarAvailable(car, startDate, endDate)) { var reservationId = GenerateReservationId(); var reservation = new Reservation(reservationId, customer, car, startDate, endDate); reservations[reservationId] = reservation; car.SetAvailable(false); return reservation; } return null; } public void CancelReservation(string reservationId) { if (reservations.TryGetValue(reservationId, out var reservation)) { reservations.Remove(reservationId); reservation.Car.SetAvailable(true); } } public bool ProcessPayment(Reservation reservation) { return paymentProcessor.ProcessPayment(reservation.TotalPrice); } private string GenerateReservationId() { return "RES" + Guid.NewGuid().ToString("N").Substring(0, 8).ToUpper(); } } } ================================================ FILE: solutions/csharp/carrentalsystem/Reservation.cs ================================================ using System; namespace CarRentalSystem { public class Reservation { public string ReservationId { get; } public Customer Customer { get; } public Car Car { get; } public DateTime StartDate { get; } public DateTime EndDate { get; } public double TotalPrice { get; } public Reservation(string reservationId, Customer customer, Car car, DateTime startDate, DateTime endDate) { ReservationId = reservationId; Customer = customer; Car = car; StartDate = startDate; EndDate = endDate; TotalPrice = CalculateTotalPrice(); } private double CalculateTotalPrice() { int daysRented = (EndDate - StartDate).Days + 1; return Car.RentalPricePerDay * daysRented; } } } ================================================ FILE: solutions/csharp/chessgame/Bishop.cs ================================================ namespace ChessGame { public class Bishop : Piece { public Bishop(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { int rowDiff = System.Math.Abs(destRow - Row); int colDiff = System.Math.Abs(destCol - Col); return rowDiff == colDiff; } } } ================================================ FILE: solutions/csharp/chessgame/Board.cs ================================================ using System; namespace ChessGame { public class Board { private readonly Piece[,] board; public Board() { board = new Piece[8, 8]; InitializeBoard(); } private void InitializeBoard() { // Initialize white pieces board[0, 0] = new Rook(Color.White, 0, 0); board[0, 1] = new Knight(Color.White, 0, 1); board[0, 2] = new Bishop(Color.White, 0, 2); board[0, 3] = new Queen(Color.White, 0, 3); board[0, 4] = new King(Color.White, 0, 4); board[0, 5] = new Bishop(Color.White, 0, 5); board[0, 6] = new Knight(Color.White, 0, 6); board[0, 7] = new Rook(Color.White, 0, 7); for (int i = 0; i < 8; i++) { board[1, i] = new Pawn(Color.White, 1, i); } // Initialize black pieces board[7, 0] = new Rook(Color.Black, 7, 0); board[7, 1] = new Knight(Color.Black, 7, 1); board[7, 2] = new Bishop(Color.Black, 7, 2); board[7, 3] = new Queen(Color.Black, 7, 3); board[7, 4] = new King(Color.Black, 7, 4); board[7, 5] = new Bishop(Color.Black, 7, 5); board[7, 6] = new Knight(Color.Black, 7, 6); board[7, 7] = new Rook(Color.Black, 7, 7); for (int i = 0; i < 8; i++) { board[6, i] = new Pawn(Color.Black, 6, i); } } public Piece GetPiece(int row, int col) { return board[row, col]; } public void SetPiece(int row, int col, Piece piece) { board[row, col] = piece; } public bool IsValidMove(Piece piece, int destRow, int destCol) { if (piece == null || destRow < 0 || destRow > 7 || destCol < 0 || destCol > 7) { return false; } Piece destPiece = board[destRow, destCol]; return (destPiece == null || destPiece.Color != piece.Color) && piece.CanMove(this, destRow, destCol); } public bool IsCheckmate(Color color) { // TODO: Implement checkmate logic return false; } public bool IsStalemate(Color color) { // TODO: Implement stalemate logic return false; } } } ================================================ FILE: solutions/csharp/chessgame/ChessGame.cs ================================================ using System; namespace ChessGame { public class ChessGame { private readonly Board board; private readonly Player[] players; private int currentPlayer; public ChessGame() { board = new Board(); players = new Player[] { new Player(Color.White), new Player(Color.Black) }; currentPlayer = 0; } public void Start() { // Game loop while (!IsGameOver()) { Player player = players[currentPlayer]; Console.WriteLine($"{player.Color}'s turn."); // Get move from the player Move move = GetPlayerMove(player); // Make the move on the board try { player.MakeMove(board, move); } catch (InvalidMoveException e) { Console.WriteLine(e.Message); Console.WriteLine("Try again!"); continue; } // Switch to the next player currentPlayer = (currentPlayer + 1) % 2; } // Display game result DisplayResult(); } private bool IsGameOver() { return board.IsCheckmate(players[0].Color) || board.IsCheckmate(players[1].Color) || board.IsStalemate(players[0].Color) || board.IsStalemate(players[1].Color); } private Move GetPlayerMove(Player player) { // TODO: Implement logic to get a valid move from the player Console.Write("Enter source row: "); int sourceRow = int.Parse(Console.ReadLine()); Console.Write("Enter source column: "); int sourceCol = int.Parse(Console.ReadLine()); Console.Write("Enter destination row: "); int destRow = int.Parse(Console.ReadLine()); Console.Write("Enter destination column: "); int destCol = int.Parse(Console.ReadLine()); Piece piece = board.GetPiece(sourceRow, sourceCol); if (piece == null || piece.Color != player.Color) { throw new ArgumentException("Invalid piece selection!"); } return new Move(piece, destRow, destCol); } private void DisplayResult() { if (board.IsCheckmate(Color.White)) { Console.WriteLine("Black wins by checkmate!"); } else if (board.IsCheckmate(Color.Black)) { Console.WriteLine("White wins by checkmate!"); } else if (board.IsStalemate(Color.White) || board.IsStalemate(Color.Black)) { Console.WriteLine("The game ends in a stalemate!"); } } } } ================================================ FILE: solutions/csharp/chessgame/ChessGameDemo.cs ================================================ namespace ChessGame { public class ChessGameDemo { public static void Run() { ChessGame chessGame = new ChessGame(); chessGame.Start(); } } } ================================================ FILE: solutions/csharp/chessgame/Color.cs ================================================ namespace ChessGame { public enum Color { White, Black } } ================================================ FILE: solutions/csharp/chessgame/InvalidMoveException.cs ================================================ using System; namespace ChessGame { public class InvalidMoveException : Exception { public InvalidMoveException(string message) : base(message) { } } } ================================================ FILE: solutions/csharp/chessgame/King.cs ================================================ namespace ChessGame { public class King : Piece { public King(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { int rowDiff = System.Math.Abs(destRow - Row); int colDiff = System.Math.Abs(destCol - Col); return rowDiff <= 1 && colDiff <= 1; } } } ================================================ FILE: solutions/csharp/chessgame/Knight.cs ================================================ namespace ChessGame { public class Knight : Piece { public Knight(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { int rowDiff = System.Math.Abs(destRow - Row); int colDiff = System.Math.Abs(destCol - Col); return (rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2); } } } ================================================ FILE: solutions/csharp/chessgame/Move.cs ================================================ namespace ChessGame { public class Move { public Piece Piece { get; } public int DestRow { get; } public int DestCol { get; } public Move(Piece piece, int destRow, int destCol) { Piece = piece; DestRow = destRow; DestCol = destCol; } } } ================================================ FILE: solutions/csharp/chessgame/Pawn.cs ================================================ namespace ChessGame { public class Pawn : Piece { public Pawn(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { int rowDiff = destRow - Row; int colDiff = System.Math.Abs(destCol - Col); if (Color == Color.White) { return (rowDiff == 1 && colDiff == 0) || (Row == 1 && rowDiff == 2 && colDiff == 0) || (rowDiff == 1 && colDiff == 1 && board.GetPiece(destRow, destCol) != null); } else { return (rowDiff == -1 && colDiff == 0) || (Row == 6 && rowDiff == -2 && colDiff == 0) || (rowDiff == -1 && colDiff == 1 && board.GetPiece(destRow, destCol) != null); } } } } ================================================ FILE: solutions/csharp/chessgame/Piece.cs ================================================ namespace ChessGame { public abstract class Piece { public Color Color { get; } public int Row { get; set; } public int Col { get; set; } public Piece(Color color, int row, int col) { Color = color; Row = row; Col = col; } public abstract bool CanMove(Board board, int destRow, int destCol); } } ================================================ FILE: solutions/csharp/chessgame/Player.cs ================================================ namespace ChessGame { public class Player { public Color Color { get; } public Player(Color color) { Color = color; } public void MakeMove(Board board, Move move) { Piece piece = move.Piece; int destRow = move.DestRow; int destCol = move.DestCol; if (board.IsValidMove(piece, destRow, destCol)) { int sourceRow = piece.Row; int sourceCol = piece.Col; board.SetPiece(sourceRow, sourceCol, null); board.SetPiece(destRow, destCol, piece); piece.Row = destRow; piece.Col = destCol; } else { throw new InvalidMoveException("Invalid move!"); } } } } ================================================ FILE: solutions/csharp/chessgame/Queen.cs ================================================ namespace ChessGame { public class Queen : Piece { public Queen(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { int rowDiff = System.Math.Abs(destRow - Row); int colDiff = System.Math.Abs(destCol - Col); return rowDiff == colDiff || Row == destRow || Col == destCol; } } } ================================================ FILE: solutions/csharp/chessgame/README.md ================================================ # Designing a Chess Game ## Requirements 1. The chess game should follow the standard rules of chess. 2. The game should support two players, each controlling their own set of pieces. 3. The game board should be represented as an 8x8 grid, with alternating black and white squares. 4. Each player should have 16 pieces: 1 king, 1 queen, 2 rooks, 2 bishops, 2 knights, and 8 pawns. 5. The game should validate legal moves for each piece and prevent illegal moves. 6. The game should detect checkmate and stalemate conditions. 7. The game should handle player turns and allow players to make moves alternately. 8. The game should provide a user interface for players to interact with the game. ## Classes, Interfaces and Enumerations 1. The **Piece** class is an abstract base class representing a chess piece. It contains common attributes such as color, row, and column, and declares an abstract method canMove to be implemented by each specific piece class. 2. The **King**, **Queen**, **Rook**, **Bishop**, **Knight**, and **Pawn** classes extend the Piece class and implement their respective movement logic in the canMove method. 3. The **Board** class represents the chess board and manages the placement of pieces. It provides methods to get and set pieces on the board, check the validity of moves, and determine checkmate and stalemate conditions. 4. The **Player** class represents a player in the game and has a method to make a move on the board. 5. The Move class represents a move made by a player, containing the piece being moved and the destination coordinates. 6. The **Game** class orchestrates the overall game flow. It initializes the board, handles player turns, and determines the game result. 7. The **ChessGame** class is the entry point of the application and starts the game. ================================================ FILE: solutions/csharp/chessgame/Rook.cs ================================================ namespace ChessGame { public class Rook : Piece { public Rook(Color color, int row, int col) : base(color, row, col) { } public override bool CanMove(Board board, int destRow, int destCol) { return Row == destRow || Col == destCol; } } } ================================================ FILE: solutions/csharp/coffeevendingmachine/CoffeeVendingMachine.cs ================================================ class CoffeeVendingMachine { private static CoffeeVendingMachine instance; private static readonly object lockObject = new object(); private IVendingMachineState state; private Coffee selectedCoffee; private int moneyInserted; private CoffeeVendingMachine() { state = new ReadyState(); moneyInserted = 0; } public static CoffeeVendingMachine GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new CoffeeVendingMachine(); } } } return instance; } public void SelectCoffee(CoffeeType type, List toppings) { // 1. Create the base coffee using the factory Coffee coffee = CoffeeFactory.CreateCoffee(type); // 2. Wrap it with decorators foreach (ToppingType topping in toppings) { switch (topping) { case ToppingType.EXTRA_SUGAR: coffee = new ExtraSugarDecorator(coffee); break; case ToppingType.CARAMEL_SYRUP: coffee = new CaramelSyrupDecorator(coffee); break; } } // Let the state handle the rest state.SelectCoffee(this, coffee); } public void InsertMoney(int amount) { state.InsertMoney(this, amount); } public void DispenseCoffee() { state.DispenseCoffee(this); } public void Cancel() { state.Cancel(this); } // Getters and Setters used by State objects public void SetState(IVendingMachineState state) { this.state = state; } public IVendingMachineState GetState() { return state; } public void SetSelectedCoffee(Coffee selectedCoffee) { this.selectedCoffee = selectedCoffee; } public Coffee GetSelectedCoffee() { return selectedCoffee; } public void SetMoneyInserted(int moneyInserted) { this.moneyInserted = moneyInserted; } public int GetMoneyInserted() { return moneyInserted; } public void Reset() { selectedCoffee = null; moneyInserted = 0; } } ================================================ FILE: solutions/csharp/coffeevendingmachine/CoffeeVendingMachineDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class CoffeeVendingMachineDemo { public static void Main(string[] args) { CoffeeVendingMachine machine = CoffeeVendingMachine.GetInstance(); Inventory inventory = Inventory.GetInstance(); // Initial setup: Refill inventory Console.WriteLine("=== Initializing Vending Machine ==="); inventory.AddStock(Ingredient.COFFEE_BEANS, 50); inventory.AddStock(Ingredient.WATER, 500); inventory.AddStock(Ingredient.MILK, 200); inventory.AddStock(Ingredient.SUGAR, 100); inventory.AddStock(Ingredient.CARAMEL_SYRUP, 50); inventory.PrintInventory(); // Scenario 1: Successful Purchase of a Latte Console.WriteLine("\n--- SCENARIO 1: Buy a Latte (Success) ---"); machine.SelectCoffee(CoffeeType.LATTE, new List()); machine.InsertMoney(200); machine.InsertMoney(50); // Total 250, price is 220 machine.DispenseCoffee(); inventory.PrintInventory(); // Scenario 2: Purchase with Insufficient Funds & Cancellation Console.WriteLine("\n--- SCENARIO 2: Buy Espresso (Insufficient Funds & Cancel) ---"); machine.SelectCoffee(CoffeeType.ESPRESSO, new List()); machine.InsertMoney(100); // Price is 150 machine.DispenseCoffee(); // Should fail machine.Cancel(); // Should refund 100 inventory.PrintInventory(); // Should be unchanged // Scenario 3: Attempt to Buy with Insufficient Ingredients Console.WriteLine("\n--- SCENARIO 3: Buy Cappuccino (Out of Milk) ---"); inventory.PrintInventory(); machine.SelectCoffee(CoffeeType.CAPPUCCINO, new List { ToppingType.CARAMEL_SYRUP, ToppingType.EXTRA_SUGAR }); machine.InsertMoney(300); machine.DispenseCoffee(); // Should fail and refund inventory.PrintInventory(); // Refill and final test Console.WriteLine("\n--- REFILLING AND FINAL TEST ---"); inventory.AddStock(Ingredient.MILK, 200); inventory.PrintInventory(); machine.SelectCoffee(CoffeeType.LATTE, new List { ToppingType.CARAMEL_SYRUP }); machine.InsertMoney(250); machine.DispenseCoffee(); inventory.PrintInventory(); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/Decorator/CaramelSyrupDecorator.cs ================================================ class CaramelSyrupDecorator : CoffeeDecorator { private const int COST = 30; private static readonly Dictionary RECIPE_ADDITION = new Dictionary { { Ingredient.CARAMEL_SYRUP, 10 } }; public CaramelSyrupDecorator(Coffee coffee) : base(coffee) { } public override string GetCoffeeType() { return decoratedCoffee.GetCoffeeType() + ", Caramel Syrup"; } public override int GetPrice() { return decoratedCoffee.GetPrice() + COST; } public override Dictionary GetRecipe() { var newRecipe = new Dictionary(decoratedCoffee.GetRecipe()); foreach (var pair in RECIPE_ADDITION) { if (newRecipe.ContainsKey(pair.Key)) newRecipe[pair.Key] += pair.Value; else newRecipe[pair.Key] = pair.Value; } return newRecipe; } public override void Prepare() { base.Prepare(); Console.WriteLine("- Drizzling Caramel Syrup on top."); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/Decorator/CoffeeDecorator.cs ================================================ abstract class CoffeeDecorator : Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { decoratedCoffee = coffee; } public override int GetPrice() { return decoratedCoffee.GetPrice(); } public override Dictionary GetRecipe() { return decoratedCoffee.GetRecipe(); } public override void AddCondiments() { decoratedCoffee.AddCondiments(); } public override void Prepare() { decoratedCoffee.Prepare(); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/Decorator/ExtraSugarDecorator.cs ================================================ class ExtraSugarDecorator : CoffeeDecorator { private const int COST = 10; private static readonly Dictionary RECIPE_ADDITION = new Dictionary { { Ingredient.SUGAR, 1 } }; public ExtraSugarDecorator(Coffee coffee) : base(coffee) { } public override string GetCoffeeType() { return decoratedCoffee.GetCoffeeType() + ", Extra Sugar"; } public override int GetPrice() { return decoratedCoffee.GetPrice() + COST; } public override Dictionary GetRecipe() { var newRecipe = new Dictionary(decoratedCoffee.GetRecipe()); foreach (var pair in RECIPE_ADDITION) { if (newRecipe.ContainsKey(pair.Key)) newRecipe[pair.Key] += pair.Value; else newRecipe[pair.Key] = pair.Value; } return newRecipe; } public override void Prepare() { base.Prepare(); Console.WriteLine("- Stirring in Extra Sugar."); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/Enums/CoffeeType.cs ================================================ enum CoffeeType { ESPRESSO, LATTE, CAPPUCCINO } ================================================ FILE: solutions/csharp/coffeevendingmachine/Enums/Ingredient.cs ================================================ enum Ingredient { COFFEE_BEANS, MILK, SUGAR, WATER, CARAMEL_SYRUP } ================================================ FILE: solutions/csharp/coffeevendingmachine/Enums/ToppingType.cs ================================================ enum ToppingType { EXTRA_SUGAR, CARAMEL_SYRUP } ================================================ FILE: solutions/csharp/coffeevendingmachine/Factory/CoffeeFactory.cs ================================================ class CoffeeFactory { public static Coffee CreateCoffee(CoffeeType type) { switch (type) { case CoffeeType.ESPRESSO: return new Espresso(); case CoffeeType.LATTE: return new Latte(); case CoffeeType.CAPPUCCINO: return new Cappuccino(); default: throw new ArgumentException($"Unsupported coffee type: {type}"); } } } ================================================ FILE: solutions/csharp/coffeevendingmachine/Inventory.cs ================================================ class Inventory { private static Inventory instance; private static readonly object lockObject = new object(); private readonly Dictionary stock = new Dictionary(); private readonly object inventoryLock = new object(); private Inventory() { } public static Inventory GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new Inventory(); } } } return instance; } public void AddStock(Ingredient ingredient, int quantity) { if (stock.ContainsKey(ingredient)) stock[ingredient] += quantity; else stock[ingredient] = quantity; } public bool HasIngredients(Dictionary recipe) { return recipe.All(pair => stock.GetValueOrDefault(pair.Key, 0) >= pair.Value); } public void DeductIngredients(Dictionary recipe) { lock (inventoryLock) { if (!HasIngredients(recipe)) { Console.WriteLine("Not enough ingredients to make coffee."); return; } foreach (var pair in recipe) { stock[pair.Key] -= pair.Value; } } } public void PrintInventory() { Console.WriteLine("--- Current Inventory ---"); foreach (var pair in stock) { Console.WriteLine($"{pair.Key}: {pair.Value}"); } Console.WriteLine("-------------------------"); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/README.md ================================================ # Designing a Coffee Vending Machine ## Requirements 1. The coffee vending machine should support different types of coffee, such as espresso, cappuccino, and latte. 2. Each type of coffee should have a specific price and recipe (ingredients and their quantities). 3. The machine should have a menu to display the available coffee options and their prices. 4. Users should be able to select a coffee type and make a payment. 5. The machine should dispense the selected coffee and provide change if necessary. 6. The machine should track the inventory of ingredients and notify when they are running low. 7. The machine should handle multiple user requests concurrently and ensure thread safety. ## Classes, Interfaces and Enumerations 1. The **Coffee** class represents a coffee type with its name, price, and recipe (ingredients and their quantities). 2. The **Ingredient** class represents an ingredient used in making coffee, with its name and quantity. It provides a synchronized method to update the quantity. 3. The **Payment** class represents a payment made by a user, with the amount paid. 4. The **CoffeeMachine** class is the main class that manages the coffee vending machine. It follows the Singleton pattern to ensure a single instance of the machine. 5. The **CoffeeMachine** class initializes the coffee menu and ingredients in its constructor. It provides methods to display the menu, select a coffee, dispense coffee, and update ingredient quantities. 6. The hasEnoughIngredients method checks if there are sufficient ingredients to make a selected coffee, while the updateIngredients method updates the ingredient quantities after dispensing a coffee. 7. The **CoffeeVendingMachine** class is the entry point of the application and demonstrates the usage of the coffee vending machine. It creates an instance of the machine, displays the menu, and simulates concurrent user requests using an ExecutorService. ================================================ FILE: solutions/csharp/coffeevendingmachine/States/IVendingMachineState.cs ================================================ interface IVendingMachineState { void SelectCoffee(CoffeeVendingMachine machine, Coffee coffee); void InsertMoney(CoffeeVendingMachine machine, int amount); void DispenseCoffee(CoffeeVendingMachine machine); void Cancel(CoffeeVendingMachine machine); } ================================================ FILE: solutions/csharp/coffeevendingmachine/States/OutOfIngredientState.cs ================================================ class OutOfIngredientState : IVendingMachineState { public void SelectCoffee(CoffeeVendingMachine machine, Coffee coffee) { Console.WriteLine("Sorry, we are sold out."); } public void InsertMoney(CoffeeVendingMachine machine, int amount) { Console.WriteLine("Sorry, we are sold out. Money refunded."); } public void DispenseCoffee(CoffeeVendingMachine machine) { Console.WriteLine("Sorry, we are sold out."); } public void Cancel(CoffeeVendingMachine machine) { Console.WriteLine($"Refunding {machine.GetMoneyInserted()}"); machine.Reset(); machine.SetState(new ReadyState()); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/States/PaidState.cs ================================================ class PaidState : IVendingMachineState { public void SelectCoffee(CoffeeVendingMachine machine, Coffee coffee) { Console.WriteLine("Already paid. Please dispense or cancel."); } public void InsertMoney(CoffeeVendingMachine machine, int amount) { machine.SetMoneyInserted(machine.GetMoneyInserted() + amount); Console.WriteLine($"Additional {amount} inserted. Total: {machine.GetMoneyInserted()}"); } public void DispenseCoffee(CoffeeVendingMachine machine) { Inventory inventory = Inventory.GetInstance(); Coffee coffee = machine.GetSelectedCoffee(); if (!inventory.HasIngredients(coffee.GetRecipe())) { Console.WriteLine("Sorry, we are out of ingredients. Refunding your money."); Console.WriteLine($"Refunding {machine.GetMoneyInserted()}"); machine.Reset(); machine.SetState(new OutOfIngredientState()); return; } // Deduct ingredients and prepare coffee inventory.DeductIngredients(coffee.GetRecipe()); coffee.Prepare(); // Calculate change int change = machine.GetMoneyInserted() - coffee.GetPrice(); if (change > 0) { Console.WriteLine($"Here's your change: {change}"); } machine.Reset(); machine.SetState(new ReadyState()); } public void Cancel(CoffeeVendingMachine machine) { Console.WriteLine($"Transaction cancelled. Refunding {machine.GetMoneyInserted()}"); machine.Reset(); machine.SetState(new ReadyState()); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/States/ReadyState.cs ================================================ class ReadyState : IVendingMachineState { public void SelectCoffee(CoffeeVendingMachine machine, Coffee coffee) { machine.SetSelectedCoffee(coffee); machine.SetState(new SelectingState()); Console.WriteLine($"{coffee.GetCoffeeType()} selected. Price: {coffee.GetPrice()}"); } public void InsertMoney(CoffeeVendingMachine machine, int amount) { Console.WriteLine("Please select a coffee first."); } public void DispenseCoffee(CoffeeVendingMachine machine) { Console.WriteLine("Please select and pay first."); } public void Cancel(CoffeeVendingMachine machine) { Console.WriteLine("Nothing to cancel."); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/States/SelectingState.cs ================================================ class SelectingState : IVendingMachineState { public void SelectCoffee(CoffeeVendingMachine machine, Coffee coffee) { Console.WriteLine("Already selected. Please pay or cancel."); } public void InsertMoney(CoffeeVendingMachine machine, int amount) { machine.SetMoneyInserted(machine.GetMoneyInserted() + amount); Console.WriteLine($"Inserted {amount}. Total: {machine.GetMoneyInserted()}"); if (machine.GetMoneyInserted() >= machine.GetSelectedCoffee().GetPrice()) { machine.SetState(new PaidState()); } } public void DispenseCoffee(CoffeeVendingMachine machine) { Console.WriteLine("Please insert enough money first."); } public void Cancel(CoffeeVendingMachine machine) { Console.WriteLine($"Transaction cancelled. Refunding {machine.GetMoneyInserted()}"); machine.Reset(); machine.SetState(new ReadyState()); } } ================================================ FILE: solutions/csharp/coffeevendingmachine/TemplateMethod/Cappuccino.cs ================================================ class Cappuccino : Coffee { public Cappuccino() { coffeeType = "Cappuccino"; } public override void AddCondiments() { Console.WriteLine("- Adding steamed milk and foam."); } public override int GetPrice() { return 250; } public override Dictionary GetRecipe() { return new Dictionary { { Ingredient.COFFEE_BEANS, 7 }, { Ingredient.WATER, 30 }, { Ingredient.MILK, 100 } }; } } ================================================ FILE: solutions/csharp/coffeevendingmachine/TemplateMethod/Coffee.cs ================================================ abstract class Coffee { protected string coffeeType = "Unknown Coffee"; public virtual string GetCoffeeType() { return coffeeType; } // The Template Method public virtual void Prepare() { Console.WriteLine($"\nPreparing your {GetCoffeeType()}..."); GrindBeans(); Brew(); AddCondiments(); // The "hook" for base coffee types PourIntoCup(); Console.WriteLine($"{GetCoffeeType()} is ready!"); } // Common steps private void GrindBeans() { Console.WriteLine("- Grinding fresh coffee beans."); } private void Brew() { Console.WriteLine("- Brewing coffee with hot water."); } private void PourIntoCup() { Console.WriteLine("- Pouring into a cup."); } // Abstract step to be implemented by subclasses public abstract void AddCondiments(); public abstract int GetPrice(); public abstract Dictionary GetRecipe(); } ================================================ FILE: solutions/csharp/coffeevendingmachine/TemplateMethod/Espresso.cs ================================================ class Espresso : Coffee { public Espresso() { coffeeType = "Espresso"; } public override void AddCondiments() { // No extra condiments for espresso } public override int GetPrice() { return 150; } public override Dictionary GetRecipe() { return new Dictionary { { Ingredient.COFFEE_BEANS, 7 }, { Ingredient.WATER, 30 } }; } } ================================================ FILE: solutions/csharp/coffeevendingmachine/TemplateMethod/Latte.cs ================================================ class Latte : Coffee { public Latte() { coffeeType = "Latte"; } public override void AddCondiments() { Console.WriteLine("- Adding steamed milk."); } public override int GetPrice() { return 220; } public override Dictionary GetRecipe() { return new Dictionary { { Ingredient.COFFEE_BEANS, 7 }, { Ingredient.WATER, 30 }, { Ingredient.MILK, 150 } }; } } ================================================ FILE: solutions/csharp/coffeevendingmachine/coffeevendingmachine.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/concertticketbookingsystem/Booking.cs ================================================ using System; using System.Collections.Generic; namespace ConcertBookingSystem { public class Booking { public string Id { get; } public User User { get; } public Concert Concert { get; } public List Seats { get; } public double TotalPrice { get; } public BookingStatus Status { get; private set; } public Booking(string id, User user, Concert concert, List seats) { Id = id; User = user; Concert = concert; Seats = seats; TotalPrice = CalculateTotalPrice(); Status = BookingStatus.PENDING; } private double CalculateTotalPrice() { return Seats.Sum(seat => seat.Price); } public void ConfirmBooking() { if (Status == BookingStatus.PENDING) { Status = BookingStatus.CONFIRMED; // Send booking confirmation } } public void CancelBooking() { if (Status == BookingStatus.CONFIRMED) { Status = BookingStatus.CANCELLED; Seats.ForEach(seat => seat.Release()); Console.WriteLine($"Booking {Id} cancelled"); } } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/BookingStatus.cs ================================================ namespace ConcertBookingSystem { public enum BookingStatus { PENDING, CONFIRMED, CANCELLED } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/Concert.cs ================================================ using System; using System.Collections.Generic; namespace ConcertBookingSystem { public class Concert { public string Id { get; } public string Artist { get; } public string Venue { get; } public DateTime DateTime { get; } public List Seats { get; } public Concert(string id, string artist, string venue, DateTime dateTime, List seats) { Id = id; Artist = artist; Venue = venue; DateTime = dateTime; Seats = seats; } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/ConcertTicketBookingSystem.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; namespace ConcertBookingSystem { public class ConcertTicketBookingSystem { private static ConcertTicketBookingSystem _instance; private readonly ConcurrentDictionary concerts; private readonly ConcurrentDictionary bookings; private readonly object lockObject = new object(); private ConcertTicketBookingSystem() { concerts = new ConcurrentDictionary(); bookings = new ConcurrentDictionary(); } public static ConcertTicketBookingSystem Instance { get { if (_instance == null) { _instance = new ConcertTicketBookingSystem(); } return _instance; } } public void AddConcert(Concert concert) { concerts.TryAdd(concert.Id, concert); } public Concert GetConcert(string concertId) { concerts.TryGetValue(concertId, out var concert); return concert; } public List SearchConcerts(string artist, string venue, DateTime dateTime) { return concerts.Values.Where(concert => concert.Artist.Equals(artist, StringComparison.OrdinalIgnoreCase) && concert.Venue.Equals(venue, StringComparison.OrdinalIgnoreCase) && concert.DateTime == dateTime).ToList(); } public Booking BookTickets(User user, Concert concert, List seats) { lock (lockObject) { foreach (var seat in seats) { if (seat.Status != SeatStatus.AVAILABLE) { throw new SeatNotAvailableException($"Seat {seat.SeatNumber} is not available."); } } seats.ForEach(seat => seat.Book()); string bookingId = GenerateBookingId(); var booking = new Booking(bookingId, user, concert, seats); bookings.TryAdd(bookingId, booking); ProcessPayment(booking); booking.ConfirmBooking(); Console.WriteLine($"Booking {booking.Id} - {booking.Seats.Count} seats booked"); return booking; } } public void CancelBooking(string bookingId) { bookings.TryRemove(bookingId, out var booking); booking?.CancelBooking(); } private void ProcessPayment(Booking booking) { // Simulate payment processing logic here } private string GenerateBookingId() { return "BKG" + Guid.NewGuid(); } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/ConcertTicketBookingSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace ConcertBookingSystem { public class ConcertTicketBookingSystemDemo { public static void Run() { // Create concert ticket booking system instance var bookingSystem = ConcertTicketBookingSystem.Instance; // Create concerts var concert1Seats = GenerateSeats(100); var concert1 = new Concert("C001", "Artist 1", "Venue 1", DateTime.Now.AddDays(30), concert1Seats); bookingSystem.AddConcert(concert1); var concert2Seats = GenerateSeats(50); var concert2 = new Concert("C002", "Artist 2", "Venue 2", DateTime.Now.AddDays(60), concert2Seats); bookingSystem.AddConcert(concert2); // Create users var user1 = new User("U001", "John Doe", "john@example.com"); var user2 = new User("U002", "Jane Smith", "jane@example.com"); // Search concerts var searchResults = bookingSystem.SearchConcerts("Artist 1", "Venue 1", DateTime.Now.AddDays(30)); Console.WriteLine("Search Results:"); foreach (var concert in searchResults) { Console.WriteLine($"Concert: {concert.Artist} at {concert.Venue}"); } // Book tickets var selectedSeats1 = SelectSeats(concert1, 3); var booking1 = bookingSystem.BookTickets(user1, concert1, selectedSeats1); var selectedSeats2 = SelectSeats(concert2, 2); var booking2 = bookingSystem.BookTickets(user2, concert2, selectedSeats2); // Cancel booking bookingSystem.CancelBooking(booking1.Id); // Book tickets again var selectedSeats3 = SelectSeats(concert1, 2); var booking3 = bookingSystem.BookTickets(user2, concert1, selectedSeats3); } private static List GenerateSeats(int numberOfSeats) { var seats = new List(); for (int i = 1; i <= numberOfSeats; i++) { string seatNumber = "S" + i; SeatType seatType = (i <= 10) ? SeatType.VIP : (i <= 30) ? SeatType.PREMIUM : SeatType.REGULAR; double price = seatType switch { SeatType.VIP => 100.0, SeatType.PREMIUM => 75.0, _ => 50.0, }; seats.Add(new Seat(seatNumber, seatNumber, seatType, price)); } return seats; } private static List SelectSeats(Concert concert, int numberOfSeats) { var availableSeats = concert.Seats .Where(seat => seat.Status == SeatStatus.AVAILABLE) .Take(numberOfSeats) .ToList(); return availableSeats; } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/README.md ================================================ # Designing a Concert Ticket Booking System ## Requirements 1. The concert ticket booking system should allow users to view available concerts and their seating arrangements. 2. Users should be able to search for concerts based on various criteria such as artist, venue, date, and time. 3. Users should be able to select seats and purchase tickets for a specific concert. 4. The system should handle concurrent booking requests to avoid double-booking of seats. 5. The system should ensure fair booking opportunities for all users. 6. The system should handle payment processing securely. 7. The system should generate booking confirmations and send them to users via email or SMS. 8. The system should provide a waiting list functionality for sold-out concerts. ## Classes, Interfaces and Enumerations 1. The **Concert** class represents a concert event, with properties such as ID, artist, venue, date and time, and a list of seats. 2. The **Seat** class represents a seat in a concert, with properties like ID, seat number, seat type, price, and status. It provides methods to book and release a seat. 3. The **SeatType** enum represents the different types of seats available, such as regular, premium, and VIP. 4. The **SeatStatus** enum represents the status of a seat, which can be available, booked, or reserved. 5. The **Booking** class represents a booking made by a user for a specific concert and seats. It contains properties such as ID, user, concert, seats, total price, and status. It provides methods to confirm and cancel a booking. 6. The **BookingStatus** enum represents the status of a booking, which can be pending, confirmed, or cancelled. 7. The **User** class represents a user of the concert ticket booking system, with properties like ID, name, and email. 8. The **ConcertTicketBookingSystem** class is the central component of the system. It follows the Singleton pattern to ensure a single instance of the system. It manages concerts, bookings, and provides methods to add concerts, search concerts, book tickets, and cancel bookings. 9. The **SeatNotAvailableException** is a custom exception used to handle cases where a seat is not available for booking. ================================================ FILE: solutions/csharp/concertticketbookingsystem/Seat.cs ================================================ namespace ConcertBookingSystem { public class Seat { public string Id { get; } public string SeatNumber { get; } public SeatType SeatType { get; } public double Price { get; } public SeatStatus Status { get; private set; } public Seat(string id, string seatNumber, SeatType seatType, double price) { Id = id; SeatNumber = seatNumber; SeatType = seatType; Price = price; Status = SeatStatus.AVAILABLE; } public void Book() { if (Status == SeatStatus.AVAILABLE) { Status = SeatStatus.BOOKED; } else { throw new SeatNotAvailableException("Seat is already booked or reserved."); } } public void Release() { if (Status == SeatStatus.BOOKED) { Status = SeatStatus.AVAILABLE; } } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/SeatNotAvailableException.cs ================================================ using System; namespace ConcertBookingSystem { public class SeatNotAvailableException : Exception { public SeatNotAvailableException(string message) : base(message) { } } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/SeatStatus.cs ================================================ namespace ConcertBookingSystem { public enum SeatStatus { AVAILABLE, BOOKED, RESERVED } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/SeatType.cs ================================================ namespace ConcertBookingSystem { public enum SeatType { REGULAR, PREMIUM, VIP } } ================================================ FILE: solutions/csharp/concertticketbookingsystem/User.cs ================================================ namespace ConcertBookingSystem { public class User { public string Id { get; } public string Name { get; } public string Email { get; } public User(string id, string name, string email) { Id = id; Name = name; Email = email; } } } ================================================ FILE: solutions/csharp/courseregistrationsystem/Course.cs ================================================ namespace CourseRegistrationSystem { public class Course { private readonly string code; private readonly string name; private readonly string instructor; private readonly int maxCapacity; private int enrolledStudents; public Course(string code, string name, string instructor, int maxCapacity, int enrolledStudents) { this.code = code; this.name = name; this.instructor = instructor; this.maxCapacity = maxCapacity; this.enrolledStudents = enrolledStudents; } public string GetCode() => code; public string GetName() => name; public string GetInstructor() => instructor; public int GetMaxCapacity() => maxCapacity; public int GetEnrolledStudents() => enrolledStudents; public void SetEnrolledStudents(int enrolledStudents) => this.enrolledStudents = enrolledStudents; } } ================================================ FILE: solutions/csharp/courseregistrationsystem/CourseRegistrationDemo.cs ================================================ using System; using System.Collections.Generic; namespace CourseRegistrationSystem { public class CourseRegistrationDemo { public static void Run() { CourseRegistrationSystem registrationSystem = CourseRegistrationSystem.GetInstance(); // Create courses Course course1 = new Course("CS101", "Introduction to Programming", "John Doe", 50, 0); Course course2 = new Course("CS201", "Data Structures and Algorithms", "Jane Smith", 30, 0); registrationSystem.AddCourse(course1); registrationSystem.AddCourse(course2); // Create students Student student1 = new Student(1, "Alice", "alice@example.com", new List()); Student student2 = new Student(2, "Bob", "bob@example.com", new List()); registrationSystem.AddStudent(student1); registrationSystem.AddStudent(student2); // Search for courses List searchResults = registrationSystem.SearchCourses("CS"); Console.WriteLine("Search Results:"); foreach (Course course in searchResults) { Console.WriteLine(course.GetCode() + " - " + course.GetName()); } // Register courses for students bool registered1 = registrationSystem.RegisterCourse(student1, course1); bool registered2 = registrationSystem.RegisterCourse(student2, course1); bool registered3 = registrationSystem.RegisterCourse(student1, course2); Console.WriteLine("Registration Results:"); Console.WriteLine("Student 1 - Course 1: " + registered1); Console.WriteLine("Student 2 - Course 1: " + registered2); Console.WriteLine("Student 1 - Course 2: " + registered3); // Get registered courses for a student List registeredCourses = registrationSystem.GetRegisteredCourses(student1); Console.WriteLine("Registered Courses for Student 1:"); foreach (Course course in registeredCourses) { Console.WriteLine(course.GetCode() + " - " + course.GetName()); } } } } ================================================ FILE: solutions/csharp/courseregistrationsystem/CourseRegistrationSystem.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; namespace CourseRegistrationSystem { public class CourseRegistrationSystem { private static CourseRegistrationSystem instance; private readonly ConcurrentDictionary courses; private readonly ConcurrentDictionary students; private readonly List registrations; private CourseRegistrationSystem() { courses = new ConcurrentDictionary(); students = new ConcurrentDictionary(); registrations = new List(); } public static CourseRegistrationSystem GetInstance() { if (instance == null) { instance = new CourseRegistrationSystem(); } return instance; } public void AddCourse(Course course) => courses[course.GetCode()] = course; public void AddStudent(Student student) => students[student.GetId()] = student; public List SearchCourses(string query) { return courses.Values .Where(course => course.GetCode().Contains(query) || course.GetName().Contains(query)) .ToList(); } public bool RegisterCourse(Student student, Course course) { if (course.GetEnrolledStudents() < course.GetMaxCapacity()) { Registration registration = new Registration(student, course, DateTime.Now); registrations.Add(registration); student.GetRegisteredCourses().Add(course); course.SetEnrolledStudents(course.GetEnrolledStudents() + 1); NotifyObservers(course); return true; } return false; } public List GetRegisteredCourses(Student student) => student.GetRegisteredCourses(); private void NotifyObservers(Course course) { // Notify observers (e.g., UI) about the updated course enrollment } } } ================================================ FILE: solutions/csharp/courseregistrationsystem/README.md ================================================ # Designing a University Course Registration System ## Requirements 1. The course registration system should allow students to register for courses and view their registered courses. 2. Each course should have a course code, name, instructor, and maximum enrollment capacity. 3. Students should be able to search for courses based on course code or name. 4. The system should prevent students from registering for courses that have reached their maximum enrollment capacity. 5. The system should handle concurrent registration requests from multiple students. 6. The system should ensure data consistency and prevent race conditions. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Student** class represents a student in the course registration system, with properties such as ID, name, email, and a list of registered courses. 2. The **Course** class represents a course offered in the system, with properties such as code, name, instructor, maximum capacity, and the number of enrolled students. 3. The **Registration** class represents a registration record, associating a student with a course and capturing the registration timestamp. 4. The **CourseRegistrationSystem** class is the main class that manages the course registration system. It follows the Singleton pattern to ensure only one instance of the system exists. 5. The CourseRegistrationSystem class provides methods for adding courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. 6. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as courses and registrations. 7. The registerCourse method is synchronized to ensure thread safety when multiple students are registering for courses simultaneously. 8. The notifyObservers method is a placeholder for notifying observers (e.g., UI components) about updates to course enrollment. 9. The **CourseRegistrationDemo** class demonstrates the usage of the course registration system by creating courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. ================================================ FILE: solutions/csharp/courseregistrationsystem/Registration.cs ================================================ using System; namespace CourseRegistrationSystem { public class Registration { private readonly Student student; private readonly Course course; private readonly DateTime registrationTime; public Registration(Student student, Course course, DateTime registrationTime) { this.student = student; this.course = course; this.registrationTime = registrationTime; } } } ================================================ FILE: solutions/csharp/courseregistrationsystem/Student.cs ================================================ using System.Collections.Generic; namespace CourseRegistrationSystem { public class Student { private readonly int id; private readonly string name; private readonly string email; private readonly List registeredCourses; public Student(int id, string name, string email, List registeredCourses) { this.id = id; this.name = name; this.email = email; this.registeredCourses = registeredCourses; } public int GetId() => id; public string GetName() => name; public string GetEmail() => email; public List GetRegisteredCourses() => registeredCourses; } } ================================================ FILE: solutions/csharp/cricinfo/CommentaryManager.cs ================================================ class CommentaryManager { private static volatile CommentaryManager instance; private static readonly object lockObject = new object(); private readonly Dictionary> commentaryTemplates; private readonly Random random; private CommentaryManager() { commentaryTemplates = new Dictionary>(); random = new Random(); InitializeTemplates(); } public static CommentaryManager GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new CommentaryManager(); } } } return instance; } private void InitializeTemplates() { commentaryTemplates["RUNS_0"] = new List { "%s defends solidly.", "No run, good fielding by the cover fielder.", "A dot ball to end the over.", "Pushed to mid-on, but no run." }; commentaryTemplates["RUNS_1"] = new List { "Tucked away to the leg side for a single.", "Quick single taken by %s.", "Pushed to long-on for one." }; commentaryTemplates["RUNS_2"] = new List { "Two runs taken!", "Quick double taken by %s.", "Pushed to mid-on for two." }; commentaryTemplates["RUNS_4"] = new List { "FOUR! %s smashes it through the covers!", "Beautiful shot! That's a boundary.", "Finds the gap perfectly. Four runs." }; commentaryTemplates["RUNS_6"] = new List { "SIX! That's out of the park!", "%s sends it sailing over the ropes!", "Massive hit! It's a maximum." }; commentaryTemplates["WICKET_BOWLED"] = new List { "BOWLED HIM! %s misses completely and the stumps are shattered!", "Cleaned up! A perfect yorker from %s." }; commentaryTemplates["WICKET_CAUGHT"] = new List { "CAUGHT! %s skies it and the fielder takes a comfortable catch.", "Out! A brilliant catch in the deep by %s." }; commentaryTemplates["WICKET_LBW"] = new List { "LBW! That one kept low and struck %s right in front.", "%s completely misjudged the line and pays the price." }; commentaryTemplates["WICKET_STUMPED"] = new List { "STUMPED! %s misses it, and the keeper does the rest!", "Gone! Lightning-fast work by the keeper to stump %s." }; commentaryTemplates["EXTRA_WIDE"] = new List { "That's a wide. The umpire signals an extra run.", "Too far down the leg side, that'll be a wide." }; commentaryTemplates["EXTRA_NO_BALL"] = new List { "No ball! %s has overstepped. It's a free hit.", "It's a no-ball for overstepping." }; } public string GenerateCommentary(Ball ball) { string key = GetEventKey(ball); var templates = commentaryTemplates.ContainsKey(key) ? commentaryTemplates[key] : new List { "Just a standard delivery." }; string template = templates[random.Next(templates.Count)]; string batsmanName = ball.GetFacedBy()?.GetName() ?? ""; return template.Replace("%s", batsmanName); } private string GetEventKey(Ball ball) { if (ball.IsWicket()) { return $"WICKET_{ball.GetWicket().GetWicketType()}"; } if (ball.GetExtraType().HasValue) { return $"EXTRA_{ball.GetExtraType().Value}"; } int runs = ball.GetRunsScored(); if (runs >= 0 && runs <= 6) { return $"RUNS_{runs}"; } return "DEFAULT"; } } ================================================ FILE: solutions/csharp/cricinfo/CricinfoDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; public class CricinfoDemo { public static void Main() { var service = CricInfoService.GetInstance(); // Setup Players and Teams var p1 = service.AddPlayer("P1", "Virat", PlayerRole.BATSMAN); var p2 = service.AddPlayer("P2", "Rohit", PlayerRole.BATSMAN); var p3 = service.AddPlayer("P3", "Bumrah", PlayerRole.BOWLER); var p4 = service.AddPlayer("P4", "Jadeja", PlayerRole.ALL_ROUNDER); var p5 = service.AddPlayer("P5", "Warner", PlayerRole.BATSMAN); var p6 = service.AddPlayer("P6", "Smith", PlayerRole.BATSMAN); var p7 = service.AddPlayer("P7", "Starc", PlayerRole.BOWLER); var p8 = service.AddPlayer("P8", "Maxwell", PlayerRole.ALL_ROUNDER); var india = new Team("T1", "India", new List { p1, p2, p3, p4 }); var australia = new Team("T2", "Australia", new List { p5, p6, p7, p8 }); // Create a T20 Match var t20Match = service.CreateMatch(india, australia, new T20FormatStrategy()); string matchId = t20Match.GetId(); // Create and subscribe observers var scorecard = new ScorecardDisplay(); var commentary = new CommentaryDisplay(); var notifier = new UserNotifier(); service.SubscribeToMatch(matchId, scorecard); service.SubscribeToMatch(matchId, commentary); service.SubscribeToMatch(matchId, notifier); // Start the match service.StartMatch(matchId); Console.WriteLine("\n--- SIMULATING FIRST INNINGS ---"); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p7).WithFacedBy(p2).WithRuns(6).Build()); var p2Wicket = new WicketBuilder(WicketType.BOWLED, p2).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p7).WithFacedBy(p2).WithRuns(0).WithWicket(p2Wicket).Build()); var p3Wicket = new WicketBuilder(WicketType.LBW, p3).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p7).WithFacedBy(p3).WithRuns(0).WithWicket(p3Wicket).Build()); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p7).WithFacedBy(p4).WithRuns(4).Build()); var p4Wicket = new WicketBuilder(WicketType.CAUGHT, p4).WithCaughtBy(p6).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p7).WithFacedBy(p4).WithRuns(0).WithWicket(p4Wicket).Build()); Console.WriteLine("\n\n--- INNINGS BREAK ---"); Console.WriteLine("Players are off the field. Preparing for the second innings."); // Start the second innings service.StartNextInnings(matchId); Console.WriteLine("\n--- SIMULATING SECOND INNINGS ---"); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p3).WithFacedBy(p5).WithRuns(4).Build()); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p3).WithFacedBy(p5).WithRuns(1).Build()); var p5Wicket = new WicketBuilder(WicketType.BOWLED, p5).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p3).WithFacedBy(p5).WithRuns(0).WithWicket(p5Wicket).Build()); var p7Wicket = new WicketBuilder(WicketType.LBW, p7).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p3).WithFacedBy(p7).WithRuns(0).WithWicket(p7Wicket).Build()); var p8Wicket = new WicketBuilder(WicketType.STUMPED, p8).Build(); service.ProcessBallUpdate(matchId, new BallBuilder() .WithBowledBy(p3).WithFacedBy(p8).WithRuns(0).WithWicket(p8Wicket).Build()); service.EndMatch(matchId); } } ================================================ FILE: solutions/csharp/cricinfo/CricinfoService.cs ================================================ class CricInfoService { private static volatile CricInfoService instance; private static readonly object lockObject = new object(); private readonly MatchRepository matchRepository; private readonly PlayerRepository playerRepository; private CricInfoService() { matchRepository = new MatchRepository(); playerRepository = new PlayerRepository(); } public static CricInfoService GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new CricInfoService(); } } } return instance; } public Match CreateMatch(Team team1, Team team2, IMatchFormatStrategy format) { string matchId = Guid.NewGuid().ToString(); var match = new Match(matchId, team1, team2, format); matchRepository.Save(match); Console.WriteLine($"Match {format.GetFormatName()} created between {team1.GetName()} and {team2.GetName()}."); return match; } public void StartMatch(string matchId) { var match = matchRepository.FindById(matchId); if (match != null) { match.SetState(new LiveState()); Console.WriteLine($"Match {matchId} is now LIVE."); } } public void ProcessBallUpdate(string matchId, Ball ball) { var match = matchRepository.FindById(matchId); match?.ProcessBall(ball); } public void StartNextInnings(string matchId) { var match = matchRepository.FindById(matchId); match?.StartNextInnings(); } public void SubscribeToMatch(string matchId, IMatchObserver observer) { var match = matchRepository.FindById(matchId); match?.AddObserver(observer); } public void EndMatch(string matchId) { var match = matchRepository.FindById(matchId); if (match != null) { match.SetState(new FinishedState()); Console.WriteLine($"Match {matchId} has FINISHED."); } } public Player AddPlayer(string playerId, string playerName, PlayerRole playerRole) { var player = new Player(playerId, playerName, playerRole); playerRepository.Save(player); return player; } } ================================================ FILE: solutions/csharp/cricinfo/Enums/ExtraType.cs ================================================ enum ExtraType { WIDE, NO_BALL, BYE, LEG_BYE } ================================================ FILE: solutions/csharp/cricinfo/Enums/MatchStatus.cs ================================================ enum MatchStatus { SCHEDULED, LIVE, IN_BREAK, FINISHED, ABANDONED } ================================================ FILE: solutions/csharp/cricinfo/Enums/MatchType.cs ================================================ enum MatchType { T20, ODI, TEST } ================================================ FILE: solutions/csharp/cricinfo/Enums/PlayerRole.cs ================================================ enum PlayerRole { BATSMAN, BOWLER, ALL_ROUNDER, WICKET_KEEPER } ================================================ FILE: solutions/csharp/cricinfo/Enums/WicketType.cs ================================================ enum WicketType { BOWLED, CAUGHT, LBW, RUN_OUT, STUMPED, HIT_WICKET } ================================================ FILE: solutions/csharp/cricinfo/Models/Ball.cs ================================================ class Ball { private readonly int ballNumber; private readonly Player bowledBy; private readonly Player facedBy; private readonly int runsScored; private readonly Wicket wicket; private readonly ExtraType? extraType; private readonly string commentary; public Ball(BallBuilder builder) { ballNumber = builder.BallNumber; bowledBy = builder.BowledBy; facedBy = builder.FacedBy; runsScored = builder.RunsScored; wicket = builder.Wicket; extraType = builder.ExtraType; commentary = builder.Commentary; } public bool IsWicket() => wicket != null; public bool IsBoundary() => runsScored == 4 || runsScored == 6; public int GetBallNumber() => ballNumber; public Player GetBowledBy() => bowledBy; public Player GetFacedBy() => facedBy; public int GetRunsScored() => runsScored; public Wicket GetWicket() => wicket; public ExtraType? GetExtraType() => extraType; public string GetCommentary() => commentary; } class BallBuilder { private int ballNumber; private Player bowledBy; private Player facedBy; private int runsScored; private Wicket wicket; private ExtraType? extraType; private string commentary; public BallBuilder WithBallNumber(int number) { ballNumber = number; return this; } public BallBuilder WithBowledBy(Player bowler) { bowledBy = bowler; return this; } public BallBuilder WithFacedBy(Player batsman) { facedBy = batsman; return this; } public BallBuilder WithRuns(int runs) { runsScored = runs; return this; } public BallBuilder WithWicket(Wicket w) { wicket = w; return this; } public BallBuilder WithExtraType(ExtraType extra) { extraType = extra; return this; } public BallBuilder WithCommentary(string comm) { commentary = comm; return this; } public Ball Build() { var tempBall = new Ball(this); if (string.IsNullOrEmpty(commentary)) { commentary = CommentaryManager.GetInstance().GenerateCommentary(tempBall); } return new Ball(this); } internal int BallNumber => ballNumber; internal Player BowledBy => bowledBy; internal Player FacedBy => facedBy; internal int RunsScored => runsScored; internal Wicket Wicket => wicket; internal ExtraType? ExtraType => extraType; internal string Commentary => commentary; } ================================================ FILE: solutions/csharp/cricinfo/Models/Innings.cs ================================================ class Innings { private readonly Team battingTeam; private readonly Team bowlingTeam; private int score; private int wickets; private readonly List balls; private readonly Dictionary playerStats; public Innings(Team batting, Team bowling) { battingTeam = batting; bowlingTeam = bowling; score = 0; wickets = 0; balls = new List(); playerStats = new Dictionary(); foreach (var player in battingTeam.GetPlayers()) { playerStats[player] = new PlayerStats(); } foreach (var player in bowlingTeam.GetPlayers()) { playerStats[player] = new PlayerStats(); } } public void AddBall(Ball ball) { balls.Add(ball); int runsScored = ball.GetRunsScored(); score += runsScored; if (ball.GetExtraType() == ExtraType.WIDE || ball.GetExtraType() == ExtraType.NO_BALL) { score += 1; } else { ball.GetFacedBy().GetStats().UpdateRuns(runsScored); ball.GetFacedBy().GetStats().IncrementBallsPlayed(); playerStats[ball.GetFacedBy()].UpdateRuns(runsScored); playerStats[ball.GetFacedBy()].IncrementBallsPlayed(); } if (ball.IsWicket()) { wickets++; ball.GetBowledBy().GetStats().IncrementWickets(); playerStats[ball.GetBowledBy()].IncrementWickets(); } } public void PrintPlayerStats() { foreach (var entry in playerStats) { var player = entry.Key; var stats = entry.Value; if (stats.GetBallsPlayed() > 0 || stats.GetWickets() > 0) { Console.WriteLine($"Player: {player.GetName()} - Stats: {stats}"); } } } public double GetOvers() { int validBalls = balls.Count(b => b.GetExtraType() != ExtraType.WIDE && b.GetExtraType() != ExtraType.NO_BALL); int completedOvers = validBalls / 6; int ballsInCurrentOver = validBalls % 6; return completedOvers + (ballsInCurrentOver / 10.0); } public Team GetBattingTeam() => battingTeam; public Team GetBowlingTeam() => bowlingTeam; public int GetScore() => score; public int GetWickets() => wickets; public List GetBalls() => balls; } ================================================ FILE: solutions/csharp/cricinfo/Models/Match.cs ================================================ class Match { private readonly string id; private readonly Team team1; private readonly Team team2; private readonly IMatchFormatStrategy formatStrategy; private readonly List innings; private IMatchState currentState; private MatchStatus currentStatus; private readonly List observers; private Team winner; private string resultMessage; public Match(string matchId, Team t1, Team t2, IMatchFormatStrategy format) { id = matchId; team1 = t1; team2 = t2; formatStrategy = format; innings = new List { new Innings(team1, team2) }; currentState = new ScheduledState(); observers = new List(); resultMessage = ""; } public void ProcessBall(Ball ball) { currentState.ProcessBall(this, ball); } public void StartNextInnings() { currentState.StartNextInnings(this); } public void CreateNewInnings() { if (innings.Count >= formatStrategy.GetTotalInnings()) { Console.WriteLine("Cannot create a new innings, match has already reached its limit."); return; } var nextInnings = new Innings(team2, team1); innings.Add(nextInnings); } public void AddObserver(IMatchObserver observer) { observers.Add(observer); } public void RemoveObserver(IMatchObserver observer) { observers.Remove(observer); } public void NotifyObservers(Ball ball) { foreach (var observer in observers) { observer.Update(this, ball); } } public Innings GetCurrentInnings() { return innings.Last(); } public string GetId() => id; public Team GetTeam1() => team1; public Team GetTeam2() => team2; public IMatchFormatStrategy GetFormatStrategy() => formatStrategy; public List GetInnings() => innings; public MatchStatus GetCurrentStatus() => currentStatus; public Team GetWinner() => winner; public string GetResultMessage() => resultMessage; public void SetState(IMatchState state) { currentState = state; } public void SetCurrentStatus(MatchStatus status) { currentStatus = status; } public void SetWinner(Team w) { winner = w; } public void SetResultMessage(string message) { resultMessage = message; } } ================================================ FILE: solutions/csharp/cricinfo/Models/Player.cs ================================================ class Player { private readonly string id; private readonly string name; private readonly PlayerRole role; private readonly PlayerStats stats; public Player(string playerId, string playerName, PlayerRole playerRole) { id = playerId; name = playerName; role = playerRole; stats = new PlayerStats(); } public string GetId() => id; public string GetName() => name; public PlayerRole GetRole() => role; public PlayerStats GetStats() => stats; } ================================================ FILE: solutions/csharp/cricinfo/Models/PlayerStats.cs ================================================ class PlayerStats { private int runs; private int ballsPlayed; private int wickets; public PlayerStats() { runs = 0; ballsPlayed = 0; wickets = 0; } public void UpdateRuns(int runScored) { runs += runScored; } public void IncrementBallsPlayed() { ballsPlayed++; } public void IncrementWickets() { wickets++; } public int GetRuns() => runs; public int GetBallsPlayed() => ballsPlayed; public int GetWickets() => wickets; public override string ToString() { return $"Runs: {runs}, Balls Played: {ballsPlayed}, Wickets: {wickets}"; } } ================================================ FILE: solutions/csharp/cricinfo/Models/Team.cs ================================================ class Team { private readonly string id; private readonly string name; private readonly List players; public Team(string teamId, string teamName, List teamPlayers) { id = teamId; name = teamName; players = teamPlayers; } public string GetId() => id; public string GetName() => name; public List GetPlayers() => players; } ================================================ FILE: solutions/csharp/cricinfo/Models/Wicket.cs ================================================ class Wicket { private readonly WicketType wicketType; private readonly Player playerOut; private readonly Player caughtBy; private readonly Player runoutBy; public Wicket(WicketBuilder builder) { wicketType = builder.WicketType; playerOut = builder.PlayerOut; caughtBy = builder.CaughtBy; runoutBy = builder.RunoutBy; } public WicketType GetWicketType() => wicketType; public Player GetPlayerOut() => playerOut; public Player GetCaughtBy() => caughtBy; public Player GetRunoutBy() => runoutBy; } class WicketBuilder { private readonly WicketType wicketType; private readonly Player playerOut; private Player caughtBy; private Player runoutBy; public WicketBuilder(WicketType type, Player player) { wicketType = type; playerOut = player; } public WicketBuilder WithCaughtBy(Player player) { caughtBy = player; return this; } public WicketBuilder WithRunoutBy(Player player) { runoutBy = player; return this; } public Wicket Build() { return new Wicket(this); } internal WicketType WicketType => wicketType; internal Player PlayerOut => playerOut; internal Player CaughtBy => caughtBy; internal Player RunoutBy => runoutBy; } ================================================ FILE: solutions/csharp/cricinfo/Observers/CommentaryDisplay.cs ================================================ class CommentaryDisplay : IMatchObserver { public void Update(Match match, Ball lastBall) { if (match.GetCurrentStatus() == MatchStatus.FINISHED) { Console.WriteLine("[COMMENTARY]: Match has finished!"); } else if (match.GetCurrentStatus() == MatchStatus.IN_BREAK) { Console.WriteLine("[COMMENTARY]: Inning has ended!"); } else if (lastBall != null) { Console.WriteLine($"[COMMENTARY]: {lastBall.GetCommentary()}"); } } } ================================================ FILE: solutions/csharp/cricinfo/Observers/IMatchObserver.cs ================================================ interface IMatchObserver { void Update(Match match, Ball lastBall); } ================================================ FILE: solutions/csharp/cricinfo/Observers/ScorecardDisplay.cs ================================================ class ScorecardDisplay : IMatchObserver { public void Update(Match match, Ball lastBall) { if (match.GetCurrentStatus() == MatchStatus.FINISHED) { Console.WriteLine("\n--- MATCH RESULT ---"); Console.WriteLine(match.GetResultMessage().ToUpper()); Console.WriteLine("--------------------"); Console.WriteLine("Player Stats:"); int counter = 1; foreach (var inning in match.GetInnings()) { Console.WriteLine($"Inning {counter++}"); inning.PrintPlayerStats(); } } else if (match.GetCurrentStatus() == MatchStatus.IN_BREAK) { Console.WriteLine("\n--- END OF INNINGS ---"); var lastInnings = match.GetInnings().Last(); Console.WriteLine($"Final Score: {lastInnings.GetBattingTeam().GetName()}: " + $"{lastInnings.GetScore()}/{lastInnings.GetWickets()} " + $"(Overs: {lastInnings.GetOvers():F1})"); Console.WriteLine("------------------------"); } else { Console.WriteLine("\n--- SCORECARD UPDATE ---"); var currentInnings = match.GetCurrentInnings(); Console.WriteLine($"{currentInnings.GetBattingTeam().GetName()}: " + $"{currentInnings.GetScore()}/{currentInnings.GetWickets()} " + $"(Overs: {currentInnings.GetOvers():F1})"); Console.WriteLine("------------------------"); } } } ================================================ FILE: solutions/csharp/cricinfo/Observers/UserNotifier.cs ================================================ class UserNotifier : IMatchObserver { public void Update(Match match, Ball lastBall) { if (match.GetCurrentStatus() == MatchStatus.FINISHED) { Console.WriteLine("[NOTIFICATION]: Match has finished!"); } else if (match.GetCurrentStatus() == MatchStatus.IN_BREAK) { Console.WriteLine("[NOTIFICATION]: Inning has ended!"); } else if (lastBall != null && lastBall.IsWicket()) { Console.WriteLine("[NOTIFICATION]: Wicket! A player is out."); } else if (lastBall != null && lastBall.IsBoundary()) { Console.WriteLine($"[NOTIFICATION]: It's a boundary! {lastBall.GetRunsScored()} runs."); } } } ================================================ FILE: solutions/csharp/cricinfo/README.md ================================================ # Designing a Cricket Information System like CricInfo ## Requirements 1. The Cricinfo system should provide information about cricket matches, teams, players, and live scores. 2. Users should be able to view the schedule of upcoming matches and the results of completed matches. 3. The system should allow users to search for specific matches, teams, or players. 4. Users should be able to view detailed information about a particular match, including the scorecard, commentary, and statistics. 5. The system should support real-time updates of live scores and match information. 6. The system should handle concurrent access to match data and ensure data consistency. 7. The system should be scalable and able to handle a large volume of user requests. 8. The system should be extensible to accommodate new features and enhancements in the future. ## Classes, Interfaces and Enumerations 1. The **Match** class represents a cricket match, with properties such as ID, title, venue, start time, teams, status, and scorecard. 2. The **Team** class represents a cricket team, with properties like ID, name, and a list of players. 3. The **Player** class represents a cricket player, with properties such as ID, name, and role. 4. The **Scorecard** class represents the scorecard of a match, containing team scores and a list of innings. 5. The **Innings** class represents an innings in a match, with properties like ID, batting team, bowling team, and a list of overs. 6. The **Over** class represents an over in an innings, containing a list of balls. 7. The **Ball** class represents a ball bowled in an over, with properties such as ball number, bowler, batsman, and result. 8. The **MatchStatus** enum represents the different statuses of a match, such as scheduled, in progress, completed, or abandoned. 9. The **MatchService** class manages the matches in the system, providing methods to add, retrieve, and update match information. It follows the Singleton pattern to ensure a single instance of the service. 10. The **ScorecardService** class manages the scorecards of matches, allowing the creation, retrieval, and update of scorecards and their associated data, such as innings and scores. It also follows the Singleton pattern. 11. The **CricinfoSystem** class serves as the main entry point of the system, integrating the match and scorecard services and providing high-level methods for interacting with the system. ================================================ FILE: solutions/csharp/cricinfo/Repositories/MatchRepository.cs ================================================ class MatchRepository { private readonly Dictionary matches = new Dictionary(); public void Save(Match match) { matches[match.GetId()] = match; } public Match FindById(string id) { return matches.ContainsKey(id) ? matches[id] : null; } } ================================================ FILE: solutions/csharp/cricinfo/Repositories/PlayerRepository.cs ================================================ class PlayerRepository { private readonly Dictionary players = new Dictionary(); public void Save(Player player) { players[player.GetId()] = player; } public Player FindById(string id) { return players.ContainsKey(id) ? players[id] : null; } } ================================================ FILE: solutions/csharp/cricinfo/States/FinishedState.cs ================================================ class FinishedState : IMatchState { public void ProcessBall(Match match, Ball ball) { Console.WriteLine("ERROR: Cannot process a ball for a finished match."); } public void StartNextInnings(Match match) { Console.WriteLine("ERROR: Cannot start the next innings from the current state."); } } ================================================ FILE: solutions/csharp/cricinfo/States/IMatchState.cs ================================================ interface IMatchState { void ProcessBall(Match match, Ball ball); void StartNextInnings(Match match); } ================================================ FILE: solutions/csharp/cricinfo/States/InBreakState.cs ================================================ class InBreakState : IMatchState { public void ProcessBall(Match match, Ball ball) { Console.WriteLine("ERROR: Cannot process a ball. The match is currently in a break."); } public void StartNextInnings(Match match) { Console.WriteLine("Starting the next innings..."); match.CreateNewInnings(); match.SetState(new LiveState()); match.SetCurrentStatus(MatchStatus.LIVE); } } ================================================ FILE: solutions/csharp/cricinfo/States/LiveState.cs ================================================ class LiveState : IMatchState { public void ProcessBall(Match match, Ball ball) { var currentInnings = match.GetCurrentInnings(); currentInnings.AddBall(ball); match.NotifyObservers(ball); CheckForMatchEnd(match); } public void StartNextInnings(Match match) { Console.WriteLine("ERROR: Cannot start the next innings from the current state."); } private void CheckForMatchEnd(Match match) { var currentInnings = match.GetCurrentInnings(); int inningsCount = match.GetInnings().Count; bool isFinalInnings = (inningsCount == match.GetFormatStrategy().GetTotalInnings()); if (isFinalInnings) { int targetScore = match.GetInnings()[0].GetScore() + 1; if (currentInnings.GetScore() >= targetScore) { int wicketsRemaining = (currentInnings.GetBattingTeam().GetPlayers().Count - 1) - currentInnings.GetWickets(); DeclareWinner(match, currentInnings.GetBattingTeam(), $"won by {wicketsRemaining} wickets"); return; } } if (IsInningsOver(match)) { if (isFinalInnings) { int score1 = match.GetInnings()[0].GetScore(); int score2 = currentInnings.GetScore(); if (score1 > score2) { DeclareWinner(match, match.GetTeam1(), $"won by {score1 - score2} runs"); } else if (score2 > score1) { int wicketsRemaining = (currentInnings.GetBattingTeam().GetPlayers().Count - 1) - currentInnings.GetWickets(); DeclareWinner(match, currentInnings.GetBattingTeam(), $"won by {wicketsRemaining} wickets"); } else { DeclareWinner(match, null, "Match Tied"); } } else { Console.WriteLine("End of the innings!"); match.SetState(new InBreakState()); match.SetCurrentStatus(MatchStatus.IN_BREAK); match.NotifyObservers(null); } } } private void DeclareWinner(Match match, Team winningTeam, string message) { Console.WriteLine("MATCH FINISHED!"); match.SetWinner(winningTeam); string resultMessage = winningTeam != null ? $"{winningTeam.GetName()} {message}" : message; match.SetResultMessage(resultMessage); match.SetState(new FinishedState()); match.SetCurrentStatus(MatchStatus.FINISHED); match.NotifyObservers(null); } private bool IsInningsOver(Match match) { var currentInnings = match.GetCurrentInnings(); bool allOut = currentInnings.GetWickets() >= currentInnings.GetBattingTeam().GetPlayers().Count - 1; bool oversFinished = (int)currentInnings.GetOvers() >= match.GetFormatStrategy().GetTotalOvers(); return allOut || oversFinished; } } ================================================ FILE: solutions/csharp/cricinfo/States/ScheduledState.cs ================================================ class ScheduledState : IMatchState { public void ProcessBall(Match match, Ball ball) { Console.WriteLine("ERROR: Cannot process a ball for a match that has not started."); } public void StartNextInnings(Match match) { Console.WriteLine("ERROR: Cannot start the next innings from the current state."); } } ================================================ FILE: solutions/csharp/cricinfo/Strategy/IMatchFormatStrategy.cs ================================================ interface IMatchFormatStrategy { int GetTotalInnings(); int GetTotalOvers(); string GetFormatName(); } ================================================ FILE: solutions/csharp/cricinfo/Strategy/ODIFormatStrategy.cs ================================================ class ODIFormatStrategy : IMatchFormatStrategy { public int GetTotalInnings() => 2; public int GetTotalOvers() => 50; public string GetFormatName() => "ODI"; } ================================================ FILE: solutions/csharp/cricinfo/Strategy/T20FormatStrategy.cs ================================================ class T20FormatStrategy : IMatchFormatStrategy { public int GetTotalInnings() => 2; public int GetTotalOvers() => 20; public string GetFormatName() => "T20"; } ================================================ FILE: solutions/csharp/cricinfo/cricinfo.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/digitalwalletservice/Account.cs ================================================ using System; using System.Collections.Generic; using System.Numerics; namespace DigitalWallet { public class Account { private readonly string id; private readonly User user; private readonly string accountNumber; private readonly Currency currency; private decimal balance; private readonly List transactions; public Account(string id, User user, string accountNumber, Currency currency) { this.id = id; this.user = user; this.accountNumber = accountNumber; this.currency = currency; this.balance = 0.0M; this.transactions = new List(); } public void Deposit(decimal amount) { balance = balance + amount; } public void Withdraw(decimal amount) { if (balance.CompareTo(amount) >= 0) { balance = balance - amount; } else { throw new InsufficientFundsException("Insufficient funds in the account."); } } public void AddTransaction(Transaction transaction) { transactions.Add(transaction); } public string GetId() { return id; } public User GetUser() { return user; } public Currency GetCurrency() { return currency; } public decimal GetBalance() { return balance; } public List GetTransactions() { return transactions; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/BankAccount.cs ================================================ using System; using System.Numerics; namespace DigitalWallet { public class BankAccount : PaymentMethod { private readonly string accountNumber; private readonly string routingNumber; public BankAccount(string id, User user, string accountNumber, string routingNumber) : base(id, user) { this.accountNumber = accountNumber; this.routingNumber = routingNumber; } public override bool ProcessPayment(decimal amount, Currency currency) { // Process bank account payment logic return true; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/CreditCard.cs ================================================ using System; using System.Numerics; namespace DigitalWallet { public class CreditCard : PaymentMethod { private readonly string cardNumber; private readonly string expirationDate; private readonly string cvv; public CreditCard(string id, User user, string cardNumber, string expirationDate, string cvv) : base(id, user) { this.cardNumber = cardNumber; this.expirationDate = expirationDate; this.cvv = cvv; } public override bool ProcessPayment(decimal amount, Currency currency) { // Process credit card payment logic return true; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/Currency.cs ================================================ namespace DigitalWallet { public enum Currency { USD, EUR, GBP, JPY } } ================================================ FILE: solutions/csharp/digitalwalletservice/CurrencyConverter.cs ================================================ using System; using System.Collections.Generic; using System.Numerics; namespace DigitalWallet { public class CurrencyConverter { private static readonly Dictionary exchangeRates = new Dictionary { { Currency.USD, 1.00M }, { Currency.EUR, 0.85M }, { Currency.GBP, 0.72M }, { Currency.JPY, 110.00M } }; public static decimal Convert(decimal amount, Currency sourceCurrency, Currency targetCurrency) { decimal sourceRate = exchangeRates[sourceCurrency]; decimal targetRate = exchangeRates[targetCurrency]; return amount * sourceRate / targetRate; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/DigitalWallet.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Numerics; namespace DigitalWallet { public class DigitalWallet { private static DigitalWallet instance; private readonly ConcurrentDictionary users; private readonly ConcurrentDictionary accounts; private readonly ConcurrentDictionary paymentMethods; private DigitalWallet() { users = new ConcurrentDictionary(); accounts = new ConcurrentDictionary(); paymentMethods = new ConcurrentDictionary(); } public static DigitalWallet GetInstance() { if (instance == null) { instance = new DigitalWallet(); } return instance; } public void CreateUser(User user) { users[user.GetId()] = user; } public User GetUser(string userId) { return users.ContainsKey(userId) ? users[userId] : null; } public void CreateAccount(Account account) { accounts[account.GetId()] = account; account.GetUser().AddAccount(account); } public Account GetAccount(string accountId) { return accounts.ContainsKey(accountId) ? accounts[accountId] : null; } public void AddPaymentMethod(PaymentMethod paymentMethod) { paymentMethods[paymentMethod.GetId()] = paymentMethod; } public PaymentMethod GetPaymentMethod(string paymentMethodId) { return paymentMethods.ContainsKey(paymentMethodId) ? paymentMethods[paymentMethodId] : null; } public void TransferFunds(Account sourceAccount, Account destinationAccount, decimal amount, Currency currency) { if (sourceAccount.GetCurrency() != currency) { amount = CurrencyConverter.Convert(amount, currency, sourceAccount.GetCurrency()); } sourceAccount.Withdraw(amount); if (destinationAccount.GetCurrency() != currency) { amount = CurrencyConverter.Convert(amount, currency, destinationAccount.GetCurrency()); } destinationAccount.Deposit(amount); string transactionId = GenerateTransactionId(); Transaction transaction = new Transaction(transactionId, sourceAccount, destinationAccount, amount, currency); sourceAccount.AddTransaction(transaction); destinationAccount.AddTransaction(transaction); } public List GetTransactionHistory(Account account) { return account.GetTransactions(); } private string GenerateTransactionId() { return "TXN" + Guid.NewGuid().ToString().Substring(0, 8).ToUpper(); } } } ================================================ FILE: solutions/csharp/digitalwalletservice/DigitalWalletDemo.cs ================================================ using System; using System.Collections.Generic; using System.Numerics; namespace DigitalWallet { public class DigitalWalletDemo { public static void Run() { DigitalWallet digitalWallet = DigitalWallet.GetInstance(); // Create users User user1 = new User("U001", "John Doe", "john@example.com", "password123"); User user2 = new User("U002", "Jane Smith", "jane@example.com", "password456"); digitalWallet.CreateUser(user1); digitalWallet.CreateUser(user2); // Create accounts Account account1 = new Account("A001", user1, "1234567890", Currency.USD); Account account2 = new Account("A002", user2, "9876543210", Currency.EUR); digitalWallet.CreateAccount(account1); digitalWallet.CreateAccount(account2); // Add payment methods PaymentMethod creditCard = new CreditCard("PM001", user1, "1234567890123456", "12/25", "123"); PaymentMethod bankAccount = new BankAccount("PM002", user2, "9876543210", "987654321"); digitalWallet.AddPaymentMethod(creditCard); digitalWallet.AddPaymentMethod(bankAccount); // Deposit funds account1.Deposit(1000.00M); account2.Deposit(500.00M); // Transfer funds digitalWallet.TransferFunds(account1, account2, 100.00M, Currency.USD); // Get transaction history List transactionHistory1 = digitalWallet.GetTransactionHistory(account1); List transactionHistory2 = digitalWallet.GetTransactionHistory(account2); // Print transaction history Console.WriteLine("Transaction History for Account 1:"); foreach (Transaction transaction in transactionHistory1) { Console.WriteLine("Transaction ID: " + transaction.GetId()); Console.WriteLine("Amount: " + transaction.GetAmount() + " " + transaction.GetCurrency()); Console.WriteLine("Timestamp: " + transaction.GetTimestamp()); Console.WriteLine(); } Console.WriteLine("Transaction History for Account 2:"); foreach (Transaction transaction in transactionHistory2) { Console.WriteLine("Transaction ID: " + transaction.GetId()); Console.WriteLine("Amount: " + transaction.GetAmount() + " " + transaction.GetCurrency()); Console.WriteLine("Timestamp: " + transaction.GetTimestamp()); Console.WriteLine(); } } } } ================================================ FILE: solutions/csharp/digitalwalletservice/InsufficientFundsException.cs ================================================ using System; namespace DigitalWallet { public class InsufficientFundsException : Exception { public InsufficientFundsException(string message) : base(message) { } } } ================================================ FILE: solutions/csharp/digitalwalletservice/PaymentMethod.cs ================================================ using System; using System.Numerics; namespace DigitalWallet { public abstract class PaymentMethod { protected readonly string id; protected readonly User user; protected PaymentMethod(string id, User user) { this.id = id; this.user = user; } public abstract bool ProcessPayment(decimal amount, Currency currency); public string GetId() { return id; } public User GetUser() { return user; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/README.md ================================================ # Designing a Digital Wallet System ## Requirements 1. The digital wallet should allow users to create an account and manage their personal information. 2. Users should be able to add and remove payment methods, such as credit cards or bank accounts. 3. The digital wallet should support fund transfers between users and to external accounts. 4. The system should handle transaction history and provide a statement of transactions. 5. The digital wallet should support multiple currencies and perform currency conversions. 6. The system should ensure the security of user information and transactions. 7. The digital wallet should handle concurrent transactions and ensure data consistency. 8. The system should be scalable to handle a large number of users and transactions. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the digital wallet, with properties such as ID, name, email, password, and a list of accounts. 2. The **Account** class represents a user's account within the digital wallet, with properties like ID, user, account number, currency, balance, and a list of transactions. It provides methods to deposit and withdraw funds. 3. The **Transaction** class represents a financial transaction between two accounts, containing properties such as ID, source account, destination account, amount, currency, and timestamp. 4. The **PaymentMethod** class is an abstract base class for different payment methods, such as credit cards and bank accounts. It defines the common properties and methods for processing payments. 5. The **CreditCard** and **BankAccount** classes are concrete implementations of the PaymentMethod class, representing specific payment methods. 6. The **Currency** enum represents different currencies supported by the digital wallet. 7. The **CurrencyConverter** class provides a static method to convert amounts between different currencies based on predefined exchange rates. 8. The **DigitalWallet** class is the central component of the digital wallet system. It follows the Singleton pattern to ensure only one instance of the digital wallet exists. It provides methods to create users, accounts, add payment methods, transfer funds, and retrieve transaction history. It handles concurrent access to shared resources using synchronization. 9. The **DigitalWalletDemo** class demonstrates the usage of the digital wallet system by creating users, accounts, adding payment methods, depositing funds, transferring funds, and retrieving transaction history. ================================================ FILE: solutions/csharp/digitalwalletservice/Transaction.cs ================================================ using System; using System.Numerics; namespace DigitalWallet { public class Transaction { private readonly string id; private readonly Account sourceAccount; private readonly Account destinationAccount; private readonly decimal amount; private readonly Currency currency; private readonly DateTime timestamp; public Transaction(string id, Account sourceAccount, Account destinationAccount, decimal amount, Currency currency) { this.id = id; this.sourceAccount = sourceAccount; this.destinationAccount = destinationAccount; this.amount = amount; this.currency = currency; this.timestamp = DateTime.Now; } public string GetId() { return id; } public Account GetSourceAccount() { return sourceAccount; } public Account GetDestinationAccount() { return destinationAccount; } public decimal GetAmount() { return amount; } public Currency GetCurrency() { return currency; } public DateTime GetTimestamp() { return timestamp; } } } ================================================ FILE: solutions/csharp/digitalwalletservice/User.cs ================================================ using System; using System.Collections.Generic; namespace DigitalWallet { public class User { private readonly string id; private readonly string name; private readonly string email; private readonly string password; private readonly List accounts; public User(string id, string name, string email, string password) { this.id = id; this.name = name; this.email = email; this.password = password; this.accounts = new List(); } public void AddAccount(Account account) { accounts.Add(account); } public void RemoveAccount(Account account) { accounts.Remove(account); } public string GetId() { return id; } } } ================================================ FILE: solutions/csharp/elevatorsystem/ElevatorSystem.cs ================================================ class ElevatorSystem { private static ElevatorSystem instance; private static readonly object lockObject = new object(); private readonly Dictionary elevators; private readonly IElevatorSelectionStrategy selectionStrategy; private readonly List elevatorTasks; private ElevatorSystem(int numElevators) { this.selectionStrategy = new NearestElevatorStrategy(); this.elevatorTasks = new List(); List elevatorList = new List(); Display display = new Display(); // Create the observer for (int i = 1; i <= numElevators; i++) { Elevator elevator = new Elevator(i); elevator.AddObserver(display); // Attach the observer elevatorList.Add(elevator); } this.elevators = elevatorList.ToDictionary(e => e.GetId(), e => e); } public static ElevatorSystem GetInstance(int numElevators) { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new ElevatorSystem(numElevators); } } } return instance; } public void Start() { foreach (Elevator elevator in elevators.Values) { elevatorTasks.Add(Task.Run(() => elevator.Run())); } } // --- Facade Methods --- // EXTERNAL Request (Hall Call) public void RequestElevator(int floor, Direction direction) { Console.WriteLine($"\n>> EXTERNAL Request: User at floor {floor} wants to go {direction}"); Request request = new Request(floor, direction, RequestSource.EXTERNAL); // Use strategy to find the best elevator Elevator selectedElevator = selectionStrategy.SelectElevator(elevators.Values.ToList(), request); if (selectedElevator != null) { selectedElevator.AddRequest(request); } else { Console.WriteLine("System busy, please wait."); } } // INTERNAL Request (Cabin Call) public void SelectFloor(int elevatorId, int destinationFloor) { Console.WriteLine($"\n>> INTERNAL Request: User in Elevator {elevatorId} selected floor {destinationFloor}"); Request request = new Request(destinationFloor, Direction.IDLE, RequestSource.INTERNAL); if (elevators.TryGetValue(elevatorId, out Elevator elevator)) { elevator.AddRequest(request); } else { Console.Error.WriteLine("Invalid elevator ID."); } } public void Shutdown() { Console.WriteLine("Shutting down elevator system..."); foreach (Elevator elevator in elevators.Values) { elevator.StopElevator(); } Task.WaitAll(elevatorTasks.ToArray()); } } ================================================ FILE: solutions/csharp/elevatorsystem/ElevatorSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using System.Linq; public class ElevatorSystemDemo { public static void Main(string[] args) { // Setup: A building with 2 elevators int numElevators = 2; // The GetInstance method now initializes the elevators and attaches the Display (Observer). ElevatorSystem elevatorSystem = ElevatorSystem.GetInstance(numElevators); // Start the elevator system elevatorSystem.Start(); Console.WriteLine("Elevator system started. ConsoleDisplay is observing.\n"); // --- SIMULATION START --- // 1. External Request: User at floor 5 wants to go UP. // The system will dispatch this to the nearest elevator (likely E1 or E2, both at floor 1). elevatorSystem.RequestElevator(5, Direction.UP); Thread.Sleep(100); // Wait for the elevator to start moving // 2. Internal Request: Assume E1 took the previous request. // The user gets in at floor 5 and presses 10. // We send this request directly to E1. // Note: In a real simulation, we'd wait until E1 reaches floor 5, but for this demo, // we simulate the internal button press shortly after the external one. elevatorSystem.SelectFloor(1, 10); Thread.Sleep(200); // 3. External Request: User at floor 3 wants to go DOWN. // E2 (likely still idle at floor 1) might take this, or E1 if it's convenient. elevatorSystem.RequestElevator(3, Direction.DOWN); Thread.Sleep(300); // 4. Internal Request: User in E2 presses 1. elevatorSystem.SelectFloor(2, 1); // Let the simulation run for a while to observe the display updates Console.WriteLine("\n--- Letting simulation run for 1 second ---"); Thread.Sleep(1000); // Shutdown the system elevatorSystem.Shutdown(); Console.WriteLine("\n--- SIMULATION END ---"); } } ================================================ FILE: solutions/csharp/elevatorsystem/Enums/Direction.cs ================================================ enum Direction { UP, DOWN, IDLE } ================================================ FILE: solutions/csharp/elevatorsystem/Enums/RequestSource.cs ================================================ enum RequestSource { INTERNAL, // From inside the cabin EXTERNAL // From the hall/floor } ================================================ FILE: solutions/csharp/elevatorsystem/Models/Elevator.cs ================================================ class Elevator { private readonly int id; private int currentFloor; private IElevatorState state; private volatile bool isRunning = true; private readonly SortedSet upRequests; private readonly SortedSet downRequests; private readonly object lockObject = new object(); // Observer Pattern: List of observers private readonly List observers = new List(); public Elevator(int id) { this.id = id; this.currentFloor = 1; this.upRequests = new SortedSet(); this.downRequests = new SortedSet(Comparer.Create((a, b) => b.CompareTo(a))); this.state = new IdleState(); } // --- Observer Pattern Methods --- public void AddObserver(IElevatorObserver observer) { observers.Add(observer); observer.Update(this); // Send initial state } public void NotifyObservers() { foreach (IElevatorObserver observer in observers) { observer.Update(this); } } // --- State Pattern Methods --- public void SetState(IElevatorState state) { this.state = state; NotifyObservers(); // Notify observers on direction change } public void Move() { state.Move(this); } // --- Request Handling --- public void AddRequest(Request request) { lock (lockObject) { Console.WriteLine($"Elevator {id} processing: {request}"); state.AddRequest(this, request); } } // --- Getters and Setters --- public int GetId() => id; public int GetCurrentFloor() { lock (lockObject) { return currentFloor; } } public void SetCurrentFloor(int floor) { lock (lockObject) { this.currentFloor = floor; } NotifyObservers(); // Notify observers on floor change } public Direction GetDirection() => state.GetDirection(); public SortedSet GetUpRequests() => upRequests; public SortedSet GetDownRequests() => downRequests; public bool IsRunning() => isRunning; public void StopElevator() => isRunning = false; public void Run() { while (isRunning) { Move(); try { Thread.Sleep(1000); // Simulate movement time } catch (ThreadInterruptedException) { isRunning = false; } } } } ================================================ FILE: solutions/csharp/elevatorsystem/Models/Request.cs ================================================ class Request { private readonly int targetFloor; private readonly Direction direction; private readonly RequestSource source; public Request(int targetFloor, Direction direction, RequestSource source) { this.targetFloor = targetFloor; this.direction = direction; this.source = source; } public int GetTargetFloor() => targetFloor; public Direction GetDirection() => direction; public RequestSource GetSource() => source; public override string ToString() { if (source == RequestSource.EXTERNAL) { return $"{source} Request to floor {targetFloor} going {direction}"; } else { return $"{source} Request to floor {targetFloor}"; } } } ================================================ FILE: solutions/csharp/elevatorsystem/Observer/Display.cs ================================================ class Display : IElevatorObserver { public void Update(Elevator elevator) { Console.WriteLine($"[DISPLAY] Elevator {elevator.GetId()} | Current Floor: {elevator.GetCurrentFloor()} | Direction: {elevator.GetDirection()}"); } } ================================================ FILE: solutions/csharp/elevatorsystem/Observer/IElevatorObserver.cs ================================================ interface IElevatorObserver { void Update(Elevator elevator); } ================================================ FILE: solutions/csharp/elevatorsystem/README.md ================================================ # Designing an Elevator System ## Requirements 1. The elevator system should consist of multiple elevators serving multiple floors. 2. Each elevator should have a capacity limit and should not exceed it. 3. Users should be able to request an elevator from any floor and select a destination floor. 4. The elevator system should efficiently handle user requests and optimize the movement of elevators to minimize waiting time. 5. The system should prioritize requests based on the direction of travel and the proximity of the elevators to the requested floor. 6. The elevators should be able to handle multiple requests concurrently and process them in an optimal order. 7. The system should ensure thread safety and prevent race conditions when multiple threads interact with the elevators. ## Classes, Interfaces and Enumerations 1. The **Direction** enum represents the possible directions of elevator movement (UP or DOWN). 2. The **Request** class represents a user request for an elevator, containing the source floor and destination floor. 3. The **Elevator** class represents an individual elevator in the system. It has a capacity limit and maintains a list of 4. requests. The elevator processes requests concurrently and moves between floors based on the requests. 4. The **ElevatorController** class manages multiple elevators and handles user requests. It finds the optimal elevator to serve a request based on the proximity of the elevators to the requested floor. 5. The **ElevatorSystem** class is the entry point of the application and demonstrates the usage of the elevator system. ================================================ FILE: solutions/csharp/elevatorsystem/States/IElevatorState.cs ================================================ interface IElevatorState { void Move(Elevator elevator); void AddRequest(Elevator elevator, Request request); Direction GetDirection(); } ================================================ FILE: solutions/csharp/elevatorsystem/States/IdleState.cs ================================================ class IdleState : IElevatorState { public void Move(Elevator elevator) { if (elevator.GetUpRequests().Count > 0) { elevator.SetState(new MovingUpState()); } else if (elevator.GetDownRequests().Count > 0) { elevator.SetState(new MovingDownState()); } // Else stay idle } public void AddRequest(Elevator elevator, Request request) { if (request.GetTargetFloor() > elevator.GetCurrentFloor()) { elevator.GetUpRequests().Add(request.GetTargetFloor()); } else if (request.GetTargetFloor() < elevator.GetCurrentFloor()) { elevator.GetDownRequests().Add(request.GetTargetFloor()); } // If request is for current floor, doors would open (handled implicitly by moving to that floor) } public Direction GetDirection() => Direction.IDLE; } ================================================ FILE: solutions/csharp/elevatorsystem/States/MovingDownState.cs ================================================ class MovingDownState : IElevatorState { public void Move(Elevator elevator) { if (elevator.GetDownRequests().Count == 0) { elevator.SetState(new IdleState()); return; } int nextFloor = elevator.GetDownRequests().Max(); elevator.SetCurrentFloor(elevator.GetCurrentFloor() - 1); if (elevator.GetCurrentFloor() == nextFloor) { Console.WriteLine($"Elevator {elevator.GetId()} stopped at floor {nextFloor}"); elevator.GetDownRequests().Remove(nextFloor); } if (elevator.GetDownRequests().Count == 0) { elevator.SetState(new IdleState()); } } public void AddRequest(Elevator elevator, Request request) { // Internal requests always get added to the appropriate queue if (request.GetSource() == RequestSource.INTERNAL) { if (request.GetTargetFloor() > elevator.GetCurrentFloor()) { elevator.GetUpRequests().Add(request.GetTargetFloor()); } else { elevator.GetDownRequests().Add(request.GetTargetFloor()); } return; } // External requests if (request.GetDirection() == Direction.DOWN && request.GetTargetFloor() <= elevator.GetCurrentFloor()) { elevator.GetDownRequests().Add(request.GetTargetFloor()); } else if (request.GetDirection() == Direction.UP) { elevator.GetUpRequests().Add(request.GetTargetFloor()); } } public Direction GetDirection() => Direction.DOWN; } ================================================ FILE: solutions/csharp/elevatorsystem/States/MovingUpState.cs ================================================ class MovingUpState : IElevatorState { public void Move(Elevator elevator) { if (elevator.GetUpRequests().Count == 0) { elevator.SetState(new IdleState()); return; } int nextFloor = elevator.GetUpRequests().Min(); elevator.SetCurrentFloor(elevator.GetCurrentFloor() + 1); if (elevator.GetCurrentFloor() == nextFloor) { Console.WriteLine($"Elevator {elevator.GetId()} stopped at floor {nextFloor}"); elevator.GetUpRequests().Remove(nextFloor); } if (elevator.GetUpRequests().Count == 0) { elevator.SetState(new IdleState()); } } public void AddRequest(Elevator elevator, Request request) { // Internal requests always get added to the appropriate queue if (request.GetSource() == RequestSource.INTERNAL) { if (request.GetTargetFloor() > elevator.GetCurrentFloor()) { elevator.GetUpRequests().Add(request.GetTargetFloor()); } else { elevator.GetDownRequests().Add(request.GetTargetFloor()); } return; } // External requests if (request.GetDirection() == Direction.UP && request.GetTargetFloor() >= elevator.GetCurrentFloor()) { elevator.GetUpRequests().Add(request.GetTargetFloor()); } else if (request.GetDirection() == Direction.DOWN) { elevator.GetDownRequests().Add(request.GetTargetFloor()); } } public Direction GetDirection() => Direction.UP; } ================================================ FILE: solutions/csharp/elevatorsystem/Strategy/IElevatorSelectionStrategy.cs ================================================ interface IElevatorSelectionStrategy { Elevator SelectElevator(List elevators, Request request); } ================================================ FILE: solutions/csharp/elevatorsystem/Strategy/NearestElevatorStrategy.cs ================================================ class NearestElevatorStrategy : IElevatorSelectionStrategy { public Elevator SelectElevator(List elevators, Request request) { Elevator bestElevator = null; int minDistance = int.MaxValue; foreach (Elevator elevator in elevators) { if (IsSuitable(elevator, request)) { int distance = Math.Abs(elevator.GetCurrentFloor() - request.GetTargetFloor()); if (distance < minDistance) { minDistance = distance; bestElevator = elevator; } } } return bestElevator; } private bool IsSuitable(Elevator elevator, Request request) { if (elevator.GetDirection() == Direction.IDLE) return true; if (elevator.GetDirection() == request.GetDirection()) { if (request.GetDirection() == Direction.UP && elevator.GetCurrentFloor() <= request.GetTargetFloor()) return true; if (request.GetDirection() == Direction.DOWN && elevator.GetCurrentFloor() >= request.GetTargetFloor()) return true; } return false; } } ================================================ FILE: solutions/csharp/elevatorsystem/elevatorsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/fooddeliveryservice/Enums/OrderStatus.cs ================================================ enum OrderStatus { PENDING, CONFIRMED, PREPARING, READY_FOR_PICKUP, OUT_FOR_DELIVERY, DELIVERED, CANCELLED } ================================================ FILE: solutions/csharp/fooddeliveryservice/FoodDeliveryService.cs ================================================ using System.Collections.Concurrent; class FoodDeliveryService { private static volatile FoodDeliveryService instance; private static readonly object lockObject = new object(); private readonly ConcurrentDictionary customers = new ConcurrentDictionary(); private readonly ConcurrentDictionary restaurants = new ConcurrentDictionary(); private readonly ConcurrentDictionary deliveryAgents = new ConcurrentDictionary(); private readonly ConcurrentDictionary orders = new ConcurrentDictionary(); private IDeliveryAssignmentStrategy assignmentStrategy; private FoodDeliveryService() { } public static FoodDeliveryService GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) instance = new FoodDeliveryService(); } } return instance; } public void SetAssignmentStrategy(IDeliveryAssignmentStrategy assignmentStrategy) { this.assignmentStrategy = assignmentStrategy; } public Customer RegisterCustomer(string name, string phone, Address address) { Customer customer = new Customer(name, phone, address); customers.TryAdd(customer.GetId(), customer); return customer; } public Restaurant RegisterRestaurant(string name, Address address) { Restaurant restaurant = new Restaurant(name, address); restaurants.TryAdd(restaurant.GetId(), restaurant); return restaurant; } public DeliveryAgent RegisterDeliveryAgent(string name, string phone, Address initialLocation) { DeliveryAgent deliveryAgent = new DeliveryAgent(name, phone, initialLocation); deliveryAgents.TryAdd(deliveryAgent.GetId(), deliveryAgent); return deliveryAgent; } public Order PlaceOrder(string customerId, string restaurantId, List items) { if (!customers.TryGetValue(customerId, out Customer customer) || !restaurants.TryGetValue(restaurantId, out Restaurant restaurant)) { throw new KeyNotFoundException("Customer or Restaurant not found."); } Order order = new Order(customer, restaurant, items); orders.TryAdd(order.GetId(), order); customer.AddOrderToHistory(order); Console.WriteLine($"Order {order.GetId()} placed by {customer.GetName()} at {restaurant.GetName()}."); order.SetStatus(OrderStatus.PENDING); return order; } public void UpdateOrderStatus(string orderId, OrderStatus newStatus) { if (!orders.TryGetValue(orderId, out Order order)) { throw new KeyNotFoundException("Order not found."); } order.SetStatus(newStatus); if (newStatus == OrderStatus.READY_FOR_PICKUP) { AssignDelivery(order); } } public void CancelOrder(string orderId) { if (!orders.TryGetValue(orderId, out Order order)) { Console.WriteLine($"ERROR: Order with ID {orderId} not found."); return; } if (order.Cancel()) { Console.WriteLine($"SUCCESS: Order {orderId} has been successfully canceled."); } else { Console.WriteLine($"FAILED: Order {orderId} could not be canceled. Its status is: {order.GetStatus()}"); } } private void AssignDelivery(Order order) { List availableAgents = deliveryAgents.Values.ToList(); DeliveryAgent agent = assignmentStrategy.FindAgent(order, availableAgents); if (agent != null) { order.AssignDeliveryAgent(agent); double distance = agent.GetCurrentLocation().DistanceTo(order.GetRestaurant().GetAddress()); Console.WriteLine($"Agent {agent.GetName()} (dist: {distance:F2}) assigned to order {order.GetId()}."); order.SetStatus(OrderStatus.OUT_FOR_DELIVERY); } else { Console.WriteLine($"No available delivery agents found for order {order.GetId()}"); } } public List SearchRestaurants(List strategies) { List results = restaurants.Values.ToList(); foreach (var strategy in strategies) { results = strategy.Filter(results); } return results; } public Menu GetRestaurantMenu(string restaurantId) { if (!restaurants.TryGetValue(restaurantId, out Restaurant restaurant)) { throw new KeyNotFoundException($"Restaurant with ID {restaurantId} not found."); } return restaurant.GetMenu(); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/FoodDeliveryServiceDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class FoodDeliveryServiceDemo { public static void Main(string[] args) { // 1. Setup the system FoodDeliveryService service = FoodDeliveryService.GetInstance(); service.SetAssignmentStrategy(new NearestAvailableAgentStrategy()); // 2. Define Addresses Address aliceAddress = new Address("123 Maple St", "Springfield", "12345", 40.7128, -74.0060); Address pizzaAddress = new Address("456 Oak Ave", "Springfield", "12345", 40.7138, -74.0070); Address burgerAddress = new Address("789 Pine Ln", "Springfield", "12345", 40.7108, -74.0050); Address tacoAddress = new Address("101 Elm Ct", "Shelbyville", "54321", 41.7528, -75.0160); // 3. Register entities Customer alice = service.RegisterCustomer("Alice", "123-4567-890", aliceAddress); Restaurant pizzaPalace = service.RegisterRestaurant("Pizza Palace", pizzaAddress); Restaurant burgerBarn = service.RegisterRestaurant("Burger Barn", burgerAddress); Restaurant tacoTown = service.RegisterRestaurant("Taco Town", tacoAddress); service.RegisterDeliveryAgent("Bob", "321-4567-880", new Address("1 B", "Springfield", "12345", 40.71, -74.00)); // 4. Setup menus pizzaPalace.AddToMenu(new MenuItem("P001", "Margherita Pizza", 12.99)); pizzaPalace.AddToMenu(new MenuItem("P002", "Veggie Pizza", 11.99)); burgerBarn.AddToMenu(new MenuItem("B001", "Classic Burger", 8.99)); tacoTown.AddToMenu(new MenuItem("T001", "Crunchy Taco", 3.50)); // 5. Demonstrate Search Functionality Console.WriteLine("\n--- 1. Searching for Restaurants ---"); // (A) Search by City Console.WriteLine("\n(A) Restaurants in 'Springfield':"); List citySearch = new List { new SearchByCityStrategy("Springfield") }; List springfieldRestaurants = service.SearchRestaurants(citySearch); foreach (var r in springfieldRestaurants) { Console.WriteLine($" - {r.GetName()}"); } // (B) Search for restaurants near Alice Console.WriteLine("\n(B) Restaurants near Alice (within 0.01 distance units):"); List proximitySearch = new List { new SearchByProximityStrategy(aliceAddress, 0.01) }; List nearbyRestaurants = service.SearchRestaurants(proximitySearch); foreach (var r in nearbyRestaurants) { Console.WriteLine($" - {r.GetName()} (Distance: {aliceAddress.DistanceTo(r.GetAddress()):F4})"); } // (C) Search for restaurants that serve 'Pizza' Console.WriteLine("\n(C) Restaurants that serve 'Pizza':"); List menuSearch = new List { new SearchByMenuKeywordStrategy("Pizza") }; List pizzaRestaurants = service.SearchRestaurants(menuSearch); foreach (var r in pizzaRestaurants) { Console.WriteLine($" - {r.GetName()}"); } // (D) Combined Search: Find restaurants near Alice that serve 'Burger' Console.WriteLine("\n(D) Burger joints near Alice:"); List combinedSearch = new List { new SearchByProximityStrategy(aliceAddress, 0.01), new SearchByMenuKeywordStrategy("Burger") }; List burgerJointsNearAlice = service.SearchRestaurants(combinedSearch); foreach (var r in burgerJointsNearAlice) { Console.WriteLine($" - {r.GetName()}"); } // 6. Demonstrate Browsing a Menu Console.WriteLine("\n--- 2. Browsing a Menu ---"); Console.WriteLine("\nMenu for 'Pizza Palace':"); Menu pizzaMenu = service.GetRestaurantMenu(pizzaPalace.GetId()); foreach (var item in pizzaMenu.GetItems().Values) { Console.WriteLine($" - {item.GetName()}: ${item.GetPrice():F2}"); } // 7. Alice places an order from a searched restaurant Console.WriteLine("\n--- 3. Placing an Order ---"); if (pizzaRestaurants.Count > 0) { Restaurant chosenRestaurant = pizzaRestaurants[0]; MenuItem chosenItem = chosenRestaurant.GetMenu().GetItem("P001"); Console.WriteLine($"\nAlice is ordering '{chosenItem.GetName()}' from '{chosenRestaurant.GetName()}'."); var order = service.PlaceOrder(alice.GetId(), chosenRestaurant.GetId(), new List { new OrderItem(chosenItem, 1) }); Console.WriteLine("\n--- Restaurant starts preparing the order ---"); service.UpdateOrderStatus(order.GetId(), OrderStatus.PREPARING); Console.WriteLine("\n--- Order is ready for pickup ---"); Console.WriteLine("System will now find the nearest available delivery agent..."); service.UpdateOrderStatus(order.GetId(), OrderStatus.READY_FOR_PICKUP); Console.WriteLine("\n--- Agent delivers the order ---"); service.UpdateOrderStatus(order.GetId(), OrderStatus.DELIVERED); } } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/Address.cs ================================================ class Address { private readonly string street; private readonly string city; private readonly string zipCode; private readonly double latitude; private readonly double longitude; public Address(string street, string city, string zipCode, double latitude, double longitude) { this.street = street; this.city = city; this.zipCode = zipCode; this.latitude = latitude; this.longitude = longitude; } public string GetCity() { return city; } public double DistanceTo(Address other) { double latDiff = latitude - other.latitude; double lonDiff = longitude - other.longitude; return Math.Sqrt(latDiff * latDiff + lonDiff * lonDiff); } public override string ToString() { return $"{street}, {city}, {zipCode} @({latitude}, {longitude})"; } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/Customer.cs ================================================ class Customer : User { private readonly Address address; private readonly List orderHistory = new List(); public Customer(string name, string phone, Address address) : base(name, phone) { this.address = address; } public void AddOrderToHistory(Order order) { orderHistory.Add(order); } public Address GetAddress() { return address; } public override void OnUpdate(Order order) { Console.WriteLine($"--- Notification for Customer {GetName()} ---"); Console.WriteLine($" Order {order.GetId()} is now {order.GetStatus()}."); Console.WriteLine("-------------------------------------\n"); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/DeliveryAgent.cs ================================================ class DeliveryAgent : User { private volatile bool isAvailable = true; private Address currentLocation; private readonly object locationLock = new object(); public DeliveryAgent(string name, string phone, Address currentLocation) : base(name, phone) { this.currentLocation = currentLocation; } public void SetAvailable(bool available) { isAvailable = available; } public bool IsAvailableAgent() { return isAvailable; } public void SetCurrentLocation(Address currentLocation) { lock (locationLock) { this.currentLocation = currentLocation; } } public Address GetCurrentLocation() { lock (locationLock) { return currentLocation; } } public override void OnUpdate(Order order) { Console.WriteLine($"--- Notification for Delivery Agent {GetName()} ---"); Console.WriteLine($" Order {order.GetId()} update: Status is {order.GetStatus()}."); Console.WriteLine("-------------------------------------------\n"); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/Menu.cs ================================================ class Menu { private readonly Dictionary items = new Dictionary(); public void AddItem(MenuItem item) { items[item.GetId()] = item; } public MenuItem GetItem(string id) { return items.ContainsKey(id) ? items[id] : null; } public Dictionary GetItems() { return new Dictionary(items); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/MenuItem.cs ================================================ class MenuItem { private readonly string id; private readonly string name; private readonly double price; private bool available; public MenuItem(string id, string name, double price) { this.id = id; this.name = name; this.price = price; this.available = true; } public string GetId() { return id; } public void SetAvailable(bool available) { this.available = available; } public string GetName() { return name; } public double GetPrice() { return price; } public string GetMenuItem() { return $"Name: {name}, Price: {price}"; } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/Order.cs ================================================ class Order { private readonly string id; private readonly Customer customer; private readonly Restaurant restaurant; private readonly List items; private OrderStatus status; private DeliveryAgent deliveryAgent; private readonly List observers = new List(); public Order(Customer customer, Restaurant restaurant, List items) { this.id = Guid.NewGuid().ToString(); this.customer = customer; this.restaurant = restaurant; this.items = items; this.status = OrderStatus.PENDING; AddObserver(customer); AddObserver(restaurant); } public void AddObserver(IOrderObserver observer) { observers.Add(observer); } private void NotifyObservers() { foreach (var observer in observers) { observer.OnUpdate(this); } } public void SetStatus(OrderStatus newStatus) { if (status != newStatus) { status = newStatus; NotifyObservers(); } } public bool Cancel() { if (status == OrderStatus.PENDING) { SetStatus(OrderStatus.CANCELLED); return true; } return false; } public void AssignDeliveryAgent(DeliveryAgent agent) { deliveryAgent = agent; AddObserver(agent); agent.SetAvailable(false); } public string GetId() { return id; } public OrderStatus GetStatus() { return status; } public Customer GetCustomer() { return customer; } public Restaurant GetRestaurant() { return restaurant; } public DeliveryAgent GetDeliveryAgent() { return deliveryAgent; } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/OrderItem.cs ================================================ class OrderItem { private readonly MenuItem item; private readonly int quantity; public OrderItem(MenuItem item, int quantity) { this.item = item; this.quantity = quantity; } public MenuItem GetItem() { return item; } public int GetQuantity() { return quantity; } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/Restaurant.cs ================================================ class Restaurant : IOrderObserver { private readonly string id; private readonly string name; private readonly Address address; private readonly Menu menu; public Restaurant(string name, Address address) { this.id = Guid.NewGuid().ToString(); this.name = name; this.address = address; this.menu = new Menu(); } public void AddToMenu(MenuItem item) { menu.AddItem(item); } public string GetId() { return id; } public string GetName() { return name; } public Address GetAddress() { return address; } public Menu GetMenu() { return menu; } public void OnUpdate(Order order) { Console.WriteLine($"--- Notification for Restaurant {GetName()} ---"); Console.WriteLine($" Order {order.GetId()} has been updated to {order.GetStatus()}."); Console.WriteLine("---------------------------------------\n"); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Models/User.cs ================================================ abstract class User : IOrderObserver { protected readonly string id; protected readonly string name; protected readonly string phone; public User(string name, string phone) { this.id = Guid.NewGuid().ToString(); this.name = name; this.phone = phone; } public string GetId() { return id; } public string GetName() { return name; } public abstract void OnUpdate(Order order); } ================================================ FILE: solutions/csharp/fooddeliveryservice/Observer/IOrderObserver.cs ================================================ interface IOrderObserver { void OnUpdate(Order order); } ================================================ FILE: solutions/csharp/fooddeliveryservice/README.md ================================================ # Designing an Online Food Delivery Service Like Swiggy ## Requirements 1. The food delivery service should allow customers to browse restaurants, view menus, and place orders. 2. Restaurants should be able to manage their menus, prices, and availability. 3. Delivery agents should be able to accept and fulfill orders. 4. The system should handle order tracking and status updates. 5. The system should support multiple payment methods. 6. The system should handle concurrent orders and ensure data consistency. 7. The system should be scalable and handle a high volume of orders. 8. The system should provide real-time notifications to customers, restaurants, and delivery agents. ## Classes, Interfaces and Enumerations 1. The **Customer** class represents a customer who can place orders. It contains customer details such as ID, name, email, and phone number. 2. The **Restaurant** class represents a restaurant that offers menu items. It contains restaurant details such as ID, name, address, and a list of menu items. It provides methods to add and remove menu items. 3. The **MenuItem** class represents an item on a restaurant's menu. It contains details such as ID, name, description, price, and availability status. 4. The **Order** class represents an order placed by a customer. It contains order details such as ID, customer, restaurant, list of order items, status, and assigned delivery agent. It provides methods to add and remove order items, update order status, and assign a delivery agent. 5. The **OrderItem** class represents an item within an order. It contains the selected menu item and the quantity ordered. 6. The **OrderStatus** enum represents the different statuses an order can have, such as PENDING, CONFIRMED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, and CANCELLED. 7. The **DeliveryAgent** class represents a delivery agent who fulfills orders. It contains details such as ID, name, phone number, and availability status. 8. The **FoodDeliveryService** class is the main class that manages the food delivery service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register customers, restaurants, and delivery agents, retrieve available restaurants and menus, place orders, update order status, cancel orders, and assign delivery agents to orders. It also handles notifications to customers, restaurants, and delivery agents. ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/assignment/IDeliveryAssignmentStrategy.cs ================================================ interface IDeliveryAssignmentStrategy { DeliveryAgent FindAgent(Order order, List agents); } ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/assignment/NearestAvailableAgentStrategy.cs ================================================ class NearestAvailableAgentStrategy : IDeliveryAssignmentStrategy { public DeliveryAgent FindAgent(Order order, List availableAgents) { Address restaurantAddress = order.GetRestaurant().GetAddress(); Address customerAddress = order.GetCustomer().GetAddress(); return availableAgents .Where(agent => agent.IsAvailableAgent()) .OrderBy(agent => CalculateTotalDistance(agent, restaurantAddress, customerAddress)) .FirstOrDefault(); } private double CalculateTotalDistance(DeliveryAgent agent, Address restaurantAddress, Address customerAddress) { double agentToRestaurantDist = agent.GetCurrentLocation().DistanceTo(restaurantAddress); double restaurantToCustomerDist = restaurantAddress.DistanceTo(customerAddress); return agentToRestaurantDist + restaurantToCustomerDist; } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/search/IRestaurantSearchStrategy.cs ================================================ interface IRestaurantSearchStrategy { List Filter(List allRestaurants); } ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/search/SearchByCityStrategy.cs ================================================ class SearchByCityStrategy : IRestaurantSearchStrategy { private readonly string city; public SearchByCityStrategy(string city) { this.city = city; } public List Filter(List allRestaurants) { return allRestaurants .Where(r => r.GetAddress().GetCity().Equals(city, StringComparison.OrdinalIgnoreCase)) .ToList(); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/search/SearchByMenuKeywordStrategy.cs ================================================ class SearchByMenuKeywordStrategy : IRestaurantSearchStrategy { private readonly string keyword; public SearchByMenuKeywordStrategy(string keyword) { this.keyword = keyword.ToLower(); } public List Filter(List allRestaurants) { return allRestaurants .Where(r => r.GetMenu().GetItems().Values .Any(item => item.GetName().ToLower().Contains(keyword))) .ToList(); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/Strategies/search/SearchByProximityStrategy.cs ================================================ class SearchByProximityStrategy : IRestaurantSearchStrategy { private readonly Address userLocation; private readonly double maxDistance; public SearchByProximityStrategy(Address userLocation, double maxDistance) { this.userLocation = userLocation; this.maxDistance = maxDistance; } public List Filter(List allRestaurants) { return allRestaurants .Where(r => userLocation.DistanceTo(r.GetAddress()) <= maxDistance) .OrderBy(r => userLocation.DistanceTo(r.GetAddress())) .ToList(); } } ================================================ FILE: solutions/csharp/fooddeliveryservice/fooddeliveryservice.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/hotelmanagementsystem/CashPayment.cs ================================================ namespace HotelManagement { public class CashPayment : Payment { public bool ProcessPayment(double amount) { // Process cash payment return true; } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/CreditCardPayment.cs ================================================ namespace HotelManagement { public class CreditCardPayment : Payment { public bool ProcessPayment(double amount) { // Process credit card payment return true; } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/Guest.cs ================================================ namespace HotelManagement { public class Guest { public string Id { get; } public string Name { get; } public string Email { get; } public string PhoneNumber { get; } public Guest(string id, string name, string email, string phoneNumber) { Id = id; Name = name; Email = email; PhoneNumber = phoneNumber; } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/HotelManagementSystem.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; namespace HotelManagement { public class HotelManagementSystem { private static HotelManagementSystem _instance; private readonly ConcurrentDictionary _guests; private readonly ConcurrentDictionary _rooms; private readonly ConcurrentDictionary _reservations; private HotelManagementSystem() { _guests = new ConcurrentDictionary(); _rooms = new ConcurrentDictionary(); _reservations = new ConcurrentDictionary(); } public static HotelManagementSystem Instance { get { if (_instance == null) { _instance = new HotelManagementSystem(); } return _instance; } } public void AddGuest(Guest guest) { _guests[guest.Id] = guest; } public Guest GetGuest(string guestId) { _guests.TryGetValue(guestId, out var guest); return guest; } public void AddRoom(Room room) { _rooms[room.Id] = room; } public Room GetRoom(string roomId) { _rooms.TryGetValue(roomId, out var room); return room; } public Reservation BookRoom(Guest guest, Room room, DateTime checkInDate, DateTime checkOutDate) { lock (room) { if (room.Status == RoomStatus.AVAILABLE) { room.Book(); var reservationId = GenerateReservationId(); var reservation = new Reservation(reservationId, guest, room, checkInDate, checkOutDate); _reservations[reservationId] = reservation; return reservation; } return null; } } public void CancelReservation(string reservationId) { lock (this) { if (_reservations.TryGetValue(reservationId, out var reservation)) { reservation.Cancel(); _reservations.TryRemove(reservationId, out _); } } } public void CheckIn(string reservationId) { lock (this) { if (_reservations.TryGetValue(reservationId, out var reservation) && reservation.Status == ReservationStatus.CONFIRMED) { reservation.Room.CheckIn(); } else { throw new InvalidOperationException("Invalid reservation or reservation not confirmed."); } } } public void CheckOut(string reservationId, Payment payment) { lock (this) { if (_reservations.TryGetValue(reservationId, out var reservation) && reservation.Status == ReservationStatus.CONFIRMED) { var room = reservation.Room; var amount = room.Price * (reservation.CheckOutDate - reservation.CheckInDate).TotalDays; if (payment.ProcessPayment(amount)) { room.CheckOut(); _reservations.TryRemove(reservationId, out _); } else { throw new InvalidOperationException("Payment failed."); } } else { throw new InvalidOperationException("Invalid reservation or reservation not confirmed."); } } } private string GenerateReservationId() { return "RES" + Guid.NewGuid().ToString("N").Substring(0, 8).ToUpper(); } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/HotelManagementSystemDemo.cs ================================================ using System; namespace HotelManagement { public class HotelManagementSystemDemo { public static void Run() { var hotelManagementSystem = HotelManagementSystem.Instance; // Create guests var guest1 = new Guest("G001", "John Doe", "john@example.com", "1234567890"); var guest2 = new Guest("G002", "Jane Smith", "jane@example.com", "9876543210"); hotelManagementSystem.AddGuest(guest1); hotelManagementSystem.AddGuest(guest2); // Create rooms var room1 = new Room("R001", RoomType.SINGLE, 100.0); var room2 = new Room("R002", RoomType.DOUBLE, 200.0); hotelManagementSystem.AddRoom(room1); hotelManagementSystem.AddRoom(room2); // Book a room var checkInDate = DateTime.Now; var checkOutDate = checkInDate.AddDays(3); var reservation1 = hotelManagementSystem.BookRoom(guest1, room1, checkInDate, checkOutDate); if (reservation1 != null) { Console.WriteLine("Reservation created: " + reservation1.Id); } else { Console.WriteLine("Room not available for booking."); } // Check-in hotelManagementSystem.CheckIn(reservation1.Id); Console.WriteLine("Checked in: " + reservation1.Id); // Check-out and process payment var payment = new CreditCardPayment(); hotelManagementSystem.CheckOut(reservation1.Id, payment); Console.WriteLine("Checked out: " + reservation1.Id); // Cancel a reservation hotelManagementSystem.CancelReservation(reservation1.Id); Console.WriteLine("Reservation cancelled: " + reservation1.Id); } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/Payment.cs ================================================ namespace HotelManagement { public interface Payment { bool ProcessPayment(double amount); } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/README.md ================================================ # Designing a Hotel Management System ## Requirements 1. The hotel management system should allow guests to book rooms, check-in, and check-out. 2. The system should manage different types of rooms, such as single, double, deluxe, and suite. 3. The system should handle room availability and reservation status. 4. The system should allow the hotel staff to manage guest information, room assignments, and billing. 5. The system should support multiple payment methods, such as cash, credit card, and online payment. 6. The system should handle concurrent bookings and ensure data consistency. 7. The system should provide reporting and analytics features for hotel management. 8. The system should be scalable and handle a large number of rooms and guests. ## Classes, Interfaces and Enumerations 1. The **Guest** class represents a guest of the hotel, with properties such as ID, name, email, and phone number. 2. The **Room** class represents a room in the hotel, with properties like ID, room type, price, and status. It provides methods to book, check-in, and check-out a room. 3. The **RoomType** enum represents the different types of rooms available in the hotel. 4. The **RoomStatus** enum represents the status of a room, which can be available, booked, or occupied. 5. The **Reservation** class represents a reservation made by a guest for a specific room and date range. It contains properties such as ID, guest, room, check-in date, check-out date, and status. It provides a method to cancel a reservation. 6. The **ReservationStatus** enum represents the status of a reservation, which can be confirmed or cancelled. 7. The **Payment** interface defines the contract for processing payments. It is implemented by concrete payment classes like CashPayment and CreditCardPayment. 8. The **HotelManagementSystem** class is the central component of the hotel management system. It follows the Singleton pattern to ensure only one instance of the system exists. It provides methods to add guests and rooms, book rooms, cancel reservations, check-in, check-out, and process payments. It also handles concurrent access to shared resources using synchronization. 9. The **HotelManagementSystemDemo** class demonstrates the usage of the hotel management system by creating guests, rooms, booking a room, checking in, checking out, and cancelling a reservation. ================================================ FILE: solutions/csharp/hotelmanagementsystem/Reservation.cs ================================================ using System; namespace HotelManagement { public class Reservation { public string Id { get; } public Guest Guest { get; } public Room Room { get; } public DateTime CheckInDate { get; } public DateTime CheckOutDate { get; } public ReservationStatus Status { get; private set; } public Reservation(string id, Guest guest, Room room, DateTime checkInDate, DateTime checkOutDate) { Id = id; Guest = guest; Room = room; CheckInDate = checkInDate; CheckOutDate = checkOutDate; Status = ReservationStatus.CONFIRMED; } public void Cancel() { if (Status == ReservationStatus.CONFIRMED) { Status = ReservationStatus.CANCELLED; Room.CheckOut(); } else { throw new InvalidOperationException("Reservation is not confirmed."); } } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/ReservationStatus.cs ================================================ namespace HotelManagement { public enum ReservationStatus { CONFIRMED, CANCELLED } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/Room.cs ================================================ namespace HotelManagement { public class Room { public string Id { get; } public RoomType Type { get; } public double Price { get; } public RoomStatus Status { get; private set; } public Room(string id, RoomType type, double price) { Id = id; Type = type; Price = price; Status = RoomStatus.AVAILABLE; } public void Book() { if (Status == RoomStatus.AVAILABLE) { Status = RoomStatus.BOOKED; } else { throw new InvalidOperationException("Room is not available for booking."); } } public void CheckIn() { if (Status == RoomStatus.BOOKED) { Status = RoomStatus.OCCUPIED; } else { throw new InvalidOperationException("Room is not booked."); } } public void CheckOut() { if (Status == RoomStatus.OCCUPIED) { Status = RoomStatus.AVAILABLE; } else { throw new InvalidOperationException("Room is not occupied."); } } } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/RoomStatus.cs ================================================ namespace HotelManagement { public enum RoomStatus { AVAILABLE, BOOKED, OCCUPIED } } ================================================ FILE: solutions/csharp/hotelmanagementsystem/RoomType.cs ================================================ namespace HotelManagement { public enum RoomType { SINGLE, DOUBLE, DELUXE, SUITE } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Enum/ItemType.cs ================================================ enum ItemType { BOOK, MAGAZINE } ================================================ FILE: solutions/csharp/librarymanagementsystem/Factory/ItemFactory.cs ================================================ class ItemFactory { public static LibraryItem CreateItem(ItemType type, string id, string title, string author) { switch (type) { case ItemType.BOOK: return new Book(id, title, author); case ItemType.MAGAZINE: return new Magazine(id, title, author); default: throw new ArgumentException("Unknown item type."); } } } ================================================ FILE: solutions/csharp/librarymanagementsystem/LibraryManagementSystem.cs ================================================ class LibraryManagementSystem { private static readonly LibraryManagementSystem instance = new LibraryManagementSystem(); private readonly Dictionary catalog = new Dictionary(); private readonly Dictionary members = new Dictionary(); private readonly Dictionary copies = new Dictionary(); private LibraryManagementSystem() { } public static LibraryManagementSystem GetInstance() { return instance; } public List AddItem(ItemType type, string id, string title, string author, int numCopies) { var bookCopies = new List(); var item = ItemFactory.CreateItem(type, id, title, author); catalog[id] = item; for (int i = 0; i < numCopies; i++) { string copyId = $"{id}-c{i + 1}"; var copy = new BookCopy(copyId, item); copies[copyId] = copy; bookCopies.Add(copy); } Console.WriteLine($"Added {numCopies} copies of '{title}'"); return bookCopies; } public Member AddMember(string id, string name) { var member = new Member(id, name); members[id] = member; return member; } public void Checkout(string memberId, string copyId) { if (members.TryGetValue(memberId, out var member) && copies.TryGetValue(copyId, out var copy)) { copy.Checkout(member); } else { Console.WriteLine("Error: Invalid member or copy ID."); } } public void ReturnItem(string copyId) { if (copies.TryGetValue(copyId, out var copy)) { copy.ReturnItem(); } else { Console.WriteLine("Error: Invalid copy ID."); } } public void PlaceHold(string memberId, string itemId) { if (members.TryGetValue(memberId, out var member) && catalog.TryGetValue(itemId, out var item)) { var checkedOutCopy = item.GetCopies().FirstOrDefault(c => !c.IsAvailable()); checkedOutCopy?.PlaceHold(member); } } public List Search(string query, ISearchStrategy strategy) { return strategy.Search(query, catalog.Values.ToList()); } public void PrintCatalog() { Console.WriteLine("\n--- Library Catalog ---"); foreach (var item in catalog.Values) { Console.WriteLine($"ID: {item.GetId()}, Title: {item.GetTitle()}, " + $"Author/Publisher: {item.GetAuthorOrPublisher()}, " + $"Available: {item.GetAvailableCopyCount()}"); } Console.WriteLine("-----------------------\n"); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/LibraryManagementSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; public class LibraryManagementDemo { public static void Main(string[] args) { var library = LibraryManagementSystem.GetInstance(); // === Setting up the Library === Console.WriteLine("=== Setting up the Library ==="); var hobbitCopies = library.AddItem(ItemType.BOOK, "B001", "The Hobbit", "J.R.R. Tolkien", 2); var duneCopies = library.AddItem(ItemType.BOOK, "B002", "Dune", "Frank Herbert", 1); var natGeoCopies = library.AddItem(ItemType.MAGAZINE, "M001", "National Geographic", "NatGeo Society", 3); var alice = library.AddMember("MEM01", "Alice"); var bob = library.AddMember("MEM02", "Bob"); var charlie = library.AddMember("MEM03", "Charlie"); library.PrintCatalog(); // === Scenario 1: Searching (Strategy Pattern) === Console.WriteLine("\n=== Scenario 1: Searching for Items ==="); Console.WriteLine("Searching for title 'Dune':"); var titleResults = library.Search("Dune", new SearchByTitleStrategy()); foreach (var item in titleResults) { Console.WriteLine($"Found: {item.GetTitle()}"); } Console.WriteLine("\nSearching for author 'Tolkien':"); var authorResults = library.Search("Tolkien", new SearchByAuthorStrategy()); foreach (var item in authorResults) { Console.WriteLine($"Found: {item.GetTitle()}"); } // === Scenario 2: Checkout and Return (State Pattern) === Console.WriteLine("\n\n=== Scenario 2: Checkout and Return ==="); library.Checkout(alice.GetId(), hobbitCopies[0].GetId()); library.Checkout(bob.GetId(), duneCopies[0].GetId()); library.PrintCatalog(); Console.WriteLine("Attempting to checkout an already checked-out book:"); library.Checkout(charlie.GetId(), hobbitCopies[0].GetId()); Console.WriteLine("\nAlice returns The Hobbit:"); library.ReturnItem(hobbitCopies[0].GetId()); library.PrintCatalog(); // === Scenario 3: Holds and Notifications (Observer Pattern) === Console.WriteLine("\n\n=== Scenario 3: Placing a Hold ==="); Console.WriteLine("Dune is checked out by Bob. Charlie places a hold."); library.PlaceHold(charlie.GetId(), "B002"); Console.WriteLine("\nBob returns Dune. Charlie should be notified."); library.ReturnItem(duneCopies[0].GetId()); Console.WriteLine("\nCharlie checks out the book that was on hold for him."); library.Checkout(charlie.GetId(), duneCopies[0].GetId()); Console.WriteLine("\nTrying to check out the same on-hold item by another member (Alice):"); library.Checkout(alice.GetId(), duneCopies[0].GetId()); library.PrintCatalog(); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/Book.cs ================================================ class Book : LibraryItem { private readonly string author; public Book(string id, string title, string author) : base(id, title) { this.author = author; } public override string GetAuthorOrPublisher() { return author; } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/BookCopy.cs ================================================ class BookCopy { private readonly string id; private readonly LibraryItem item; private IItemState currentState; public BookCopy(string id, LibraryItem item) { this.id = id; this.item = item; this.currentState = new AvailableState(); item.AddCopy(this); } public void Checkout(Member member) { currentState.Checkout(this, member); } public void ReturnItem() { currentState.ReturnItem(this); } public void PlaceHold(Member member) { currentState.PlaceHold(this, member); } public void SetState(IItemState state) { this.currentState = state; } public string GetId() { return id; } public LibraryItem GetItem() { return item; } public bool IsAvailable() { return currentState is AvailableState; } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/LibraryItem.cs ================================================ abstract class LibraryItem { private readonly string id; private readonly string title; protected readonly List copies = new List(); private readonly List observers = new List(); public LibraryItem(string id, string title) { this.id = id; this.title = title; } public void AddCopy(BookCopy copy) { copies.Add(copy); } public void AddObserver(Member member) { observers.Add(member); } public void RemoveObserver(Member member) { observers.Remove(member); } public void NotifyObservers() { Console.WriteLine($"Notifying {observers.Count} observers for '{title}'..."); var observersCopy = new List(observers); foreach (var observer in observersCopy) { observer.Update(this); } } public BookCopy GetAvailableCopy() { return copies.FirstOrDefault(copy => copy.IsAvailable()); } public string GetId() { return id; } public string GetTitle() { return title; } public List GetCopies() { return copies; } public abstract string GetAuthorOrPublisher(); public long GetAvailableCopyCount() { return copies.Count(copy => copy.IsAvailable()); } public bool HasObservers() { return observers.Count > 0; } public bool IsObserver(Member member) { return observers.Contains(member); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/Loan.cs ================================================ class Loan { private readonly BookCopy copy; private readonly Member member; private readonly DateTime checkoutDate; public Loan(BookCopy copy, Member member) { this.copy = copy; this.member = member; this.checkoutDate = DateTime.Now; } public BookCopy GetCopy() { return copy; } public Member GetMember() { return member; } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/Magazine.cs ================================================ class Magazine : LibraryItem { private readonly string publisher; public Magazine(string id, string title, string publisher) : base(id, title) { this.publisher = publisher; } public override string GetAuthorOrPublisher() { return publisher; } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/Member.cs ================================================ class Member { private readonly string id; private readonly string name; private readonly List loans = new List(); public Member(string id, string name) { this.id = id; this.name = name; } public void Update(LibraryItem item) { Console.WriteLine($"NOTIFICATION for {name}: The book '{item.GetTitle()}' you placed a hold on is now available!"); } public void AddLoan(Loan loan) { loans.Add(loan); } public void RemoveLoan(Loan loan) { loans.Remove(loan); } public string GetId() { return id; } public string GetName() { return name; } public List GetLoans() { return loans; } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Models/TransactionService.cs ================================================ class TransactionService { private static readonly TransactionService instance = new TransactionService(); private readonly Dictionary activeLoans = new Dictionary(); private TransactionService() { } public static TransactionService GetInstance() { return instance; } public void CreateLoan(BookCopy copy, Member member) { if (activeLoans.ContainsKey(copy.GetId())) { throw new InvalidOperationException("This copy is already on loan."); } var loan = new Loan(copy, member); activeLoans[copy.GetId()] = loan; member.AddLoan(loan); } public void EndLoan(BookCopy copy) { if (activeLoans.TryGetValue(copy.GetId(), out var loan)) { activeLoans.Remove(copy.GetId()); loan.GetMember().RemoveLoan(loan); } } } ================================================ FILE: solutions/csharp/librarymanagementsystem/README.md ================================================ # Designing a Library Management System ## Requirements 1. The library management system should allow librarians to manage books, members, and borrowing activities. 2. The system should support adding, updating, and removing books from the library catalog. 3. Each book should have details such as title, author, ISBN, publication year, and availability status. 4. The system should allow members to borrow and return books. 5. Each member should have details such as name, member ID, contact information, and borrowing history. 6. The system should enforce borrowing rules, such as a maximum number of books that can be borrowed at a time and loan duration. 7. The system should handle concurrent access to the library catalog and member records. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Book** class represents a book in the library catalog, with properties such as ISBN, title, author, publication year, and availability status. 2. The **Member** class represents a library member, with properties like member ID, name, contact information, and a list of borrowed books. 3. The **LibraryManager** class is the core of the library management system and follows the Singleton pattern to ensure a single instance of the library manager. 4. The LibraryManager class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to the library catalog and member records. 5. The LibraryManager class provides methods for adding and removing books, registering and unregistering members, borrowing and returning books, and searching for books based on keywords. 6. The **LibraryManagementSystemDemo** class serves as the entry point of the application and demonstrates the usage of the library management system. ================================================ FILE: solutions/csharp/librarymanagementsystem/States/AvailableState.cs ================================================ class AvailableState : IItemState { public void Checkout(BookCopy copy, Member member) { TransactionService.GetInstance().CreateLoan(copy, member); copy.SetState(new CheckedOutState()); Console.WriteLine($"{copy.GetId()} checked out by {member.GetName()}"); } public void ReturnItem(BookCopy copy) { Console.WriteLine("Cannot return an item that is already available."); } public void PlaceHold(BookCopy copy, Member member) { Console.WriteLine("Cannot place hold on an available item. Please check it out."); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/States/CheckedOutState.cs ================================================ class CheckedOutState : IItemState { public void Checkout(BookCopy copy, Member member) { Console.WriteLine($"{copy.GetId()} is already checked out."); } public void ReturnItem(BookCopy copy) { TransactionService.GetInstance().EndLoan(copy); Console.WriteLine($"{copy.GetId()} returned."); if (copy.GetItem().HasObservers()) { copy.SetState(new OnHoldState()); copy.GetItem().NotifyObservers(); } else { copy.SetState(new AvailableState()); } } public void PlaceHold(BookCopy copy, Member member) { copy.GetItem().AddObserver(member); Console.WriteLine($"{member.GetName()} placed a hold on '{copy.GetItem().GetTitle()}'"); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/States/IItemState.cs ================================================ interface IItemState { void Checkout(BookCopy copy, Member member); void ReturnItem(BookCopy copy); void PlaceHold(BookCopy copy, Member member); } ================================================ FILE: solutions/csharp/librarymanagementsystem/States/OnHoldState.cs ================================================ class OnHoldState : IItemState { public void Checkout(BookCopy copy, Member member) { if (copy.GetItem().IsObserver(member)) { TransactionService.GetInstance().CreateLoan(copy, member); copy.GetItem().RemoveObserver(member); copy.SetState(new CheckedOutState()); Console.WriteLine($"Hold fulfilled. {copy.GetId()} checked out by {member.GetName()}"); } else { Console.WriteLine("This item is on hold for another member."); } } public void ReturnItem(BookCopy copy) { Console.WriteLine("Invalid action. Item is on hold, not checked out."); } public void PlaceHold(BookCopy copy, Member member) { Console.WriteLine("Item is already on hold."); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Strategy/ISearchStrategy.cs ================================================ interface ISearchStrategy { List Search(string query, List items); } ================================================ FILE: solutions/csharp/librarymanagementsystem/Strategy/SearchByAuthorStrategy.cs ================================================ class SearchByAuthorStrategy : ISearchStrategy { public List Search(string query, List items) { return items.Where(item => item.GetAuthorOrPublisher().ToLower().Contains(query.ToLower())).ToList(); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/Strategy/SearchByTitleStrategy.cs ================================================ class SearchByTitleStrategy : ISearchStrategy { public List Search(string query, List items) { return items.Where(item => item.GetTitle().ToLower().Contains(query.ToLower())).ToList(); } } ================================================ FILE: solutions/csharp/librarymanagementsystem/librarymanagementsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/linkedIn/Enums/ConnectionStatus.cs ================================================ enum ConnectionStatus { PENDING, ACCEPTED, REJECTED, WITHDRAWN } ================================================ FILE: solutions/csharp/linkedIn/Enums/NotificationType.cs ================================================ enum NotificationType { CONNECTION_REQUEST, POST_LIKE, POST_COMMENT } ================================================ FILE: solutions/csharp/linkedIn/LinkedInDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class LinkedInDemo { public static void Main(string[] args) { var system = LinkedInSystem.GetInstance(); // 1. Create Members using the Builder Pattern Console.WriteLine("--- 1. Member Registration ---"); var alice = new MemberBuilder("Alice", "alice@example.com") .WithSummary("Senior Software Engineer with 10 years of experience.") .AddExperience(new Experience("Sr. Software Engineer", "Google", "2018-01-01", null)) .AddExperience(new Experience("Software Engineer", "Microsoft", "2014-06-01", "2017-12-31")) .AddEducation(new Education("Princeton University", "M.S. in Computer Science", 2012, 2014)) .Build(); var bob = new MemberBuilder("Bob", "bob@example.com") .WithSummary("Product Manager at Stripe.") .AddExperience(new Experience("Product Manager", "Stripe", "2020-02-01", null)) .AddEducation(new Education("MIT", "B.S. in Business Analytics", 2015, 2019)) .Build(); var charlie = new MemberBuilder("Charlie", "charlie@example.com").Build(); system.RegisterMember(alice); system.RegisterMember(bob); system.RegisterMember(charlie); alice.DisplayProfile(); // 2. Connection Management Console.WriteLine("\n--- 2. Connection Management ---"); string requestId1 = system.SendConnectionRequest(alice, bob); string requestId2 = system.SendConnectionRequest(alice, charlie); bob.ViewNotifications(); Console.WriteLine("\nBob accepts Alice's request."); system.AcceptConnectionRequest(requestId1); Console.WriteLine("Alice and Bob are now connected."); // 3. Posting and News Feed Console.WriteLine("\n--- 3. Posting & News Feed ---"); bob.DisplayProfile(); system.CreatePost(bob.GetId(), "Excited to share we've launched our new feature! #productmanagement"); system.ViewNewsFeed(alice.GetId()); system.ViewNewsFeed(charlie.GetId()); // 4. Interacting with a Post Console.WriteLine("\n--- 4. Post Interaction & Notifications ---"); var bobsPost = system.GetLatestPostByMember(bob.GetId()); if (bobsPost != null) { bobsPost.AddLike(alice); bobsPost.AddComment(alice, "This looks amazing! Great work!"); } bob.ViewNotifications(); // 5. Searching for Members Console.WriteLine("\n--- 5. Member Search ---"); var searchResults = system.SearchMemberByName("ali"); Console.WriteLine("Search results for 'ali':"); foreach (var member in searchResults) { Console.WriteLine($" - {member.GetName()}"); } } } ================================================ FILE: solutions/csharp/linkedIn/LinkedInSystem.cs ================================================ class LinkedInSystem { private static volatile LinkedInSystem instance; private static readonly object syncRoot = new object(); private readonly Dictionary members = new Dictionary(); private readonly ConnectionService connectionService; private readonly NewsFeedService newsFeedService; private readonly SearchService searchService; private LinkedInSystem() { connectionService = new ConnectionService(new NotificationService()); newsFeedService = new NewsFeedService(); searchService = new SearchService(members.Values); } public static LinkedInSystem GetInstance() { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new LinkedInSystem(); } } } return instance; } public void RegisterMember(Member member) { members[member.GetId()] = member; Console.WriteLine($"New member registered: {member.GetName()}"); } public Member GetMember(string name) { return members.Values.FirstOrDefault(m => m.GetName() == name); } public string SendConnectionRequest(Member from, Member to) { return connectionService.SendRequest(from, to); } public void AcceptConnectionRequest(string requestId) { connectionService.AcceptRequest(requestId); } public void CreatePost(string memberId, string content) { var author = members[memberId]; var post = new Post(author, content); newsFeedService.AddPost(author, post); Console.WriteLine($"{author.GetName()} created a new post."); } public Post GetLatestPostByMember(string memberId) { var memberPosts = newsFeedService.GetMemberPosts(members[memberId]); return memberPosts.LastOrDefault(); } public void ViewNewsFeed(string memberId) { var member = members[memberId]; Console.WriteLine($"\n--- News Feed for {member.GetName()} ---"); newsFeedService.DisplayFeedForMember(member, new ChronologicalSortStrategy()); } public List SearchMemberByName(string name) { return searchService.SearchByName(name); } } ================================================ FILE: solutions/csharp/linkedIn/Models/Comment.cs ================================================ class Comment { private readonly Member author; private readonly string text; private readonly DateTime createdAt; public Comment(Member author, string text) { this.author = author; this.text = text; this.createdAt = DateTime.Now; } public Member GetAuthor() { return author; } public string GetText() { return text; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Connection.cs ================================================ class Connection { private readonly Member fromMember; private readonly Member toMember; private ConnectionStatus status; private readonly DateTime requestedAt; private DateTime acceptedAt; public Connection(Member fromMember, Member toMember) { this.fromMember = fromMember; this.toMember = toMember; this.status = ConnectionStatus.PENDING; this.requestedAt = DateTime.Now; } public Member GetFromMember() { return fromMember; } public Member GetToMember() { return toMember; } public ConnectionStatus GetStatus() { return status; } public void SetStatus(ConnectionStatus status) { this.status = status; if (status == ConnectionStatus.ACCEPTED) { this.acceptedAt = DateTime.Now; } } } ================================================ FILE: solutions/csharp/linkedIn/Models/Education.cs ================================================ class Education { private readonly string school; private readonly string degree; private readonly int startYear; private readonly int endYear; public Education(string school, string degree, int startYear, int endYear) { this.school = school; this.degree = degree; this.startYear = startYear; this.endYear = endYear; } public override string ToString() { return $"{degree}, {school} ({startYear} - {endYear})"; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Experience.cs ================================================ class Experience { private readonly string title; private readonly string company; private readonly string startDate; private readonly string endDate; // null for current job public Experience(string title, string company, string startDate, string endDate) { this.title = title; this.company = company; this.startDate = startDate; this.endDate = endDate; } public override string ToString() { string end = string.IsNullOrEmpty(endDate) ? "Present" : endDate; return $"{title} at {company} ({startDate} to {end})"; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Like.cs ================================================ class Like { private readonly Member member; private readonly DateTime createdAt; public Like(Member member) { this.member = member; this.createdAt = DateTime.Now; } public Member GetMember() { return member; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Member.cs ================================================ class Member : INotificationObserver { private readonly string id; private readonly string name; private readonly string email; private readonly Profile profile; private readonly HashSet connections = new HashSet(); private readonly List notifications = new List(); public Member(string id, string name, string email, Profile profile) { this.id = id; this.name = name; this.email = email; this.profile = profile; } public string GetId() { return id; } public string GetName() { return name; } public string GetEmail() { return email; } public HashSet GetConnections() { return connections; } public Profile GetProfile() { return profile; } public void AddConnection(Member member) { connections.Add(member); } public void DisplayProfile() { Console.WriteLine($"\n--- Profile for {name} ({email}) ---"); profile.Display(); Console.WriteLine($" Connections: {connections.Count}"); } public void ViewNotifications() { Console.WriteLine($"\n--- Notifications for {name} ---"); var unreadNotifications = notifications.Where(n => !n.IsRead()).ToList(); if (!unreadNotifications.Any()) { Console.WriteLine(" No new notifications."); return; } foreach (var notification in unreadNotifications) { Console.WriteLine($" - {notification.GetContent()}"); notification.MarkAsRead(); } } public void Update(Notification notification) { notifications.Add(notification); Console.WriteLine($"Notification pushed to {name}: {notification.GetContent()}"); } } class MemberBuilder { private readonly string id; private readonly string name; private readonly string email; private readonly Profile profile = new Profile(); public MemberBuilder(string name, string email) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; } public MemberBuilder WithSummary(string summary) { profile.SetSummary(summary); return this; } public MemberBuilder AddExperience(Experience experience) { profile.AddExperience(experience); return this; } public MemberBuilder AddEducation(Education education) { profile.AddEducation(education); return this; } public Member Build() { return new Member(id, name, email, profile); } } ================================================ FILE: solutions/csharp/linkedIn/Models/NewsFeed.cs ================================================ class NewsFeed { private readonly List posts; public NewsFeed(List posts) { this.posts = posts; } public void Display(IFeedSortingStrategy strategy) { var sortedPosts = strategy.Sort(posts); if (!sortedPosts.Any()) { Console.WriteLine(" Your news feed is empty."); return; } foreach (var post in sortedPosts) { Console.WriteLine("----------------------------------------"); Console.WriteLine($"Post by: {post.GetAuthor().GetName()} (at {post.GetCreatedAt().ToShortDateString()})"); Console.WriteLine($"Content: {post.GetContent()}"); Console.WriteLine($"Likes: {post.GetLikes().Count}, Comments: {post.GetComments().Count}"); Console.WriteLine("----------------------------------------"); } } } ================================================ FILE: solutions/csharp/linkedIn/Models/Notification.cs ================================================ class Notification { private readonly string id; private readonly string memberId; private readonly NotificationType type; private readonly string content; private readonly DateTime createdAt; private bool isRead = false; public Notification(string memberId, NotificationType type, string content) { this.id = Guid.NewGuid().ToString(); this.memberId = memberId; this.type = type; this.content = content; this.createdAt = DateTime.Now; } public string GetContent() { return content; } public void MarkAsRead() { isRead = true; } public bool IsRead() { return isRead; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Post.cs ================================================ class Post : Subject { private readonly string id; private readonly Member author; private readonly string content; private readonly DateTime createdAt; private readonly List likes = new List(); private readonly List comments = new List(); public Post(Member author, string content) { this.id = Guid.NewGuid().ToString(); this.author = author; this.content = content; this.createdAt = DateTime.Now; AddObserver(author); } public void AddLike(Member member) { likes.Add(new Like(member)); string notificationContent = $"{member.GetName()} liked your post."; var notification = new Notification(author.GetId(), NotificationType.POST_LIKE, notificationContent); NotifyObservers(notification); } public void AddComment(Member member, string text) { comments.Add(new Comment(member, text)); string notificationContent = $"{member.GetName()} commented on your post: \"{text}\""; var notification = new Notification(author.GetId(), NotificationType.POST_COMMENT, notificationContent); NotifyObservers(notification); } public string GetId() { return id; } public Member GetAuthor() { return author; } public string GetContent() { return content; } public DateTime GetCreatedAt() { return createdAt; } public List GetLikes() { return likes; } public List GetComments() { return comments; } } ================================================ FILE: solutions/csharp/linkedIn/Models/Profile.cs ================================================ class Profile { private string summary; private readonly List experiences = new List(); private readonly List educations = new List(); public void SetSummary(string summary) { this.summary = summary; } public void AddExperience(Experience experience) { experiences.Add(experience); } public void AddEducation(Education education) { educations.Add(education); } public void Display() { Console.WriteLine($" Summary: {(summary ?? "N/A")}"); Console.WriteLine(" Experience:"); if (!experiences.Any()) { Console.WriteLine(" - None"); } else { foreach (var exp in experiences) { Console.WriteLine($" - {exp}"); } } Console.WriteLine(" Education:"); if (!educations.Any()) { Console.WriteLine(" - None"); } else { foreach (var edu in educations) { Console.WriteLine($" - {edu}"); } } } } ================================================ FILE: solutions/csharp/linkedIn/Observer/INotificationObserver.cs ================================================ interface INotificationObserver { void Update(Notification notification); } ================================================ FILE: solutions/csharp/linkedIn/Observer/Subject.cs ================================================ abstract class Subject { private readonly List observers = new List(); public void AddObserver(INotificationObserver observer) { observers.Add(observer); } public void RemoveObserver(INotificationObserver observer) { observers.Remove(observer); } public void NotifyObservers(Notification notification) { foreach (var observer in observers) { observer.Update(notification); } } } ================================================ FILE: solutions/csharp/linkedIn/README.md ================================================ # Designing a Professional Networking Platform like LinkedIn ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their professional information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their professional information, such as profile picture, headline, summary, experience, education, and skills. - Users should be able to update their profile information. #### Connections: - Users should be able to send connection requests to other users. - Users should be able to accept or decline connection requests. - Users should be able to view their list of connections. #### Messaging: - Users should be able to send messages to their connections. - Users should be able to view their inbox and sent messages. #### Job Postings: - Employers should be able to post job listings with details such as title, description, requirements, and location. - Users should be able to view and apply for job postings. #### Search Functionality: - Users should be able to search for other users, companies, and job postings based on relevant criteria. - Search results should be ranked based on relevance and user preferences. #### Notifications: - Users should receive notifications for events such as connection requests, messages, and job postings. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the LinkedIn system, containing properties such as ID, name, email, password, profile, connections, inbox, and sent messages. 2. The **Profile** class represents a user's profile, containing properties such as profile picture, headline, summary, experiences, educations, and skills. 3. The **Experience**, **Education**, and **Skill** classes represent different components of a user's profile. 4. The **Connection** class represents a connection between two users, containing the user and the connection date. 5. The **Message** class represents a message sent between users, containing properties such as ID, sender, receiver, content, and timestamp. 6. The **JobPosting** class represents a job listing posted by an employer, containing properties such as ID, title, description, requirements, location, and post date. 7. The **Notification** class represents a notification generated for a user, containing properties such as ID, user, notification type, content, and timestamp. 8. The **NotificationType** enum defines the different types of notifications, such as connection request, message, and job posting. 9. The **LinkedInService** class is the main class that manages the LinkedIn system. It follows the Singleton pattern to ensure only one instance of the service exists. 10. The **LinkedInService** class provides methods for user registration, login, profile updates, connection requests, job postings, user and job search, messaging, and notifications. 11. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 12. The **LinkedInDemo** class demonstrates the usage of the LinkedIn system by registering users, logging in, updating profiles, sending connection requests, posting job listings, searching for users and jobs, sending messages, and retrieving notifications. ================================================ FILE: solutions/csharp/linkedIn/Services/ConnectionService.cs ================================================ class ConnectionService { private readonly NotificationService notificationService; private readonly Dictionary connectionRequests = new Dictionary(); private readonly object lockObj = new object(); public ConnectionService(NotificationService notificationService) { this.notificationService = notificationService; } public string SendRequest(Member from, Member to) { var connection = new Connection(from, to); string requestId = Guid.NewGuid().ToString(); lock (lockObj) { connectionRequests[requestId] = connection; } Console.WriteLine($"{from.GetName()} sent a connection request to {to.GetName()}."); var notification = new Notification( to.GetId(), NotificationType.CONNECTION_REQUEST, $"{from.GetName()} wants to connect with you. Request ID: {requestId}" ); notificationService.SendNotification(to, notification); return requestId; } public void AcceptRequest(string requestId) { lock (lockObj) { if (connectionRequests.TryGetValue(requestId, out var request) && request.GetStatus() == ConnectionStatus.PENDING) { request.SetStatus(ConnectionStatus.ACCEPTED); var from = request.GetFromMember(); var to = request.GetToMember(); from.AddConnection(to); to.AddConnection(from); Console.WriteLine($"{to.GetName()} accepted the connection request from {from.GetName()}."); connectionRequests.Remove(requestId); } else { Console.WriteLine("Invalid or already handled request ID."); } } } } ================================================ FILE: solutions/csharp/linkedIn/Services/NewsFeedService.cs ================================================ class NewsFeedService { private readonly Dictionary> allPosts = new Dictionary>(); private readonly object lockObj = new object(); public void AddPost(Member member, Post post) { lock (lockObj) { if (!allPosts.ContainsKey(member.GetId())) { allPosts[member.GetId()] = new List(); } allPosts[member.GetId()].Add(post); } } public List GetMemberPosts(Member member) { lock (lockObj) { return allPosts.TryGetValue(member.GetId(), out var posts) ? posts : new List(); } } public void DisplayFeedForMember(Member member, IFeedSortingStrategy feedSortingStrategy) { var feedPosts = new List(); foreach (var connection in member.GetConnections()) { var connectionPosts = GetMemberPosts(connection); feedPosts.AddRange(connectionPosts); } var feed = new NewsFeed(feedPosts); feed.Display(feedSortingStrategy); } } ================================================ FILE: solutions/csharp/linkedIn/Services/NotificationService.cs ================================================ class NotificationService { public void SendNotification(Member member, Notification notification) { member.Update(notification); } } ================================================ FILE: solutions/csharp/linkedIn/Services/SearchService.cs ================================================ class SearchService { private readonly ICollection members; public SearchService(ICollection members) { this.members = members; } public List SearchByName(string name) { return members .Where(member => member.GetName().ToLower().Contains(name.ToLower())) .ToList(); } } ================================================ FILE: solutions/csharp/linkedIn/Strategy/ChronologicalSortStrategy.cs ================================================ class ChronologicalSortStrategy : IFeedSortingStrategy { public List Sort(List posts) { return posts.OrderByDescending(post => post.GetCreatedAt()).ToList(); } } ================================================ FILE: solutions/csharp/linkedIn/Strategy/IFeedSortingStrategy.cs ================================================ interface IFeedSortingStrategy { List Sort(List posts); } ================================================ FILE: solutions/csharp/linkedIn/linkedIn.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/loggingframework/Appenders/ConsoleAppender.cs ================================================ class ConsoleAppender : ILogAppender { private ILogFormatter formatter; public ConsoleAppender() { this.formatter = new SimpleTextFormatter(); } public void Append(LogMessage logMessage) { Console.Write(formatter.Format(logMessage)); } public void Close() { } public void SetFormatter(ILogFormatter formatter) { this.formatter = formatter; } public ILogFormatter GetFormatter() { return formatter; } } ================================================ FILE: solutions/csharp/loggingframework/Appenders/FileAppender.cs ================================================ class FileAppender : ILogAppender { private StreamWriter writer; private ILogFormatter formatter; private readonly object fileLock = new object(); public FileAppender(string filePath) { this.formatter = new SimpleTextFormatter(); try { this.writer = new StreamWriter(filePath, true); } catch (Exception e) { Console.WriteLine($"Failed to create writer for file logs, exception: {e.Message}"); this.writer = null; } } public void Append(LogMessage logMessage) { lock (fileLock) { if (writer != null) { try { writer.Write(formatter.Format(logMessage) + "\n"); writer.Flush(); } catch (Exception e) { Console.WriteLine($"Failed to write logs to file, exception: {e.Message}"); } } } } public void Close() { if (writer != null) { try { writer.Close(); } catch (Exception e) { Console.WriteLine($"Failed to close logs file, exception: {e.Message}"); } } } public void SetFormatter(ILogFormatter formatter) { this.formatter = formatter; } public ILogFormatter GetFormatter() { return formatter; } } ================================================ FILE: solutions/csharp/loggingframework/Appenders/ILogAppender.cs ================================================ interface ILogAppender { void Append(LogMessage logMessage); void Close(); ILogFormatter GetFormatter(); void SetFormatter(ILogFormatter formatter); } ================================================ FILE: solutions/csharp/loggingframework/AsyncLogProcessor.cs ================================================ using System.Collections.Concurrent; class AsyncLogProcessor { private readonly ConcurrentQueue taskQueue = new ConcurrentQueue(); private readonly AutoResetEvent signal = new AutoResetEvent(false); private volatile bool shutdownFlag = false; private readonly Thread workerThread; public AsyncLogProcessor() { workerThread = new Thread(WorkerLoop) { Name = "AsyncLogProcessor", IsBackground = true }; workerThread.Start(); } private void WorkerLoop() { while (!shutdownFlag) { signal.WaitOne(); while (taskQueue.TryDequeue(out Action task)) { try { task(); } catch (Exception e) { Console.WriteLine($"Error processing log task: {e.Message}"); } } } } public void Process(LogMessage logMessage, List appenders) { if (shutdownFlag) { Console.Error.WriteLine("Logger is shut down. Cannot process log message."); return; } taskQueue.Enqueue(() => { foreach (var appender in appenders) { appender.Append(logMessage); } }); signal.Set(); } public void Stop() { shutdownFlag = true; signal.Set(); if (!workerThread.Join(TimeSpan.FromSeconds(2))) { Console.Error.WriteLine("Logger executor did not terminate in the specified time."); workerThread.Abort(); } } } ================================================ FILE: solutions/csharp/loggingframework/Enum/LogLevel.cs ================================================ enum LogLevel { DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4, FATAL = 5 } static class LogLevelExtensions { public static bool IsGreaterOrEqual(this LogLevel level, LogLevel other) { return (int)level >= (int)other; } } ================================================ FILE: solutions/csharp/loggingframework/Formatters/ILogFormatter.cs ================================================ interface ILogFormatter { string Format(LogMessage logMessage); } ================================================ FILE: solutions/csharp/loggingframework/Formatters/SimpleTextFormatter.cs ================================================ class SimpleTextFormatter : ILogFormatter { public string Format(LogMessage logMessage) { return $"{logMessage.GetTimestamp():yyyy-MM-dd HH:mm:ss.fff} [{logMessage.GetThreadName()}] {logMessage.GetLevel()} - {logMessage.GetLoggerName()}: {logMessage.GetMessage()}\n"; } } ================================================ FILE: solutions/csharp/loggingframework/LogManager.cs ================================================ using System.Collections.Concurrent; class LogManager { private static volatile LogManager instance; private static readonly object lockObject = new object(); private readonly ConcurrentDictionary loggers = new ConcurrentDictionary(); private readonly Logger rootLogger; private readonly AsyncLogProcessor processor; private LogManager() { this.rootLogger = new Logger("root", null); this.loggers.TryAdd("root", rootLogger); this.processor = new AsyncLogProcessor(); } public static LogManager GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) instance = new LogManager(); } } return instance; } public Logger GetLogger(string name) { return loggers.GetOrAdd(name, CreateLogger); } private Logger CreateLogger(string name) { if (name.Equals("root")) { return rootLogger; } int lastDot = name.LastIndexOf('.'); string parentName = (lastDot == -1) ? "root" : name.Substring(0, lastDot); Logger parent = GetLogger(parentName); return new Logger(name, parent); } public Logger GetRootLogger() { return rootLogger; } public AsyncLogProcessor GetProcessor() { return processor; } public void Shutdown() { // Stop the processor first to ensure all logs are written processor.Stop(); // Then, close all appenders var allAppenders = loggers.Values .SelectMany(logger => logger.GetAppenders()) .Distinct() .ToList(); foreach (var appender in allAppenders) { appender.Close(); } Console.WriteLine("Logging framework shut down gracefully."); } } ================================================ FILE: solutions/csharp/loggingframework/Logger.cs ================================================ class Logger { private readonly string name; private LogLevel? level; private readonly Logger parent; private readonly List appenders; private bool additivity = true; public Logger(string name, Logger parent) { this.name = name; this.parent = parent; this.appenders = new List(); } public void AddAppender(ILogAppender appender) { appenders.Add(appender); } public List GetAppenders() { return new List(appenders); } public void SetLevel(LogLevel minLevel) { this.level = minLevel; } public void SetAdditivity(bool additivity) { this.additivity = additivity; } public LogLevel GetEffectiveLevel() { for (Logger logger = this; logger != null; logger = logger.parent) { LogLevel? currentLevel = logger.level; if (currentLevel.HasValue) { return currentLevel.Value; } } return LogLevel.DEBUG; // Default root level } public void Log(LogLevel messageLevel, string message) { if (messageLevel.IsGreaterOrEqual(GetEffectiveLevel())) { LogMessage logMessage = new LogMessage(messageLevel, this.name, message); CallAppenders(logMessage); } } private void CallAppenders(LogMessage logMessage) { if (appenders.Count > 0) { LogManager.GetInstance().GetProcessor().Process(logMessage, this.appenders); } if (additivity && parent != null) { parent.CallAppenders(logMessage); } } public void Debug(string message) { Log(LogLevel.DEBUG, message); } public void Info(string message) { Log(LogLevel.INFO, message); } public void Warn(string message) { Log(LogLevel.WARN, message); } public void Error(string message) { Log(LogLevel.ERROR, message); } public void Fatal(string message) { Log(LogLevel.FATAL, message); } } ================================================ FILE: solutions/csharp/loggingframework/LoggingFrameworkDemo.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Linq; public class LoggingFrameworkDemo { public static void Main(string[] args) { // --- 1. Initial Configuration --- LogManager logManager = LogManager.GetInstance(); Logger rootLogger = logManager.GetRootLogger(); rootLogger.SetLevel(LogLevel.INFO); // Set global minimum level to INFO // Add a console appender to the root logger rootLogger.AddAppender(new ConsoleAppender()); Console.WriteLine("--- Initial Logging Demo ---"); Logger mainLogger = logManager.GetLogger("com.example.Main"); mainLogger.Info("Application starting up."); mainLogger.Debug("This is a debug message, it should NOT appear."); // Below root level mainLogger.Warn("This is a warning message."); // --- 2. Hierarchy and Additivity Demo --- Console.WriteLine("\n--- Logger Hierarchy Demo ---"); Logger dbLogger = logManager.GetLogger("com.example.db"); // dbLogger inherits level and appenders from root dbLogger.Info("Database connection pool initializing."); // Let's create a more specific logger and override its level Logger serviceLogger = logManager.GetLogger("com.example.service.UserService"); serviceLogger.SetLevel(LogLevel.DEBUG); // More verbose logging for this specific service serviceLogger.Info("User service starting."); serviceLogger.Debug("This debug message SHOULD now appear for the service logger."); // --- 3. Dynamic Configuration Change --- Console.WriteLine("\n--- Dynamic Configuration Demo ---"); Console.WriteLine("Changing root log level to DEBUG..."); rootLogger.SetLevel(LogLevel.DEBUG); mainLogger.Debug("This debug message should now be visible."); try { Thread.Sleep(500); logManager.Shutdown(); } catch (Exception e) { Console.WriteLine("Caught exception"); } } } ================================================ FILE: solutions/csharp/loggingframework/Models/LogMessage.cs ================================================ class LogMessage { private readonly DateTime timestamp; private readonly LogLevel level; private readonly string loggerName; private readonly string threadName; private readonly string message; public LogMessage(LogLevel level, string loggerName, string message) { this.timestamp = DateTime.Now; this.level = level; this.loggerName = loggerName; this.message = message; this.threadName = Thread.CurrentThread.Name ?? Thread.CurrentThread.ManagedThreadId.ToString(); } public DateTime GetTimestamp() { return timestamp; } public LogLevel GetLevel() { return level; } public string GetLoggerName() { return loggerName; } public string GetThreadName() { return threadName; } public string GetMessage() { return message; } } ================================================ FILE: solutions/csharp/loggingframework/README.md ================================================ # Designing a Logging Framework ## Requirements 1. The logging framework should support different log levels, such as DEBUG, INFO, WARNING, ERROR, and FATAL. 2. It should allow logging messages with a timestamp, log level, and message content. 3. The framework should support multiple output destinations, such as console, file, and database. 4. It should provide a configuration mechanism to set the log level and output destination. 5. The logging framework should be thread-safe to handle concurrent logging from multiple threads. 6. It should be extensible to accommodate new log levels and output destinations in the future. ## Classes, Interfaces and Enumerations 1. The **LogLevel** enum defines the different log levels supported by the logging framework. 2. The **LogMessage** class represents a log message with a timestamp, log level, and message content. 3. The **LogAppender** interface defines the contract for appending log messages to different output destinations. 4. The **ConsoleAppender**, **FileAppender**, and **DatabaseAppender** classes are concrete implementations of the LogAppender interface, supporting logging to the console, file, and database, respectively. 5. The **LoggerConfig** class holds the configuration settings for the logger, including the log level and the selected log appender. 6. The **Logger** class is a singleton that provides the main logging functionality. It allows setting the configuration, logging messages at different levels, and provides convenience methods for each log level. 7. The **LoggingExample** class demonstrates the usage of the logging framework, showcasing different log levels, changing the configuration, and logging from multiple threads. ================================================ FILE: solutions/csharp/loggingframework/loggingframework.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/lrucache/DoublyLinkedList.cs ================================================ class DoublyLinkedList { private readonly Node head; private readonly Node tail; public DoublyLinkedList() { head = new Node(default(K), default(V)); tail = new Node(default(K), default(V)); head.next = tail; tail.prev = head; } public void AddFirst(Node node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } public void Remove(Node node) { node.prev.next = node.next; node.next.prev = node.prev; } public void MoveToFront(Node node) { Remove(node); AddFirst(node); } public Node RemoveLast() { if (tail.prev == head) return null; Node last = tail.prev; Remove(last); return last; } } ================================================ FILE: solutions/csharp/lrucache/LRUCache.cs ================================================ class LRUCache { private readonly int capacity; private readonly Dictionary> map; private readonly DoublyLinkedList dll; private readonly object lockObject = new object(); public LRUCache(int capacity) { this.capacity = capacity; this.map = new Dictionary>(); this.dll = new DoublyLinkedList(); } public V Get(K key) { lock (lockObject) { if (!map.ContainsKey(key)) return default(V); Node node = map[key]; dll.MoveToFront(node); return node.value; } } public void Put(K key, V value) { lock (lockObject) { if (map.ContainsKey(key)) { Node node = map[key]; node.value = value; dll.MoveToFront(node); } else { if (map.Count == capacity) { Node lru = dll.RemoveLast(); if (lru != null) map.Remove(lru.key); } Node newNode = new Node(key, value); dll.AddFirst(newNode); map[key] = newNode; } } } public void Remove(K key) { lock (lockObject) { if (!map.ContainsKey(key)) return; Node node = map[key]; dll.Remove(node); map.Remove(key); } } } ================================================ FILE: solutions/csharp/lrucache/LRUCacheDemo.cs ================================================ using System; using System.Collections.Generic; public class LRUCacheDemo { public static void Main() { LRUCache cache = new LRUCache(3); cache.Put("a", 1); cache.Put("b", 2); cache.Put("c", 3); Console.WriteLine(cache.Get("a")); // 1 cache.Put("d", 4); Console.WriteLine(cache.Get("b")); // 0 (default for int when null) } } ================================================ FILE: solutions/csharp/lrucache/Node.cs ================================================ class Node { public K key; public V value; public Node prev; public Node next; public Node(K key, V value) { this.key = key; this.value = value; } } ================================================ FILE: solutions/csharp/lrucache/README.md ================================================ # Designing a LRU Cache ## Requirements 1. The LRU cache should support the following operations: - put(key, value): Insert a key-value pair into the cache. If the cache is at capacity, remove the least recently used item before inserting the new item. - get(key): Get the value associated with the given key. If the key exists in the cache, move it to the front of the cache (most recently used) and return its value. If the key does not exist, return -1. 2. The cache should have a fixed capacity, specified during initialization. 3. The cache should be thread-safe, allowing concurrent access from multiple threads. 4. The cache should be efficient in terms of time complexity for both put and get operations, ideally O(1). ## Classes, Interfaces and Enumerations 1. The **Node** class represents a node in the doubly linked list, containing the key, value, and references to the previous and next nodes. 2. The **LRUCache** class implements the LRU cache functionality using a combination of a hash map (cache) and a doubly linked list (head and tail). 3. The get method retrieves the value associated with a given key. If the key exists in the cache, it is moved to the head of the linked list (most recently used) and its value is returned. If the key does not exist, null is returned. 4. The put method inserts a key-value pair into the cache. If the key already exists, its value is updated, and the node is moved to the head of the linked list. If the key does not exist and the cache is at capacity, the least recently used item (at the tail of the linked list) is removed, and the new item is inserted at the head. 5. The addToHead, removeNode, moveToHead, and removeTail methods are helper methods to manipulate the doubly linked list. 6. The synchronized keyword is used on the get and put methods to ensure thread safety, allowing concurrent access from multiple threads. 7. The **LRUCacheDemo** class demonstrates the usage of the LRU cache by creating an instance of LRUCache with a capacity of 3, performing various put and get operations, and printing the results. ================================================ FILE: solutions/csharp/lrucache/lrucache.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/movieticketbookingsystem/BookingManager.cs ================================================ class BookingManager { private readonly SeatLockManager seatLockManager; public BookingManager(SeatLockManager seatLockManager) { this.seatLockManager = seatLockManager; } public Booking CreateBooking(User user, Show show, List seats, IPaymentStrategy paymentStrategy) { // 1. Lock the seats seatLockManager.LockSeats(show, seats, user.GetId()); // 2. Calculate the total price double totalAmount = show.GetPricingStrategy().CalculatePrice(seats); // 3. Process Payment Payment payment = paymentStrategy.Pay(totalAmount); // 4. If payment is successful, create the booking if (payment.GetStatus() == PaymentStatus.SUCCESS) { Booking booking = new BookingBuilder() .SetUser(user) .SetShow(show) .SetSeats(seats) .SetTotalAmount(totalAmount) .SetPayment(payment) .Build(); // 5. Confirm the booking (mark seats as BOOKED) booking.ConfirmBooking(); // Clean up the lock map seatLockManager.UnlockSeats(show, seats, user.GetId()); return booking; } else { Console.WriteLine("Payment failed. Please try again."); return null; } } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Enums/PaymentStatus.cs ================================================ enum PaymentStatus { SUCCESS, FAILURE, PENDING } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Enums/SeatStatus.cs ================================================ enum SeatStatus { AVAILABLE, BOOKED, LOCKED // Temporarily held during booking process } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Enums/SeatType.cs ================================================ enum SeatType { REGULAR, PREMIUM, RECLINER } static class SeatTypeExtensions { public static double GetPrice(this SeatType seatType) { switch (seatType) { case SeatType.REGULAR: return 50.0; case SeatType.PREMIUM: return 80.0; case SeatType.RECLINER: return 120.0; default: return 50.0; } } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Booking.cs ================================================ class Booking { private readonly string id; private readonly User user; private readonly Show show; private readonly List seats; private readonly double totalAmount; private readonly Payment payment; public Booking(string id, User user, Show show, List seats, double totalAmount, Payment payment) { this.id = id; this.user = user; this.show = show; this.seats = seats; this.totalAmount = totalAmount; this.payment = payment; } public void ConfirmBooking() { foreach (var seat in seats) { seat.SetStatus(SeatStatus.BOOKED); } } public string GetId() { return id; } public User GetUser() { return user; } public Show GetShow() { return show; } public List GetSeats() { return seats; } public double GetTotalAmount() { return totalAmount; } public Payment GetPayment() { return payment; } } class BookingBuilder { private string id; private User user; private Show show; private List seats; private double totalAmount; private Payment payment; public BookingBuilder SetId(string id) { this.id = id; return this; } public BookingBuilder SetUser(User user) { this.user = user; return this; } public BookingBuilder SetShow(Show show) { this.show = show; return this; } public BookingBuilder SetSeats(List seats) { this.seats = seats; return this; } public BookingBuilder SetTotalAmount(double totalAmount) { this.totalAmount = totalAmount; return this; } public BookingBuilder SetPayment(Payment payment) { this.payment = payment; return this; } public Booking Build() { // Validations can be added here return new Booking(id ?? Guid.NewGuid().ToString(), user, show, seats, totalAmount, payment); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Cinema.cs ================================================ class Cinema { private readonly string id; private readonly string name; private readonly City city; private readonly List screens; public Cinema(string id, string name, City city, List screens) { this.id = id; this.name = name; this.city = city; this.screens = screens; } public string GetId() { return id; } public string GetName() { return name; } public City GetCity() { return city; } public List GetScreens() { return screens; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/City.cs ================================================ class City { private readonly string id; private readonly string name; public City(string id, string name) { this.id = id; this.name = name; } public string GetId() { return id; } public string GetName() { return name; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Movie.cs ================================================ class Movie : MovieSubject { private readonly string id; private readonly string title; private readonly int durationInMinutes; public Movie(string id, string title, int durationInMinutes) { this.id = id; this.title = title; this.durationInMinutes = durationInMinutes; } public string GetId() { return id; } public string GetTitle() { return title; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Payment.cs ================================================ class Payment { private readonly string id; private readonly double amount; private readonly PaymentStatus status; private readonly string transactionId; public Payment(double amount, PaymentStatus status, string transactionId) { this.id = Guid.NewGuid().ToString(); this.amount = amount; this.status = status; this.transactionId = transactionId; } public PaymentStatus GetStatus() { return status; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Screen.cs ================================================ class Screen { private readonly string id; private readonly List seats; public Screen(string id) { this.id = id; this.seats = new List(); } public void AddSeat(Seat seat) { seats.Add(seat); } public string GetId() { return id; } public List GetSeats() { return seats; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Seat.cs ================================================ class Seat { private readonly string id; private readonly int row; private readonly int col; private readonly SeatType type; private SeatStatus status; public Seat(string id, int row, int col, SeatType type) { this.id = id; this.row = row; this.col = col; this.type = type; this.status = SeatStatus.AVAILABLE; } public string GetId() { return id; } public int GetRow() { return row; } public int GetCol() { return col; } public SeatType GetSeatType() { return type; } public SeatStatus GetStatus() { return status; } public void SetStatus(SeatStatus status) { this.status = status; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/Show.cs ================================================ class Show { private readonly string id; private readonly Movie movie; private readonly Screen screen; private readonly DateTime startTime; private readonly IPricingStrategy pricingStrategy; public Show(string id, Movie movie, Screen screen, DateTime startTime, IPricingStrategy pricingStrategy) { this.id = id; this.movie = movie; this.screen = screen; this.startTime = startTime; this.pricingStrategy = pricingStrategy; } public string GetId() { return id; } public Movie GetMovie() { return movie; } public Screen GetScreen() { return screen; } public DateTime GetStartTime() { return startTime; } public IPricingStrategy GetPricingStrategy() { return pricingStrategy; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Models/User.cs ================================================ class User { private readonly string id; private readonly string name; private readonly string email; public User(string name, string email) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; } public string GetId() { return id; } public string GetName() { return name; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/MovieBookingDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class MovieBookingDemo { public static void Main(string[] args) { // Setup var service = MovieBookingService.GetInstance(); var nyc = service.AddCity("city1", "New York"); var la = service.AddCity("city2", "Los Angeles"); // 2. Add movies var matrix = new Movie("M1", "The Matrix", 120); var avengers = new Movie("M2", "Avengers: Endgame", 170); service.AddMovie(matrix); service.AddMovie(avengers); // Add Seats for a Screen var screen1 = new Screen("S1"); for (int i = 1; i <= 10; i++) { var seatType = i <= 5 ? SeatType.REGULAR : SeatType.PREMIUM; screen1.AddSeat(new Seat($"A{i}", 1, i, seatType)); screen1.AddSeat(new Seat($"B{i}", 2, i, seatType)); } // Add Cinemas var amcNYC = service.AddCinema("cinema1", "AMC Times Square", nyc.GetId(), new List { screen1 }); // Add Shows var matrixShow = service.AddShow("show1", matrix, screen1, DateTime.Now.AddHours(2), new WeekdayPricingStrategy()); var avengersShow = service.AddShow("show2", avengers, screen1, DateTime.Now.AddHours(5), new WeekdayPricingStrategy()); // --- User and Observer Setup --- var alice = service.CreateUser("Alice", "alice@example.com"); var aliceObserver = new UserObserver(alice); avengers.AddObserver(aliceObserver); // Simulate movie release Console.WriteLine("\n--- Notifying Observers about Movie Release ---"); avengers.NotifyObservers(); // --- User Story: Alice books tickets --- Console.WriteLine("\n--- Alice's Booking Flow ---"); string cityName = "New York"; string movieTitle = "Avengers: Endgame"; // 1. Search for shows var availableShows = service.FindShows(movieTitle, cityName); if (!availableShows.Any()) { Console.WriteLine($"No shows found for {movieTitle} in {cityName}"); return; } var selectedShow = availableShows[0]; // Alice selects the first show // 2. View available seats var availableSeats = selectedShow.GetScreen().GetSeats() .Where(seat => seat.GetStatus() == SeatStatus.AVAILABLE) .ToList(); Console.WriteLine($"Available seats for '{selectedShow.GetMovie().GetTitle()}' at {selectedShow.GetStartTime()}: {string.Join(", ", availableSeats.Select(s => s.GetId()))}"); // 3. Select seats var desiredSeats = new List { availableSeats[2], availableSeats[3] }; Console.WriteLine($"Alice selects seats: {string.Join(", ", desiredSeats.Select(s => s.GetId()))}"); // 4. Book Tickets var booking = service.BookTickets( alice.GetId(), selectedShow.GetId(), desiredSeats, new CreditCardPaymentStrategy("1234-5678-9876-5432", "123") ); if (booking != null) { Console.WriteLine("\n--- Booking Successful! ---"); Console.WriteLine($"Booking ID: {booking.GetId()}"); Console.WriteLine($"User: {booking.GetUser().GetName()}"); Console.WriteLine($"Movie: {booking.GetShow().GetMovie().GetTitle()}"); Console.WriteLine($"Seats: {string.Join(", ", booking.GetSeats().Select(s => s.GetId()))}"); Console.WriteLine($"Total Amount: ${booking.GetTotalAmount()}"); Console.WriteLine($"Payment Status: {booking.GetPayment().GetStatus()}"); } else { Console.WriteLine("Booking failed."); } // 5. Verify seat status after booking Console.WriteLine("\nSeat status after Alice's booking:"); foreach (var seat in desiredSeats) { Console.WriteLine($"Seat {seat.GetId()} status: {seat.GetStatus()}"); } // 6. Shut down the system to release resources like the scheduler. service.Shutdown(); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/MovieBookingService.cs ================================================ class MovieBookingService { private static volatile MovieBookingService instance; private static readonly object syncRoot = new object(); private readonly Dictionary cities; private readonly Dictionary cinemas; private readonly Dictionary movies; private readonly Dictionary users; private readonly Dictionary shows; private readonly SeatLockManager seatLockManager; private readonly BookingManager bookingManager; private MovieBookingService() { this.cities = new Dictionary(); this.cinemas = new Dictionary(); this.movies = new Dictionary(); this.users = new Dictionary(); this.shows = new Dictionary(); this.seatLockManager = new SeatLockManager(); this.bookingManager = new BookingManager(seatLockManager); } public static MovieBookingService GetInstance() { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new MovieBookingService(); } } } return instance; } public BookingManager GetBookingManager() { return bookingManager; } public City AddCity(string id, string name) { var city = new City(id, name); cities[city.GetId()] = city; return city; } public Cinema AddCinema(string id, string name, string cityId, List screens) { var city = cities[cityId]; var cinema = new Cinema(id, name, city, screens); cinemas[cinema.GetId()] = cinema; return cinema; } public void AddMovie(Movie movie) { movies[movie.GetId()] = movie; } public Show AddShow(string id, Movie movie, Screen screen, DateTime startTime, IPricingStrategy pricingStrategy) { var show = new Show(id, movie, screen, startTime, pricingStrategy); shows[show.GetId()] = show; return show; } public User CreateUser(string name, string email) { var user = new User(name, email); users[user.GetId()] = user; return user; } public Booking BookTickets(string userId, string showId, List desiredSeats, IPaymentStrategy paymentStrategy) { return bookingManager.CreateBooking( users[userId], shows[showId], desiredSeats, paymentStrategy ); } public List FindShows(string movieTitle, string cityName) { var result = new List(); foreach (var show in shows.Values) { if (show.GetMovie().GetTitle().Equals(movieTitle, StringComparison.OrdinalIgnoreCase)) { var cinema = FindCinemaForShow(show); if (cinema != null && cinema.GetCity().GetName().Equals(cityName, StringComparison.OrdinalIgnoreCase)) { result.Add(show); } } } return result; } private Cinema FindCinemaForShow(Show show) { return cinemas.Values.FirstOrDefault(cinema => cinema.GetScreens().Contains(show.GetScreen())); } public void Shutdown() { seatLockManager.Shutdown(); Console.WriteLine("MovieTicketBookingSystem has been shut down."); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Observer/IMovieObserver.cs ================================================ interface IMovieObserver { void Update(Movie movie); } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Observer/MovieSubject.cs ================================================ abstract class MovieSubject { private readonly List observers = new List(); public void AddObserver(IMovieObserver observer) { observers.Add(observer); } public void RemoveObserver(IMovieObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (var observer in observers) { observer.Update((Movie)this); } } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Observer/UserObserver.cs ================================================ class UserObserver : IMovieObserver { private readonly User user; public UserObserver(User user) { this.user = user; } public void Update(Movie movie) { Console.WriteLine($"Notification for {user.GetName()} ({user.GetId()}): Movie '{movie.GetTitle()}' is now available for booking!"); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/README.md ================================================ # Designing a Movie Ticket Booking System like BookMyShow ## Requirements 1. The system should allow users to view the list of movies playing in different theaters. 2. Users should be able to select a movie, theater, and show timing to book tickets. 3. The system should display the seating arrangement of the selected show and allow users to choose seats. 4. Users should be able to make payments and confirm their booking. 5. The system should handle concurrent bookings and ensure seat availability is updated in real-time. 6. The system should support different types of seats (e.g., normal, premium) and pricing. 7. The system should allow theater administrators to add, update, and remove movies, shows, and seating arrangements. 8. The system should be scalable to handle a large number of concurrent users and bookings. ## Classes, Interfaces and Enumerations 1. The **Movie** class represents a movie with properties such as ID, title, description, and duration. 2. The **Theater** class represents a theater with properties such as ID, name, location, and a list of shows. 3. The **Show** class represents a movie show in a theater, with properties such as ID, movie, theater, start time, end time, and a map of seats. 4. The **Seat** class represents a seat in a show, with properties such as ID, row, column, type, price, and status. 5. The **SeatType** enum defines the different types of seats (normal or premium). 6. The **SeatStatus** enum defines the different statuses of a seat (available or booked). 7. The **Booking** class represents a booking made by a user, with properties such as ID, user, show, selected seats, total price, and status. 8. The **BookingStatus** enum defines the different statuses of a booking (pending, confirmed, or cancelled). 9. The **User** class represents a user of the booking system, with properties such as ID, name, and email. 10. The **MovieTicketBookingSystem** class is the main class that manages the movie ticket booking system. It follows the Singleton pattern to ensure only one instance of the system exists. 11. The MovieTicketBookingSystem class provides methods for adding movies, theaters, and shows, as well as booking tickets, confirming bookings, and cancelling bookings. 12. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap to handle concurrent access to shared resources like shows and bookings. 13. The **MovieTicketBookingDemo** class demonstrates the usage of the movie ticket booking system by adding movies, theaters, shows, booking tickets, and confirming or cancelling bookings. ================================================ FILE: solutions/csharp/movieticketbookingsystem/SeatLockManager.cs ================================================ class SeatLockManager { private readonly Dictionary> lockedSeats = new Dictionary>(); private readonly object lockObj = new object(); private const int LOCK_TIMEOUT_MS = 500; // 0.5 seconds public void LockSeats(Show show, List seats, string userId) { lock (lockObj) { // Check if any of the requested seats are already locked or booked foreach (var seat in seats) { if (seat.GetStatus() != SeatStatus.AVAILABLE) { Console.WriteLine($"Seat {seat.GetId()} is not available."); return; } } // Lock the seats foreach (var seat in seats) { seat.SetStatus(SeatStatus.LOCKED); } if (!lockedSeats.ContainsKey(show)) { lockedSeats[show] = new Dictionary(); } foreach (var seat in seats) { lockedSeats[show][seat] = userId; } // Schedule a task to unlock the seats after a timeout Task.Delay(LOCK_TIMEOUT_MS).ContinueWith(_ => UnlockSeats(show, seats, userId)); Console.WriteLine($"Locked seats: {string.Join(", ", seats.Select(s => s.GetId()))} for user {userId}"); } } public void UnlockSeats(Show show, List seats, string userId) { lock (lockObj) { if (lockedSeats.TryGetValue(show, out var showLocks)) { foreach (var seat in seats) { if (showLocks.TryGetValue(seat, out var lockedUserId) && lockedUserId == userId) { showLocks.Remove(seat); if (seat.GetStatus() == SeatStatus.LOCKED) { seat.SetStatus(SeatStatus.AVAILABLE); Console.WriteLine($"Unlocked seat: {seat.GetId()} due to timeout."); } else { Console.WriteLine($"Unlocked seat: {seat.GetId()} due to booking completion."); } } } if (!showLocks.Any()) { lockedSeats.Remove(show); } } } } public void Shutdown() { Console.WriteLine("Shutting down SeatLockProvider scheduler."); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Strategies/Payment/CreditCardPaymentStrategy.cs ================================================ class CreditCardPaymentStrategy : IPaymentStrategy { private readonly string cardNumber; private readonly string cvv; public CreditCardPaymentStrategy(string cardNumber, string cvv) { this.cardNumber = cardNumber; this.cvv = cvv; } public Payment Pay(double amount) { Console.WriteLine($"Processing credit card payment of ${amount:F2}"); // Simulate payment gateway interaction var random = new Random(); bool paymentSuccess = random.NextDouble() > 0.05; // 95% success rate return new Payment( amount, paymentSuccess ? PaymentStatus.SUCCESS : PaymentStatus.FAILURE, $"TXN_{Guid.NewGuid()}" ); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Strategies/Payment/IPaymentStrategy.cs ================================================ interface IPaymentStrategy { Payment Pay(double amount); } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Strategies/Pricing/IPricingStrategy.cs ================================================ interface IPricingStrategy { double CalculatePrice(List seats); } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Strategies/Pricing/WeekdayPricingStrategy.cs ================================================ class WeekdayPricingStrategy : IPricingStrategy { public double CalculatePrice(List seats) { return seats.Sum(seat => seat.GetSeatType().GetPrice()); } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/Strategies/Pricing/WeekendPricingStrategy.cs ================================================ class WeekendPricingStrategy : IPricingStrategy { private const double WEEKEND_SURCHARGE = 1.2; // 20% surcharge public double CalculatePrice(List seats) { double basePrice = seats.Sum(seat => seat.GetSeatType().GetPrice()); return basePrice * WEEKEND_SURCHARGE; } } ================================================ FILE: solutions/csharp/movieticketbookingsystem/movieticketbookingsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/musicstreamingservice/Commands/ICommand.cs ================================================ interface ICommand { void Execute(); } ================================================ FILE: solutions/csharp/musicstreamingservice/Commands/NextTrackCommand.cs ================================================ class NextTrackCommand : ICommand { private readonly Player player; public NextTrackCommand(Player player) { this.player = player; } public void Execute() { player.ClickNext(); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Commands/PauseCommand.cs ================================================ class PauseCommand : ICommand { private readonly Player player; public PauseCommand(Player player) { this.player = player; } public void Execute() { player.ClickPause(); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Commands/PlayCommand.cs ================================================ class PlayCommand : ICommand { private readonly Player player; public PlayCommand(Player player) { this.player = player; } public void Execute() { player.ClickPlay(); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Enums/PlayerStatus.cs ================================================ enum PlayerStatus { PLAYING, PAUSED, STOPPED } ================================================ FILE: solutions/csharp/musicstreamingservice/Enums/SubscriptionTier.cs ================================================ enum SubscriptionTier { FREE, PREMIUM } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/Album.cs ================================================ class Album : IPlayable { private readonly string title; private readonly List tracks = new List(); public Album(string title) { this.title = title; } public void AddTrack(Song song) { tracks.Add(song); } public List GetTracks() { return new List(tracks); } public string GetTitle() => title; } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/Artist.cs ================================================ class Artist : Subject { private readonly string id; private readonly string name; private readonly List discography = new List(); public Artist(string id, string name) { this.id = id; this.name = name; } public void ReleaseAlbum(Album album) { discography.Add(album); Console.WriteLine($"[System] Artist {name} has released a new album: {album.GetTitle()}"); NotifyObservers(this, album); } public string GetId() => id; public string GetName() => name; } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/IPlayable.cs ================================================ interface IPlayable { List GetTracks(); } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/Player.cs ================================================ class Player { private PlayerState state; private PlayerStatus status; private List queue = new List(); private int currentIndex = -1; private Song currentSong; private User currentUser; public Player() { this.state = new StoppedState(); this.status = PlayerStatus.STOPPED; } public void Load(IPlayable playable, User user) { this.currentUser = user; this.queue = playable.GetTracks(); this.currentIndex = 0; Console.WriteLine($"Loaded {queue.Count} tracks for user {user.GetName()}."); this.state = new StoppedState(); } public void PlayCurrentSongInQueue() { if (currentIndex >= 0 && currentIndex < queue.Count) { Song songToPlay = queue[currentIndex]; currentUser.GetPlaybackStrategy().Play(songToPlay, this); } } public void ClickPlay() => state.Play(this); public void ClickPause() => state.Pause(this); public void ClickNext() { if (currentIndex < queue.Count - 1) { currentIndex++; PlayCurrentSongInQueue(); } else { Console.WriteLine("End of queue."); state.Stop(this); } } public void ChangeState(PlayerState state) => this.state = state; public void SetStatus(PlayerStatus status) => this.status = status; public void SetCurrentSong(Song song) => this.currentSong = song; public bool HasQueue() => queue.Count > 0; } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/Playlist.cs ================================================ class Playlist : IPlayable { private readonly string name; private readonly List tracks = new List(); public Playlist(string name) { this.name = name; } public void AddTrack(Song song) { tracks.Add(song); } public List GetTracks() { return new List(tracks); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/Song.cs ================================================ class Song : IPlayable { private readonly string id; private readonly string title; private readonly Artist artist; private readonly int durationInSeconds; public Song(string id, string title, Artist artist, int durationInSeconds) { this.id = id; this.title = title; this.artist = artist; this.durationInSeconds = durationInSeconds; } public List GetTracks() { return new List { this }; } public override string ToString() { return $"'{title}' by {artist.GetName()}"; } public string GetId() => id; public string GetTitle() => title; public Artist GetArtist() => artist; } ================================================ FILE: solutions/csharp/musicstreamingservice/Models/User.cs ================================================ class User : IArtistObserver { private readonly string id; private readonly string name; private readonly PlaybackStrategy playbackStrategy; private readonly HashSet followedArtists = new HashSet(); public User(string id, string name, PlaybackStrategy strategy) { this.id = id; this.name = name; this.playbackStrategy = strategy; } public void FollowArtist(Artist artist) { followedArtists.Add(artist); artist.AddObserver(this); } public void Update(Artist artist, Album newAlbum) { Console.WriteLine($"[Notification for {name}] Your followed artist {artist.GetName()} " + $"just released a new album: {newAlbum.GetTitle()}!"); } public PlaybackStrategy GetPlaybackStrategy() => playbackStrategy; public string GetId() => id; public string GetName() => name; } class UserBuilder { private readonly string id; private readonly string name; private PlaybackStrategy playbackStrategy; public UserBuilder(string name) { this.id = Guid.NewGuid().ToString(); this.name = name; } public UserBuilder WithSubscription(SubscriptionTier tier, int songsPlayed) { this.playbackStrategy = PlaybackStrategy.GetStrategy(tier, songsPlayed); return this; } public User Build() { return new User(id, name, playbackStrategy); } } ================================================ FILE: solutions/csharp/musicstreamingservice/MusicStreamingDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class MusicStreamingDemo { public static void Main(string[] args) { MusicStreamingSystem system = MusicStreamingSystem.GetInstance(); // --- Setup Catalog --- Artist daftPunk = new Artist("art1", "Daft Punk"); system.AddArtist(daftPunk); Album discovery = new Album("Discovery"); Song s1 = system.AddSong("s1", "One More Time", daftPunk.GetId(), 320); Song s2 = system.AddSong("s2", "Aerodynamic", daftPunk.GetId(), 212); Song s3 = system.AddSong("s3", "Digital Love", daftPunk.GetId(), 301); Song s4 = system.AddSong("s4", "Radioactive", daftPunk.GetId(), 311); discovery.AddTrack(s1); discovery.AddTrack(s2); discovery.AddTrack(s3); discovery.AddTrack(s4); // --- Register Users (Builder Pattern) --- User freeUser = new UserBuilder("Alice").WithSubscription(SubscriptionTier.FREE, 0).Build(); User premiumUser = new UserBuilder("Bob").WithSubscription(SubscriptionTier.PREMIUM, 0).Build(); system.RegisterUser(freeUser); system.RegisterUser(premiumUser); // --- Observer Pattern: User follows artist --- Console.WriteLine("--- Observer Pattern Demo ---"); premiumUser.FollowArtist(daftPunk); daftPunk.ReleaseAlbum(discovery); // This will notify Bob Console.WriteLine(); // --- Strategy Pattern: Playback behavior --- Console.WriteLine("--- Strategy Pattern (Free vs Premium) & State Pattern (Player) Demo ---"); Player player = system.GetPlayer(); player.Load(discovery, freeUser); // --- Command Pattern: Controlling the player --- ICommand play = new PlayCommand(player); ICommand pause = new PauseCommand(player); ICommand nextTrack = new NextTrackCommand(player); play.Execute(); // Plays song 1 nextTrack.Execute(); // Plays song 2 pause.Execute(); // Pauses song 2 play.Execute(); // Resumes song 2 nextTrack.Execute(); // Plays song 3 nextTrack.Execute(); // Plays song 4 (ad for free user) Console.WriteLine(); // --- Premium user experience (no ads) --- Console.WriteLine("--- Premium User Experience ---"); player.Load(discovery, premiumUser); play.Execute(); nextTrack.Execute(); Console.WriteLine(); // --- Composite Pattern: Play a playlist --- Console.WriteLine("--- Composite Pattern Demo ---"); Playlist myPlaylist = new Playlist("My Awesome Mix"); myPlaylist.AddTrack(s3); // Digital Love myPlaylist.AddTrack(s1); // One More Time player.Load(myPlaylist, premiumUser); play.Execute(); nextTrack.Execute(); Console.WriteLine(); // --- Search and Recommendation --- Console.WriteLine("--- Search and Recommendation Service Demo ---"); List searchResults = system.SearchSongsByTitle("love"); Console.WriteLine($"Search results for 'love': {string.Join(", ", searchResults)}"); List recommendations = system.GetSongRecommendations(); Console.WriteLine($"Your daily recommendations: {string.Join(", ", recommendations)}"); } } ================================================ FILE: solutions/csharp/musicstreamingservice/MusicStreamingSystem.cs ================================================ class MusicStreamingSystem { private static MusicStreamingSystem instance; private static readonly object lockObject = new object(); private readonly Dictionary users = new Dictionary(); private readonly Dictionary songs = new Dictionary(); private readonly Dictionary artists = new Dictionary(); private readonly Player player; private readonly SearchService searchService; private readonly RecommendationService recommendationService; private MusicStreamingSystem() { this.player = new Player(); this.searchService = new SearchService(); this.recommendationService = new RecommendationService(new GenreBasedRecommendationStrategy()); } public static MusicStreamingSystem GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new MusicStreamingSystem(); } } } return instance; } public void RegisterUser(User user) { users[user.GetId()] = user; } public Song AddSong(string id, string title, string artistId, int duration) { Song song = new Song(id, title, artists[artistId], duration); songs[song.GetId()] = song; return song; } public void AddArtist(Artist artist) { artists[artist.GetId()] = artist; } public List SearchSongsByTitle(string title) { return searchService.SearchSongsByTitle(songs.Values.ToList(), title); } public List GetSongRecommendations() { return recommendationService.GenerateRecommendations(songs.Values.ToList()); } public Player GetPlayer() => player; } ================================================ FILE: solutions/csharp/musicstreamingservice/Observer/IArtistObserver.cs ================================================ interface IArtistObserver { void Update(Artist artist, Album newAlbum); } ================================================ FILE: solutions/csharp/musicstreamingservice/Observer/Subject.cs ================================================ abstract class Subject { private readonly List observers = new List(); public void AddObserver(IArtistObserver observer) { observers.Add(observer); } public void RemoveObserver(IArtistObserver observer) { observers.Remove(observer); } public void NotifyObservers(Artist artist, Album album) { foreach (var observer in observers) { observer.Update(artist, album); } } } ================================================ FILE: solutions/csharp/musicstreamingservice/README.md ================================================ # Designing an Online Music Streaming Service Like Spotify ## Requirements 1. The music streaming service should allow users to browse and search for songs, albums, and artists. 2. Users should be able to create and manage playlists. 3. The system should support user authentication and authorization. 4. Users should be able to play, pause, skip, and seek within songs. 5. The system should recommend songs and playlists based on user preferences and listening history. 6. The system should handle concurrent requests and ensure smooth streaming experience for multiple users. 7. The system should be scalable and handle a large volume of songs and users. 8. The system should be extensible to support additional features such as social sharing and offline playback. ## Classes, Interfaces and Enumerations 1. The **Song**, **Album**, and **Artist** classes represent the basic entities in the music streaming service, with properties such as ID, title, artist, album, duration, and relationships between them. 2. The **User** class represents a user of the music streaming service, with properties like ID, username, password, and a list of playlists. 3. The **Playlist** class represents a user-created playlist, containing a list of songs. 4. The **MusicLibrary** class serves as a central repository for storing and managing songs, albums, and artists. It follows the Singleton pattern to ensure a single instance of the music library. 5. The **UserManager** class handles user registration, login, and other user-related operations. It also follows the Singleton pattern. 6. The **MusicPlayer** class represents the music playback functionality, allowing users to play, pause, skip, and seek within songs. 7. The **MusicRecommender** class generates song recommendations based on user preferences and listening history. It follows the Singleton pattern. 8. The **MusicStreamingService** class is the main entry point of the music streaming service. It initializes the necessary components, handles user requests, and manages the overall functionality of the service. ================================================ FILE: solutions/csharp/musicstreamingservice/Services/RecommendationService.cs ================================================ class RecommendationService { private RecommendationStrategy strategy; public RecommendationService(RecommendationStrategy strategy) { this.strategy = strategy; } public void SetStrategy(RecommendationStrategy strategy) { this.strategy = strategy; } public List GenerateRecommendations(List allSongs) { return strategy.Recommend(allSongs); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Services/SearchService.cs ================================================ class SearchService { public List SearchSongsByTitle(List songs, string query) { return songs.Where(s => s.GetTitle().ToLower().Contains(query.ToLower())).ToList(); } public List SearchArtistsByName(List artists, string query) { return artists.Where(a => a.GetName().ToLower().Contains(query.ToLower())).ToList(); } } ================================================ FILE: solutions/csharp/musicstreamingservice/States/PausedState.cs ================================================ class PausedState : PlayerState { public override void Play(Player player) { Console.WriteLine("Resuming playback."); player.ChangeState(new PlayingState()); player.SetStatus(PlayerStatus.PLAYING); } public override void Pause(Player player) { Console.WriteLine("Already paused."); } public override void Stop(Player player) { Console.WriteLine("Stopping playback from paused state."); player.ChangeState(new StoppedState()); player.SetStatus(PlayerStatus.STOPPED); } } ================================================ FILE: solutions/csharp/musicstreamingservice/States/PlayerState.cs ================================================ abstract class PlayerState { public abstract void Play(Player player); public abstract void Pause(Player player); public abstract void Stop(Player player); } ================================================ FILE: solutions/csharp/musicstreamingservice/States/PlayingState.cs ================================================ class PlayingState : PlayerState { public override void Play(Player player) { Console.WriteLine("Already playing."); } public override void Pause(Player player) { Console.WriteLine("Pausing playback."); player.ChangeState(new PausedState()); player.SetStatus(PlayerStatus.PAUSED); } public override void Stop(Player player) { Console.WriteLine("Stopping playback."); player.ChangeState(new StoppedState()); player.SetStatus(PlayerStatus.STOPPED); } } ================================================ FILE: solutions/csharp/musicstreamingservice/States/StoppedState.cs ================================================ class StoppedState : PlayerState { public override void Play(Player player) { if (player.HasQueue()) { Console.WriteLine("Starting playback."); player.ChangeState(new PlayingState()); player.SetStatus(PlayerStatus.PLAYING); player.PlayCurrentSongInQueue(); } else { Console.WriteLine("Queue is empty. Load songs to play."); } } public override void Pause(Player player) { Console.WriteLine("Cannot pause. Player is stopped."); } public override void Stop(Player player) { Console.WriteLine("Already stopped."); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Strategies/Playback/FreePlaybackStrategy.cs ================================================ class FreePlaybackStrategy : PlaybackStrategy { private int songsPlayed; private const int SONGS_BEFORE_AD = 3; public FreePlaybackStrategy(int initialSongsPlayed) { this.songsPlayed = initialSongsPlayed; } public override void Play(Song song, Player player) { if (songsPlayed > 0 && songsPlayed % SONGS_BEFORE_AD == 0) { Console.WriteLine("\n>>> Playing Advertisement: 'Buy Spotify Premium for ad-free music!' <<<\n"); } player.SetCurrentSong(song); Console.WriteLine($"Free User is now playing: {song}"); songsPlayed++; } } ================================================ FILE: solutions/csharp/musicstreamingservice/Strategies/Playback/PlaybackStrategy.cs ================================================ abstract class PlaybackStrategy { public abstract void Play(Song song, Player player); public static PlaybackStrategy GetStrategy(SubscriptionTier tier, int songsPlayed) { if (tier == SubscriptionTier.PREMIUM) { return new PremiumPlaybackStrategy(); } else { return new FreePlaybackStrategy(songsPlayed); } } } ================================================ FILE: solutions/csharp/musicstreamingservice/Strategies/Playback/PremiumPlaybackStrategy.cs ================================================ class PremiumPlaybackStrategy : PlaybackStrategy { public override void Play(Song song, Player player) { player.SetCurrentSong(song); Console.WriteLine($"Premium User is now playing: {song}"); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Strategies/Recommendation/GenreBasedRecommendationStrategy.cs ================================================ class GenreBasedRecommendationStrategy : RecommendationStrategy { public override List Recommend(List allSongs) { Console.WriteLine("Generating genre-based recommendations (simulated)..."); var shuffled = new List(allSongs); var random = new Random(); for (int i = shuffled.Count - 1; i > 0; i--) { int j = random.Next(i + 1); var temp = shuffled[i]; shuffled[i] = shuffled[j]; shuffled[j] = temp; } return shuffled.Take(Math.Min(5, shuffled.Count)).ToList(); } } ================================================ FILE: solutions/csharp/musicstreamingservice/Strategies/Recommendation/RecommendationStrategy.cs ================================================ abstract class RecommendationStrategy { public abstract List Recommend(List allSongs); } ================================================ FILE: solutions/csharp/musicstreamingservice/musicstreamingservice.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs ================================================ // using System; using System.Reflection; [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.AssemblyInfo.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ using System; using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("c#")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1379ab56cefd982c99776878aa6ef1d39bbc7b22")] [assembly: System.Reflection.AssemblyProductAttribute("c#")] [assembly: System.Reflection.AssemblyTitleAttribute("c#")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] // Generated by the MSBuild WriteCodeFragment class. ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.AssemblyInfoInputs.cache ================================================ 25fb3ba4eeb06496c566fa0153595600436e9ec4373e73b31184698121ae05ae ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.GeneratedMSBuildEditorConfig.editorconfig ================================================ is_global = true build_property.TargetFramework = net8.0 build_property.TargetPlatformMinVersion = build_property.UsingMicrosoftNETSdkWeb = build_property.ProjectTypeGuids = build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property.EnforceExtendedAnalyzerRules = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = c_ build_property.ProjectDir = /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/ build_property.EnableComHosting = build_property.EnableGeneratedComInterfaceComImportInterop = ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.GlobalUsings.g.cs ================================================ // global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.csproj.CoreCompileInputs.cache ================================================ 3c047aad63a937978d53f58242d12a232581b441bab25fd4fd674ff3245acf0e ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.csproj.FileListAbsolute.txt ================================================ /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/bin/Debug/net8.0/c# /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/bin/Debug/net8.0/c#.deps.json /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/bin/Debug/net8.0/c#.runtimeconfig.json /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/bin/Debug/net8.0/c#.dll /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/bin/Debug/net8.0/c#.pdb /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.GeneratedMSBuildEditorConfig.editorconfig /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.AssemblyInfoInputs.cache /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.AssemblyInfo.cs /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.csproj.CoreCompileInputs.cache /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.sourcelink.json /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.dll /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/refint/c#.dll /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.pdb /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/c#.genruntimeconfig.cache /Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/Debug/net8.0/ref/c#.dll ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.genruntimeconfig.cache ================================================ 7b28f71545fc472760ef5d7fcd67cc395e8399231e52d61e9317f967eeadb7ab ================================================ FILE: solutions/csharp/obj/Debug/net8.0/c#.sourcelink.json ================================================ {"documents":{"/Users/ashishps/Documents/Github/awesome-low-level-design/*":"https://raw.githubusercontent.com/ashishps1/awesome-low-level-design/670a8c96828227383eaee93e411465d985a546d0/*"}} ================================================ FILE: solutions/csharp/obj/c#.csproj.nuget.dgspec.json ================================================ { "format": 1, "restore": { "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj": {} }, "projects": { "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj": { "version": "1.0.0", "restore": { "projectUniqueName": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj", "projectName": "c#", "projectPath": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj", "packagesPath": "/Users/ashishps/.nuget/packages/", "outputPath": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/Users/ashishps/.nuget/NuGet/NuGet.Config" ], "originalTargetFrameworks": [ "net8.0" ], "sources": { "https://api.nuget.org/v3/index.json": {} }, "frameworks": { "net8.0": { "targetAlias": "net8.0", "projectReferences": {} } }, "warningProperties": { "warnAsError": [ "NU1605" ] }, "restoreAuditProperties": { "enableAudit": "true", "auditLevel": "low", "auditMode": "direct" } }, "frameworks": { "net8.0": { "targetAlias": "net8.0", "imports": [ "net461", "net462", "net47", "net471", "net472", "net48", "net481" ], "assetTargetFallback": true, "warn": true, "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/8.0.403/PortableRuntimeIdentifierGraph.json" } } } } } ================================================ FILE: solutions/csharp/obj/c#.csproj.nuget.g.props ================================================  True NuGet $(MSBuildThisFileDirectory)project.assets.json /Users/ashishps/.nuget/packages/ /Users/ashishps/.nuget/packages/ PackageReference 6.11.1 ================================================ FILE: solutions/csharp/obj/c#.csproj.nuget.g.targets ================================================  ================================================ FILE: solutions/csharp/obj/project.assets.json ================================================ { "version": 3, "targets": { "net8.0": {} }, "libraries": {}, "projectFileDependencyGroups": { "net8.0": [] }, "packageFolders": { "/Users/ashishps/.nuget/packages/": {} }, "project": { "version": "1.0.0", "restore": { "projectUniqueName": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj", "projectName": "c#", "projectPath": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj", "packagesPath": "/Users/ashishps/.nuget/packages/", "outputPath": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/Users/ashishps/.nuget/NuGet/NuGet.Config" ], "originalTargetFrameworks": [ "net8.0" ], "sources": { "https://api.nuget.org/v3/index.json": {} }, "frameworks": { "net8.0": { "targetAlias": "net8.0", "projectReferences": {} } }, "warningProperties": { "warnAsError": [ "NU1605" ] }, "restoreAuditProperties": { "enableAudit": "true", "auditLevel": "low", "auditMode": "direct" } }, "frameworks": { "net8.0": { "targetAlias": "net8.0", "imports": [ "net461", "net462", "net47", "net471", "net472", "net48", "net481" ], "assetTargetFallback": true, "warn": true, "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/8.0.403/PortableRuntimeIdentifierGraph.json" } } } } ================================================ FILE: solutions/csharp/obj/project.nuget.cache ================================================ { "version": 2, "dgSpecHash": "E8dOOPle2Ps=", "success": true, "projectFilePath": "/Users/ashishps/Documents/Github/awesome-low-level-design/solutions/c#/c#.csproj", "expectedPackageFiles": [], "logs": [] } ================================================ FILE: solutions/csharp/onlineauctionsystem/AuctionService.cs ================================================ using System.Collections.Concurrent; class AuctionService { private static AuctionService instance; private static readonly object lockObject = new object(); private readonly ConcurrentDictionary users; private readonly ConcurrentDictionary auctions; private readonly List scheduledTasks; private bool shutdown; private AuctionService() { users = new ConcurrentDictionary(); auctions = new ConcurrentDictionary(); scheduledTasks = new List(); shutdown = false; } public static AuctionService GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new AuctionService(); } } } return instance; } public User CreateUser(string name) { User user = new User(name); users.TryAdd(user.GetId(), user); return user; } public User GetUser(string userId) { users.TryGetValue(userId, out User user); return user; } public Auction CreateAuction(string itemName, string description, decimal startingPrice, DateTime endTime) { Auction auction = new Auction(itemName, description, startingPrice, endTime); auctions.TryAdd(auction.GetId(), auction); TimeSpan delay = endTime - DateTime.Now; if (delay.TotalMilliseconds > 0) { Task scheduledTask = Task.Run(async () => { await Task.Delay(delay); if (!shutdown) { EndAuction(auction.GetId()); } }); scheduledTasks.Add(scheduledTask); } Console.WriteLine($"New auction created for '{itemName}' (ID: {auction.GetId()}), ending at {endTime}."); return auction; } public List ViewActiveAuctions() { return auctions.Values.Where(auction => auction.IsActive()).ToList(); } public void PlaceBid(string auctionId, string bidderId, decimal amount) { Auction auction = GetAuction(auctionId); auction.PlaceBid(users[bidderId], amount); } public void EndAuction(string auctionId) { Auction auction = GetAuction(auctionId); auction.EndAuction(); } public Auction GetAuction(string auctionId) { if (!auctions.TryGetValue(auctionId, out Auction auction)) { throw new KeyNotFoundException($"Auction with ID {auctionId} not found."); } return auction; } public void Shutdown() { shutdown = true; Task.WaitAll(scheduledTasks.ToArray()); } } ================================================ FILE: solutions/csharp/onlineauctionsystem/AuctionSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class AuctionSystemDemo { public static void Main(string[] args) { AuctionService auctionService = AuctionService.GetInstance(); User alice = auctionService.CreateUser("Alice"); User bob = auctionService.CreateUser("Bob"); User carol = auctionService.CreateUser("Carol"); Console.WriteLine("============================================="); Console.WriteLine(" Online Auction System Demo "); Console.WriteLine("============================================="); DateTime endTime = DateTime.Now.AddSeconds(10); Auction laptopAuction = auctionService.CreateAuction( "Vintage Laptop", "A rare 1990s laptop, in working condition.", 100.00m, endTime ); Console.WriteLine(); try { auctionService.PlaceBid(laptopAuction.GetId(), alice.GetId(), 110.00m); Thread.Sleep(500); auctionService.PlaceBid(laptopAuction.GetId(), bob.GetId(), 120.00m); Thread.Sleep(500); auctionService.PlaceBid(laptopAuction.GetId(), carol.GetId(), 125.00m); Thread.Sleep(500); auctionService.PlaceBid(laptopAuction.GetId(), alice.GetId(), 150.00m); Console.WriteLine("\n--- Waiting for auction to end automatically... ---"); Thread.Sleep(2000); } catch (Exception e) { Console.WriteLine($"An error occurred during bidding: {e.Message}"); } Console.WriteLine("\n--- Post-Auction Information ---"); Auction endedAuction = auctionService.GetAuction(laptopAuction.GetId()); if (endedAuction.GetWinningBid() != null) { Console.WriteLine($"Final Winner: {endedAuction.GetWinningBid().GetBidder().GetName()}"); Console.WriteLine($"Winning Price: ${endedAuction.GetWinningBid().GetAmount():F2}"); } else { Console.WriteLine("The auction ended with no winner."); } Console.WriteLine("\nFull Bid History:"); foreach (Bid bid in endedAuction.GetBidHistory()) { Console.WriteLine(bid.ToString()); } Console.WriteLine("\n--- Attempting to bid on an ended auction ---"); try { auctionService.PlaceBid(laptopAuction.GetId(), bob.GetId(), 200.00m); } catch (Exception e) { Console.WriteLine($"CAUGHT EXPECTED ERROR: {e.Message}"); } auctionService.Shutdown(); } } ================================================ FILE: solutions/csharp/onlineauctionsystem/Enum/AuctionState.cs ================================================ enum AuctionState { PENDING, ACTIVE, CLOSED } ================================================ FILE: solutions/csharp/onlineauctionsystem/Models/Auction.cs ================================================ class Auction { private readonly string id; private readonly string itemName; private readonly string description; private readonly decimal startingPrice; private readonly DateTime endTime; private readonly List bids; private readonly HashSet observers; private AuctionState state; private Bid winningBid; private readonly object lockObject = new object(); public Auction(string itemName, string description, decimal startingPrice, DateTime endTime) { this.id = Guid.NewGuid().ToString(); this.itemName = itemName; this.description = description; this.startingPrice = startingPrice; this.endTime = endTime; this.bids = new List(); this.observers = new HashSet(); this.state = AuctionState.ACTIVE; } public void PlaceBid(User bidder, decimal amount) { lock (lockObject) { if (state != AuctionState.ACTIVE) { throw new InvalidOperationException("Auction is not active."); } if (DateTime.Now > endTime) { EndAuction(); throw new InvalidOperationException("Auction has already ended."); } Bid highestBid = GetHighestBid(); decimal currentMaxAmount = (highestBid == null) ? startingPrice : highestBid.GetAmount(); if (amount <= currentMaxAmount) { throw new ArgumentException("Bid must be higher than the current highest bid."); } User previousHighestBidder = (highestBid != null) ? highestBid.GetBidder() : null; Bid newBid = new Bid(bidder, amount); bids.Add(newBid); AddObserver(bidder); Console.WriteLine($"SUCCESS: {bidder.GetName()} placed a bid of ${amount:F2} on '{itemName}'."); if (previousHighestBidder != null && !previousHighestBidder.Equals(bidder)) { NotifyObserver(previousHighestBidder, $"You have been outbid on '{itemName}'! The new highest bid is ${amount:F2}."); } } } public void EndAuction() { lock (lockObject) { if (state != AuctionState.ACTIVE) { return; } state = AuctionState.CLOSED; winningBid = GetHighestBid(); string endMessage; if (winningBid != null) { endMessage = $"Auction for '{itemName}' has ended. Winner is {winningBid.GetBidder().GetName()} with a bid of ${winningBid.GetAmount():F2}!"; } else { endMessage = $"Auction for '{itemName}' has ended. There were no bids."; } Console.WriteLine($"\n{endMessage.ToUpper()}"); NotifyAllObservers(endMessage); } } public Bid GetHighestBid() { if (bids.Count == 0) { return null; } return bids.Max(); } public bool IsActive() { return state == AuctionState.ACTIVE; } private void AddObserver(IAuctionObserver observer) { observers.Add(observer); } private void NotifyAllObservers(string message) { foreach (IAuctionObserver observer in observers) { observer.OnUpdate(this, message); } } private void NotifyObserver(IAuctionObserver observer, string message) { observer.OnUpdate(this, message); } public string GetId() { return id; } public string GetItemName() { return itemName; } public List GetBidHistory() { return new List(bids); } public AuctionState GetState() { return state; } public Bid GetWinningBid() { return winningBid; } } ================================================ FILE: solutions/csharp/onlineauctionsystem/Models/Bid.cs ================================================ class Bid : IComparable { private readonly User bidder; private readonly decimal amount; private readonly DateTime timestamp; public Bid(User bidder, decimal amount) { this.bidder = bidder; this.amount = amount; this.timestamp = DateTime.Now; } public User GetBidder() { return bidder; } public decimal GetAmount() { return amount; } public DateTime GetTimestamp() { return timestamp; } public int CompareTo(Bid other) { int amountComparison = amount.CompareTo(other.amount); if (amountComparison != 0) { return amountComparison; } return other.timestamp.CompareTo(timestamp); } public override string ToString() { return $"Bidder: {bidder.GetName()}, Amount: {amount:F2}, Time: {timestamp}"; } } ================================================ FILE: solutions/csharp/onlineauctionsystem/Models/User.cs ================================================ class User : IAuctionObserver { private readonly string id; private readonly string name; public User(string name) { this.id = Guid.NewGuid().ToString(); this.name = name; } public string GetId() { return id; } public string GetName() { return name; } public void OnUpdate(Auction auction, string message) { Console.WriteLine($"--- Notification for {name} ---"); Console.WriteLine($"Auction: {auction.GetItemName()}"); Console.WriteLine($"Message: {message}"); Console.WriteLine("---------------------------\n"); } public override bool Equals(object obj) { if (this == obj) return true; if (obj == null || GetType() != obj.GetType()) return false; User user = (User)obj; return id.Equals(user.id); } public override int GetHashCode() { return id.GetHashCode(); } } ================================================ FILE: solutions/csharp/onlineauctionsystem/Observer/IAuctionObserver.cs ================================================ interface IAuctionObserver { void OnUpdate(Auction auction, string message); } ================================================ FILE: solutions/csharp/onlineauctionsystem/README.md ================================================ # Designing an Online Auction System In this article, we delve into the object-oriented design and implementation of an Online Auction System using Java. This system allows for the creation and management of auctions, user participation in bidding, and handling transactions. ## Requirements 1. The online auction system should allow users to register and log in to their accounts. 2. Users should be able to create new auction listings with details such as item name, description, starting price, and auction duration. 3. Users should be able to browse and search for auction listings based on various criteria (e.g., item name, category, price range). 4. Users should be able to place bids on active auction listings. 5. The system should automatically update the current highest bid and notify the bidders accordingly. 6. The auction should end when the specified duration is reached, and the highest bidder should be declared the winner. 7. The system should handle concurrent access to auction listings and ensure data consistency. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online auction system, with properties such as id, username, and email. 2. The **AuctionStatus** enum defines the possible states of an auction listing, such as active and closed. 3. The **AuctionListing** class represents an auction listing in the system, with properties like id, item name, description, starting price, duration, seller, current highest bid, and a list of bids. 4. The **Bid** class represents a bid placed by a user on an auction listing, with properties such as id, bidder, amount, and timestamp. 5. The **AuctionSystem** class is the core of the online auction system and follows the Singleton pattern to ensure a single instance of the auction system. 6. The AuctionSystem class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to auction listings and ensure thread safety. 7. The AuctionSystem class provides methods for registering users, creating auction listings, searching auction listings, and placing bids. 8. The **AuctionSystemDemo** class serves as the entry point of the application and demonstrates the usage of the online auction system. ================================================ FILE: solutions/csharp/onlineauctionsystem/onlineauctionsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/onlineshoppingservice/Decorators/GiftWrapDecorator.cs ================================================ class GiftWrapDecorator : ProductDecorator { private const double GIFT_WRAP_COST = 5.00; public GiftWrapDecorator(Product product) : base(product) { } public override double GetPrice() { return base.GetPrice() + GIFT_WRAP_COST; } public override string GetDescription() { return base.GetDescription() + " (Gift Wrapped)"; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Decorators/ProductDecorator.cs ================================================ abstract class ProductDecorator : Product { protected Product decoratedProduct; public ProductDecorator(Product product) { decoratedProduct = product; } public override string GetId() { return decoratedProduct.GetId(); } public override string GetName() { return decoratedProduct.GetName(); } public override double GetPrice() { return decoratedProduct.GetPrice(); } public override string GetDescription() { return decoratedProduct.GetDescription(); } public override ProductCategory GetCategory() { return decoratedProduct.GetCategory(); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Enums/OrderStatus.cs ================================================ enum OrderStatus { PENDING_PAYMENT, PLACED, SHIPPED, DELIVERED, CANCELLED, RETURNED } ================================================ FILE: solutions/csharp/onlineshoppingservice/Enums/ProductCategory.cs ================================================ enum ProductCategory { ELECTRONICS, BOOKS, CLOTHING, HOME_GOODS, GROCERY } ================================================ FILE: solutions/csharp/onlineshoppingservice/Exceptions/OutOfStockException.cs ================================================ class OutOfStockException : Exception { public OutOfStockException(string message) : base(message) { } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/Account.cs ================================================ class Account { private readonly string username; private readonly string password; private readonly ShoppingCart cart; public Account(string username, string password) { this.username = username; this.password = password; this.cart = new ShoppingCart(); } public ShoppingCart GetCart() { return cart; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/Address.cs ================================================ class Address { private readonly string street; private readonly string city; private readonly string state; private readonly string zipCode; public Address(string street, string city, string state, string zipCode) { this.street = street; this.city = city; this.state = state; this.zipCode = zipCode; } public override string ToString() { return $"{street}, {city}, {state} {zipCode}"; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/CartItem.cs ================================================ class CartItem { private readonly Product product; private int quantity; public CartItem(Product product, int quantity) { this.product = product; this.quantity = quantity; } public Product GetProduct() { return product; } public int GetQuantity() { return quantity; } public void IncrementQuantity(int amount) { quantity += amount; } public double GetPrice() { return product.GetPrice() * quantity; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/Customer.cs ================================================ class Customer : IOrderObserver { private readonly string id; private readonly string name; private readonly string email; private readonly Account account; private Address shippingAddress; public Customer(string name, string email, string password, Address shippingAddress) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; this.account = new Account(email, password); this.shippingAddress = shippingAddress; } public void Update(Order order) { Console.WriteLine($"[Notification for {name}]: Your order #{order.GetId()} status has been updated to: {order.GetStatus()}."); } public string GetId() { return id; } public string GetName() { return name; } public Account GetAccount() { return account; } public Address GetShippingAddress() { return shippingAddress; } public void SetShippingAddress(Address address) { shippingAddress = address; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/Order.cs ================================================ class Order : Subject { private readonly string id; private readonly Customer customer; private readonly List items; private readonly Address shippingAddress; private readonly double totalAmount; private readonly DateTime orderDate; private OrderStatus status; private IOrderState currentState; public Order(Customer customer, List items, Address shippingAddress, double totalAmount) { this.id = Guid.NewGuid().ToString().Substring(0, 8); this.customer = customer; this.items = items; this.shippingAddress = shippingAddress; this.totalAmount = totalAmount; this.orderDate = DateTime.Now; this.status = OrderStatus.PLACED; this.currentState = new PlacedState(); AddObserver(customer); } public void ShipOrder() { currentState.Ship(this); } public void DeliverOrder() { currentState.Deliver(this); } public void CancelOrder() { currentState.Cancel(this); } public string GetId() { return id; } public OrderStatus GetStatus() { return status; } public void SetState(IOrderState state) { currentState = state; } public void SetStatus(OrderStatus status) { this.status = status; NotifyObservers(this); } public List GetItems() { return items; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/OrderLineItem.cs ================================================ class OrderLineItem { private readonly string productId; private readonly string productName; private readonly int quantity; private readonly double priceAtPurchase; public OrderLineItem(string productId, string productName, int quantity, double priceAtPurchase) { this.productId = productId; this.productName = productName; this.quantity = quantity; this.priceAtPurchase = priceAtPurchase; } public string GetProductId() { return productId; } public int GetQuantity() { return quantity; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/Product.cs ================================================ abstract class Product { protected string id; protected string name; protected string description; protected double price; protected ProductCategory category; public abstract string GetId(); public abstract string GetName(); public abstract string GetDescription(); public abstract double GetPrice(); public abstract ProductCategory GetCategory(); } class BaseProduct : Product { public BaseProduct(string id, string name, string description, double price, ProductCategory category) { this.id = id; this.name = name; this.description = description; this.price = price; this.category = category; } public override string GetId() { return id; } public override string GetName() { return name; } public override string GetDescription() { return description; } public override double GetPrice() { return price; } public override ProductCategory GetCategory() { return category; } } class ProductBuilder { private readonly string name; private readonly double price; private string description = ""; private ProductCategory category; public ProductBuilder(string name, double price) { this.name = name; this.price = price; } public ProductBuilder WithDescription(string description) { this.description = description; return this; } public ProductBuilder WithCategory(ProductCategory category) { this.category = category; return this; } public Product Build() { return new BaseProduct(Guid.NewGuid().ToString(), name, description, price, category); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Models/ShoppingCart.cs ================================================ class ShoppingCart { private readonly Dictionary items = new Dictionary(); public void AddItem(Product product, int quantity) { if (items.ContainsKey(product.GetId())) { items[product.GetId()].IncrementQuantity(quantity); } else { items[product.GetId()] = new CartItem(product, quantity); } } public void RemoveItem(string productId) { items.Remove(productId); } public Dictionary GetItems() { return new Dictionary(items); } public double CalculateTotal() { return items.Values.Sum(item => item.GetPrice()); } public void ClearCart() { items.Clear(); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Observer/IOrderObserver.cs ================================================ interface IOrderObserver { void Update(Order order); } ================================================ FILE: solutions/csharp/onlineshoppingservice/Observer/Subject.cs ================================================ abstract class Subject { private readonly List observers = new List(); public void AddObserver(IOrderObserver observer) { observers.Add(observer); } public void RemoveObserver(IOrderObserver observer) { observers.Remove(observer); } public void NotifyObservers(Order order) { foreach (var observer in observers) { observer.Update(order); } } } ================================================ FILE: solutions/csharp/onlineshoppingservice/OnlineShoppingDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class OnlineShoppingDemo { public static void Main() { // System Setup (Singleton and Services) var system = OnlineShoppingSystem.GetInstance(); // Create and Add Products to Catalog (Builder Pattern) var laptop = new ProductBuilder("Dell XPS 15", 1499.99) .WithDescription("A powerful and sleek laptop.") .WithCategory(ProductCategory.ELECTRONICS) .Build(); var book = new ProductBuilder("The Pragmatic Programmer", 45.50) .WithDescription("A classic book for software developers.") .WithCategory(ProductCategory.BOOKS) .Build(); system.AddProduct(laptop, 10); // 10 laptops in stock system.AddProduct(book, 50); // 50 books in stock // Register a Customer var aliceAddress = new Address("123 Main St", "Anytown", "CA", "12345"); var alice = system.RegisterCustomer("Alice", "alice@example.com", "password123", aliceAddress); // Alice Shops Console.WriteLine("--- Alice starts shopping ---"); // Alice adds a laptop to her cart system.AddToCart(alice.GetId(), laptop.GetId(), 1); Console.WriteLine("Alice added a laptop to her cart."); // Alice decides to gift-wrap the book (Decorator Pattern) var giftWrappedBook = new GiftWrapDecorator(book); system.AddToCart(alice.GetId(), giftWrappedBook.GetId(), 1); Console.WriteLine($"Alice added a gift-wrapped book. Original price: ${book.GetPrice():F2}, New price: ${giftWrappedBook.GetPrice():F2}"); var aliceCart = system.GetCustomerCart(alice.GetId()); Console.WriteLine($"Alice's cart total: ${aliceCart.CalculateTotal():F2}"); // Alice Checks Out Console.WriteLine("\n--- Alice proceeds to checkout ---"); var aliceOrder = system.PlaceOrder(alice.GetId(), new CreditCardPaymentStrategy("1234-5678-9876-5432")); if (aliceOrder == null) { Console.WriteLine("Order placement failed."); return; } Console.WriteLine($"Order #{aliceOrder.GetId()} placed successfully for Alice."); // Order State and Notifications (State, Observer Patterns) Console.WriteLine("\n--- Order processing starts ---"); // The warehouse ships the order aliceOrder.ShipOrder(); // This will trigger a notification to Alice // The delivery service marks the order as delivered aliceOrder.DeliverOrder(); // This will also trigger a notification // Try to cancel a delivered order (State pattern prevents this) aliceOrder.CancelOrder(); Console.WriteLine("\n--- Out of Stock Scenario ---"); var bob = system.RegisterCustomer("Bob", "bob@example.com", "pass123", aliceAddress); // Bob tries to buy 15 laptops, but only 9 are left (1 was bought by Alice) system.AddToCart(bob.GetId(), laptop.GetId(), 15); var bobOrder = system.PlaceOrder(bob.GetId(), new UPIPaymentStrategy("testupi@hdfc")); if (bobOrder == null) { Console.WriteLine("Bob's order was correctly prevented due to insufficient stock."); } } } ================================================ FILE: solutions/csharp/onlineshoppingservice/OnlineShoppingSystem.cs ================================================ class OnlineShoppingSystem { private static volatile OnlineShoppingSystem instance; private static readonly object syncRoot = new object(); private readonly Dictionary products = new Dictionary(); private readonly Dictionary customers = new Dictionary(); private readonly Dictionary orders = new Dictionary(); private readonly InventoryService inventoryService; private readonly PaymentService paymentService; private readonly OrderService orderService; private readonly SearchService searchService; private OnlineShoppingSystem() { inventoryService = new InventoryService(); paymentService = new PaymentService(); orderService = new OrderService(inventoryService); searchService = new SearchService(products.Values); } public static OnlineShoppingSystem GetInstance() { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new OnlineShoppingSystem(); } } } return instance; } public void AddProduct(Product product, int initialStock) { products[product.GetId()] = product; inventoryService.AddStock(product, initialStock); } public Customer RegisterCustomer(string name, string email, string password, Address address) { var customer = new Customer(name, email, password, address); customers[customer.GetId()] = customer; return customer; } public void AddToCart(string customerId, string productId, int quantity) { var customer = customers[customerId]; var product = products[productId]; customer.GetAccount().GetCart().AddItem(product, quantity); } public ShoppingCart GetCustomerCart(string customerId) { var customer = customers[customerId]; return customer.GetAccount().GetCart(); } public List SearchProducts(string name) { return searchService.SearchByName(name); } public Order PlaceOrder(string customerId, IPaymentStrategy paymentStrategy) { var customer = customers[customerId]; var cart = customer.GetAccount().GetCart(); if (!cart.GetItems().Any()) { Console.WriteLine("Cannot place an order with an empty cart."); return null; } // 1. Process payment bool paymentSuccess = paymentService.ProcessPayment(paymentStrategy, cart.CalculateTotal()); if (!paymentSuccess) { Console.WriteLine("Payment failed. Please try again."); return null; } // 2. Create order and update inventory try { var order = orderService.CreateOrder(customer, cart); orders[order.GetId()] = order; // 3. Clear the cart cart.ClearCart(); return order; } catch (Exception e) { Console.WriteLine($"Order placement failed: {e.Message}"); return null; } } } ================================================ FILE: solutions/csharp/onlineshoppingservice/README.md ================================================ # Designing an Online Shopping System Like Amazon ## Requirements 1. The online shopping service should allow users to browse products, add them to the shopping cart, and place orders. 2. The system should support multiple product categories and provide search functionality. 3. Users should be able to manage their profiles, view order history, and track order status. 4. The system should handle inventory management and update product availability accordingly. 5. The system should support multiple payment methods and ensure secure transactions. 6. The system should handle concurrent user requests and ensure data consistency. 7. The system should be scalable to handle a large number of products and users. 8. The system should provide a user-friendly interface for a seamless shopping experience. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online shopping service, with properties such as ID, name, email, password, and a list of orders. 2. The **Product** class represents a product available for purchase, with properties like ID, name, description, price, and quantity. It provides methods to update the quantity and check product availability. 3. The **Order** class represents an order placed by a user, containing properties such as ID, user, order items, total amount, and order status. It calculates the total amount based on the order items. 4. The **OrderItem** class represents an item within an order, consisting of the product and the quantity ordered. 5. The **OrderStatus** enum represents the different statuses an order can have, such as pending, processing, shipped, delivered, or cancelled. 6. The **ShoppingCart** class represents the user's shopping cart, allowing them to add, remove, and update item quantities. It maintains a map of product IDs and order items. 7. The **Payment** interface defines the contract for processing payments, with a concrete implementation CreditCardPayment. 8. The **OnlineShoppingService** class is the central component of the online shopping service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register users, add products, search products, place orders, and retrieve order information. It handles concurrent access to shared resources using synchronization. 9. The **OnlineShoppingServiceDemo** class demonstrates the usage of the online shopping service by registering users, adding products, searching for products, placing orders, and viewing order history. ================================================ FILE: solutions/csharp/onlineshoppingservice/Services/InventoryService.cs ================================================ class InventoryService { private readonly Dictionary stock = new Dictionary(); private readonly object lockObj = new object(); public void AddStock(Product product, int quantity) { lock (lockObj) { if (!stock.ContainsKey(product.GetId())) { stock[product.GetId()] = 0; } stock[product.GetId()] += quantity; } } public void UpdateStockForOrder(List items) { lock (lockObj) { // First, check if all items are in stock foreach (var item in items) { if (!stock.ContainsKey(item.GetProductId()) || stock[item.GetProductId()] < item.GetQuantity()) { throw new OutOfStockException($"Not enough stock for product ID: {item.GetProductId()}"); } } // If all checks pass, deduct the stock foreach (var item in items) { stock[item.GetProductId()] -= item.GetQuantity(); } } } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Services/OrderService.cs ================================================ class OrderService { private readonly InventoryService inventoryService; public OrderService(InventoryService inventoryService) { this.inventoryService = inventoryService; } public Order CreateOrder(Customer customer, ShoppingCart cart) { var orderItems = cart.GetItems().Values .Select(cartItem => new OrderLineItem( cartItem.GetProduct().GetId(), cartItem.GetProduct().GetName(), cartItem.GetQuantity(), cartItem.GetProduct().GetPrice())) .ToList(); inventoryService.UpdateStockForOrder(orderItems); return new Order(customer, orderItems, customer.GetShippingAddress(), cart.CalculateTotal()); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Services/PaymentService.cs ================================================ class PaymentService { public bool ProcessPayment(IPaymentStrategy strategy, double amount) { return strategy.Pay(amount); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Services/SearchService.cs ================================================ class SearchService { private readonly ICollection productCatalog; public SearchService(ICollection productCatalog) { this.productCatalog = productCatalog; } public List SearchByName(string name) { return productCatalog .Where(p => p.GetName().ToLower().Contains(name.ToLower())) .ToList(); } public List SearchByCategory(ProductCategory category) { return productCatalog .Where(p => p.GetCategory() == category) .ToList(); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/States/CancelledState.cs ================================================ class CancelledState : IOrderState { public void Ship(Order order) { Console.WriteLine("Cannot ship a cancelled order."); } public void Deliver(Order order) { Console.WriteLine("Cannot deliver a cancelled order."); } public void Cancel(Order order) { Console.WriteLine("Order is already cancelled."); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/States/DeliveredState.cs ================================================ class DeliveredState : IOrderState { public void Ship(Order order) { Console.WriteLine("Order already delivered."); } public void Deliver(Order order) { Console.WriteLine("Order already delivered."); } public void Cancel(Order order) { Console.WriteLine("Cannot cancel a delivered order."); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/States/IOrderState.cs ================================================ interface IOrderState { void Ship(Order order); void Deliver(Order order); void Cancel(Order order); } ================================================ FILE: solutions/csharp/onlineshoppingservice/States/PlacedState.cs ================================================ class PlacedState : IOrderState { public void Ship(Order order) { Console.WriteLine($"Shipping order {order.GetId()}"); order.SetStatus(OrderStatus.SHIPPED); order.SetState(new ShippedState()); } public void Deliver(Order order) { Console.WriteLine("Cannot deliver an order that has not been shipped."); } public void Cancel(Order order) { Console.WriteLine($"Cancelling order {order.GetId()}"); order.SetStatus(OrderStatus.CANCELLED); order.SetState(new CancelledState()); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/States/ShippedState.cs ================================================ class ShippedState : IOrderState { public void Ship(Order order) { Console.WriteLine("Order is already shipped."); } public void Deliver(Order order) { Console.WriteLine($"Delivering order {order.GetId()}"); order.SetStatus(OrderStatus.DELIVERED); order.SetState(new DeliveredState()); } public void Cancel(Order order) { Console.WriteLine("Cannot cancel a shipped order."); } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Strategy/CreditCardPaymentStrategy.cs ================================================ class CreditCardPaymentStrategy : IPaymentStrategy { private readonly string cardNumber; public CreditCardPaymentStrategy(string cardNumber) { this.cardNumber = cardNumber; } public bool Pay(double amount) { Console.WriteLine($"Processing credit card payment of ${amount:F2} with card {cardNumber}."); return true; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/Strategy/IPaymentStrategy.cs ================================================ interface IPaymentStrategy { bool Pay(double amount); } ================================================ FILE: solutions/csharp/onlineshoppingservice/Strategy/UPIPaymentStrategy.cs ================================================ class UPIPaymentStrategy : IPaymentStrategy { private readonly string upiId; public UPIPaymentStrategy(string upiId) { this.upiId = upiId; } public bool Pay(double amount) { Console.WriteLine($"Processing UPI payment of ${amount:F2} with upi id {upiId}."); return true; } } ================================================ FILE: solutions/csharp/onlineshoppingservice/onlineshoppingservice.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Commands/BuyStockCommand.cs ================================================ class BuyStockCommand : IOrderCommand { private readonly Account account; private readonly Order order; private readonly StockExchange stockExchange; public BuyStockCommand(Account account, Order order) { this.account = account; this.order = order; this.stockExchange = StockExchange.GetInstance(); } public void Execute() { double estimatedCost = order.GetQuantity() * order.GetPrice(); if (order.GetOrderType() == OrderType.LIMIT && account.GetBalance() < estimatedCost) { throw new InsufficientFundsException("Not enough cash to place limit buy order."); } Console.WriteLine($"Placing BUY order {order.GetOrderId()} for {order.GetQuantity()} shares of {order.GetStock().GetSymbol()}."); stockExchange.PlaceBuyOrder(order); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Commands/IOrderCommand.cs ================================================ interface IOrderCommand { void Execute(); } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Commands/SellStockCommand.cs ================================================ class SellStockCommand : IOrderCommand { private readonly Account account; private readonly Order order; private readonly StockExchange stockExchange; public SellStockCommand(Account account, Order order) { this.account = account; this.order = order; this.stockExchange = StockExchange.GetInstance(); } public void Execute() { if (account.GetStockQuantity(order.GetStock().GetSymbol()) < order.GetQuantity()) { throw new InsufficientStockException("Not enough stock to place sell order."); } Console.WriteLine($"Placing SELL order {order.GetOrderId()} for {order.GetQuantity()} shares of {order.GetStock().GetSymbol()}."); stockExchange.PlaceSellOrder(order); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Enums/OrderStatus.cs ================================================ enum OrderStatus { OPEN, PARTIALLY_FILLED, FILLED, CANCELLED, FAILED } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Enums/OrderType.cs ================================================ enum OrderType { MARKET, LIMIT } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Enums/TransactionType.cs ================================================ enum TransactionType { BUY, SELL } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Exceptions/InsufficientFundsException.cs ================================================ class InsufficientFundsException : Exception { public InsufficientFundsException(string message) : base(message) { } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Exceptions/InsufficientStockException.cs ================================================ class InsufficientStockException : Exception { public InsufficientStockException(string message) : base(message) { } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Models/Account.cs ================================================ class Account { private double balance; private readonly Dictionary portfolio; // Stock symbol -> quantity private readonly object lockObj = new object(); public Account(double initialCash) { this.balance = initialCash; this.portfolio = new Dictionary(); } public void Debit(double amount) { lock (lockObj) { if (balance < amount) { throw new InsufficientFundsException($"Insufficient funds to debit {amount}"); } balance -= amount; } } public void Credit(double amount) { lock (lockObj) { balance += amount; } } public void AddStock(string symbol, int quantity) { lock (lockObj) { if (!portfolio.ContainsKey(symbol)) { portfolio[symbol] = 0; } portfolio[symbol] += quantity; } } public void RemoveStock(string symbol, int quantity) { lock (lockObj) { int currentQuantity = portfolio.ContainsKey(symbol) ? portfolio[symbol] : 0; if (currentQuantity < quantity) { throw new InsufficientStockException($"Not enough {symbol} stock to sell."); } portfolio[symbol] = currentQuantity - quantity; } } public double GetBalance() { return balance; } public Dictionary GetPortfolio() { return new Dictionary(portfolio); } public int GetStockQuantity(string symbol) { return portfolio.ContainsKey(symbol) ? portfolio[symbol] : 0; } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Models/Order.cs ================================================ class Order { private readonly string orderId; private readonly User user; private readonly Stock stock; private readonly OrderType type; private readonly int quantity; private readonly double price; // Limit price for Limit orders private OrderStatus status; private readonly User owner; private IOrderState currentState; private readonly IExecutionStrategy executionStrategy; public Order(string orderId, User user, Stock stock, OrderType type, int quantity, double price, IExecutionStrategy strategy, User owner) { this.orderId = orderId; this.user = user; this.stock = stock; this.type = type; this.quantity = quantity; this.price = price; this.executionStrategy = strategy; this.owner = owner; this.currentState = new OpenState(); // Initial state this.status = OrderStatus.OPEN; } public void Cancel() { currentState.Cancel(this); } // Getters public string GetOrderId() { return orderId; } public User GetUser() { return user; } public Stock GetStock() { return stock; } public OrderType GetOrderType() { return type; } public int GetQuantity() { return quantity; } public double GetPrice() { return price; } public OrderStatus GetStatus() { return status; } public IExecutionStrategy GetExecutionStrategy() { return executionStrategy; } // Setters for state transitions public void SetState(IOrderState state) { this.currentState = state; } public void SetStatus(OrderStatus status) { this.status = status; NotifyOwner(); } private void NotifyOwner() { if (owner != null) { owner.OrderStatusUpdate(this); } } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Models/OrderBuilder.cs ================================================ class OrderBuilder { private User user; private Stock stock; private OrderType type; private TransactionType transactionType; private int quantity; private double price; public OrderBuilder ForUser(User user) { this.user = user; return this; } public OrderBuilder WithStock(Stock stock) { this.stock = stock; return this; } public OrderBuilder Buy(int quantity) { this.transactionType = TransactionType.BUY; this.quantity = quantity; return this; } public OrderBuilder Sell(int quantity) { this.transactionType = TransactionType.SELL; this.quantity = quantity; return this; } public OrderBuilder AtMarketPrice() { this.type = OrderType.MARKET; this.price = 0; // Not needed for market order return this; } public OrderBuilder WithLimit(double limitPrice) { this.type = OrderType.LIMIT; this.price = limitPrice; return this; } public Order Build() { IExecutionStrategy strategy = type == OrderType.MARKET ? (IExecutionStrategy) new MarketOrderStrategy() : (IExecutionStrategy) new LimitOrderStrategy(transactionType); return new Order( Guid.NewGuid().ToString(), user, stock, type, quantity, price, strategy, user ); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Models/Stock.cs ================================================ class Stock { private readonly string symbol; private double price; private readonly List observers = new List(); public Stock(string symbol, double initialPrice) { this.symbol = symbol; this.price = initialPrice; } public string GetSymbol() { return symbol; } public double GetPrice() { return price; } public void SetPrice(double newPrice) { if (this.price != newPrice) { this.price = newPrice; NotifyObservers(); } } public void AddObserver(IStockObserver observer) { observers.Add(observer); } public void RemoveObserver(IStockObserver observer) { observers.Remove(observer); } private void NotifyObservers() { foreach (var observer in observers) { observer.Update(this); } } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Models/User.cs ================================================ class User : IStockObserver { private readonly string userId; private readonly string name; private readonly Account account; public User(string name, double initialCash) { this.userId = Guid.NewGuid().ToString(); this.name = name; this.account = new Account(initialCash); } public string GetUserId() { return userId; } public string GetName() { return name; } public Account GetAccount() { return account; } public void Update(Stock stock) { Console.WriteLine($"[Notification for {name}] Stock {stock.GetSymbol()} price updated to: ${stock.GetPrice():F2}"); } public void OrderStatusUpdate(Order order) { Console.WriteLine($"[Order Notification for {name}] Order {order.GetOrderId()} for {order.GetStock().GetSymbol()} is now {order.GetStatus()}."); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Observer/IStockObserver.cs ================================================ interface IStockObserver { void Update(Stock stock); } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/README.md ================================================ # Designing an Online Stock Brokerage System ## Requirements 1. The online stock brokerage system should allow users to create and manage their trading accounts. 2. Users should be able to buy and sell stocks, as well as view their portfolio and transaction history. 3. The system should provide real-time stock quotes and market data to users. 4. The system should handle order placement, execution, and settlement processes. 5. The system should enforce various business rules and validations, such as checking account balances and stock availability. 6. The system should handle concurrent user requests and ensure data consistency and integrity. 7. The system should be scalable and able to handle a large number of users and transactions. 8. The system should be secure and protect sensitive user information. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the stock brokerage system, with properties such as user ID, name, and email. 2. The **Account** class represents a user's trading account, with properties like account ID, associated user, and balance. It provides methods for depositing and withdrawing funds. 3. The **Stock** class represents a stock that can be traded, with properties such as symbol, name, and price. It provides a method for updating the stock price. 4. The **Order** class is an abstract base class representing an order placed by a user. It contains common properties such as order ID, associated account, stock, quantity, price, and order status. The execute() method is declared as abstract, to be implemented by concrete order classes. 5. The **BuyOrder** and **SellOrder** classes are concrete implementations of the Order class, representing buy and sell orders respectively. They provide the implementation for the execute() method specific to each order type. 6. The **OrderStatus** enum represents the possible statuses of an order, such as PENDING, EXECUTED, or REJECTED. 7. The **Portfolio** class represents a user's portfolio, which holds the stocks owned by the user. It provides methods for adding and removing stocks from the portfolio. 8. The **StockBroker** class is the central component of the stock brokerage system. It follows the Singleton pattern to ensure a single instance of the stock broker. It manages user accounts, stocks, and order processing. It provides methods for creating accounts, adding stocks, placing orders, and processing orders. 9. The **InsufficientFundsException** and **InsufficientStockException** classes are custom exceptions used to handle insufficient funds and insufficient stock scenarios respectively. 10. The **StockBrokerageSystem** class serves as the entry point of the application and demonstrates the usage of the stock brokerage system. ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/States/CancelledState.cs ================================================ class CancelledState : IOrderState { public void Handle(Order order) { Console.WriteLine("Order is cancelled."); } public void Cancel(Order order) { Console.WriteLine("Order is already cancelled."); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/States/FilledState.cs ================================================ class FilledState : IOrderState { public void Handle(Order order) { Console.WriteLine("Order is already filled."); } public void Cancel(Order order) { Console.WriteLine("Cannot cancel a filled order."); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/States/IOrderState.cs ================================================ interface IOrderState { void Handle(Order order); void Cancel(Order order); } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/States/OpenState.cs ================================================ class OpenState : IOrderState { public void Handle(Order order) { Console.WriteLine("Order is open and waiting for execution."); } public void Cancel(Order order) { order.SetStatus(OrderStatus.CANCELLED); order.SetState(new CancelledState()); Console.WriteLine($"Order {order.GetOrderId()} has been cancelled."); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/StockBrokerageSystem.cs ================================================ class StockBrokerageSystem { private static volatile StockBrokerageSystem instance; private static readonly object syncRoot = new object(); private readonly Dictionary users; private readonly Dictionary stocks; private StockBrokerageSystem() { this.users = new Dictionary(); this.stocks = new Dictionary(); } public static StockBrokerageSystem GetInstance() { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new StockBrokerageSystem(); } } } return instance; } public User RegisterUser(string name, double initialAmount) { var user = new User(name, initialAmount); users[user.GetUserId()] = user; return user; } public Stock AddStock(string symbol, double initialPrice) { var stock = new Stock(symbol, initialPrice); stocks[stock.GetSymbol()] = stock; return stock; } public void PlaceBuyOrder(Order order) { var user = order.GetUser(); IOrderCommand command = new BuyStockCommand(user.GetAccount(), order); command.Execute(); } public void PlaceSellOrder(Order order) { var user = order.GetUser(); IOrderCommand command = new SellStockCommand(user.GetAccount(), order); command.Execute(); } public void CancelOrder(Order order) { order.Cancel(); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/StockBrokerageSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class StockBrokerageSystemDemo { public static void Main(string[] args) { // System Setup var system = StockBrokerageSystem.GetInstance(); // Create Stocks var apple = system.AddStock("AAPL", 150.00); var google = system.AddStock("GOOG", 2800.00); // Create Members (Users) var alice = system.RegisterUser("Alice", 20000.00); var bob = system.RegisterUser("Bob", 25000.00); // Bob already owns some Apple stock bob.GetAccount().AddStock("AAPL", 50); // Members subscribe to stock notifications (Observer Pattern) apple.AddObserver(alice); google.AddObserver(alice); apple.AddObserver(bob); Console.WriteLine("--- Initial State ---"); PrintAccountStatus(alice); PrintAccountStatus(bob); Console.WriteLine("\n--- Trading Simulation Starts ---\n"); // SCENARIO 1: Limit Order Match Console.WriteLine("--- SCENARIO 1: Alice places a limit buy, Bob places a limit sell that matches ---"); // Alice wants to buy 10 shares of AAPL if the price is $150.50 or less var aliceBuyOrder = new OrderBuilder() .ForUser(alice) .Buy(10) .WithStock(apple) .WithLimit(150.50) .Build(); system.PlaceBuyOrder(aliceBuyOrder); // Bob wants to sell 20 of his shares if the price is $150.50 or more var bobSellOrder = new OrderBuilder() .ForUser(bob) .Sell(20) .WithStock(apple) .WithLimit(150.50) .Build(); system.PlaceSellOrder(bobSellOrder); // The exchange will automatically match and execute this trade. Thread.Sleep(100); // Give time for notifications to print Console.WriteLine("\n--- Account Status After Trade 1 ---"); PrintAccountStatus(alice); PrintAccountStatus(bob); // SCENARIO 2: Price Update triggers notifications Console.WriteLine("\n--- SCENARIO 2: Market price of GOOG changes ---"); google.SetPrice(2850.00); // Alice will get a notification // SCENARIO 3: Order Cancellation (State Pattern) Console.WriteLine("\n--- SCENARIO 3: Alice places an order and then cancels it ---"); var aliceCancelOrder = new OrderBuilder() .ForUser(alice) .Buy(5) .WithStock(google) .WithLimit(2700.00) // Price is too low, so it won't execute immediately .Build(); system.PlaceBuyOrder(aliceCancelOrder); Console.WriteLine($"Order status before cancellation: {aliceCancelOrder.GetStatus()}"); system.CancelOrder(aliceCancelOrder); Console.WriteLine($"Order status after cancellation attempt: {aliceCancelOrder.GetStatus()}"); // Now try to cancel an already filled order Console.WriteLine("\n--- Trying to cancel an already FILLED order (State Pattern) ---"); Console.WriteLine($"Bob's sell order status: {bobSellOrder.GetStatus()}"); system.CancelOrder(bobSellOrder); // This should fail Console.WriteLine($"Bob's sell order status after cancel attempt: {bobSellOrder.GetStatus()}"); } private static void PrintAccountStatus(User user) { var portfolio = user.GetAccount().GetPortfolio(); var portfolioStr = string.Join(", ", portfolio.Select(kvp => $"{kvp.Key}: {kvp.Value}")); Console.WriteLine($"Member: {user.GetName()}, Cash: ${user.GetAccount().GetBalance():F2}, Portfolio: {{{portfolioStr}}}"); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/StockExchange.cs ================================================ class StockExchange { private static volatile StockExchange instance; private static readonly object syncRoot = new object(); private readonly Dictionary> buyOrders; private readonly Dictionary> sellOrders; private readonly object matchLock = new object(); private StockExchange() { this.buyOrders = new Dictionary>(); this.sellOrders = new Dictionary>(); } public static StockExchange GetInstance() { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new StockExchange(); } } } return instance; } public void PlaceBuyOrder(Order order) { if (!buyOrders.ContainsKey(order.GetStock().GetSymbol())) { buyOrders[order.GetStock().GetSymbol()] = new List(); } buyOrders[order.GetStock().GetSymbol()].Add(order); MatchOrders(order.GetStock()); } public void PlaceSellOrder(Order order) { if (!sellOrders.ContainsKey(order.GetStock().GetSymbol())) { sellOrders[order.GetStock().GetSymbol()] = new List(); } sellOrders[order.GetStock().GetSymbol()].Add(order); MatchOrders(order.GetStock()); } private void MatchOrders(Stock stock) { lock (matchLock) // Critical section to prevent race conditions during matching { var buys = buyOrders.ContainsKey(stock.GetSymbol()) ? buyOrders[stock.GetSymbol()] : new List(); var sells = sellOrders.ContainsKey(stock.GetSymbol()) ? sellOrders[stock.GetSymbol()] : new List(); if (!buys.Any() || !sells.Any()) return; bool matchFound; do { matchFound = false; var bestBuy = FindBestBuy(buys); var bestSell = FindBestSell(sells); if (bestBuy != null && bestSell != null) { double buyPrice = bestBuy.GetOrderType() == OrderType.MARKET ? stock.GetPrice() : bestBuy.GetPrice(); double sellPrice = bestSell.GetOrderType() == OrderType.MARKET ? stock.GetPrice() : bestSell.GetPrice(); if (buyPrice >= sellPrice) { ExecuteTrade(bestBuy, bestSell, sellPrice); // Trade at the seller's asking price matchFound = true; } } } while (matchFound); } } private void ExecuteTrade(Order buyOrder, Order sellOrder, double tradePrice) { Console.WriteLine($"--- Executing Trade for {buyOrder.GetStock().GetSymbol()} at ${tradePrice:F2} ---"); var buyer = buyOrder.GetUser(); var seller = sellOrder.GetUser(); int tradeQuantity = Math.Min(buyOrder.GetQuantity(), sellOrder.GetQuantity()); double totalCost = tradeQuantity * tradePrice; // Perform transaction buyer.GetAccount().Debit(totalCost); buyer.GetAccount().AddStock(buyOrder.GetStock().GetSymbol(), tradeQuantity); seller.GetAccount().Credit(totalCost); seller.GetAccount().RemoveStock(sellOrder.GetStock().GetSymbol(), tradeQuantity); // Update orders UpdateOrderStatus(buyOrder, tradeQuantity); UpdateOrderStatus(sellOrder, tradeQuantity); // Update stock's market price to last traded price buyOrder.GetStock().SetPrice(tradePrice); Console.WriteLine("--- Trade Complete ---"); } private void UpdateOrderStatus(Order order, int quantityTraded) { // This is a simplified update logic. A real system would handle partial fills. order.SetStatus(OrderStatus.FILLED); order.SetState(new FilledState()); string stockSymbol = order.GetStock().GetSymbol(); // Remove from books if (buyOrders.ContainsKey(stockSymbol)) buyOrders[stockSymbol].Remove(order); if (sellOrders.ContainsKey(stockSymbol)) sellOrders[stockSymbol].Remove(order); } private Order FindBestBuy(List buys) { return buys .Where(o => o.GetStatus() == OrderStatus.OPEN) .OrderByDescending(o => o.GetPrice()) // Highest limit price is best .FirstOrDefault(); } private Order FindBestSell(List sells) { return sells .Where(o => o.GetStatus() == OrderStatus.OPEN) .OrderBy(o => o.GetPrice()) // Lowest limit price is best .FirstOrDefault(); } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Strategy/IExecutionStrategy.cs ================================================ interface IExecutionStrategy { bool CanExecute(Order order, double marketPrice); } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Strategy/LimitOrderStrategy.cs ================================================ class LimitOrderStrategy : IExecutionStrategy { private readonly TransactionType type; public LimitOrderStrategy(TransactionType type) { this.type = type; } public bool CanExecute(Order order, double marketPrice) { if (type == TransactionType.BUY) { // Buy if market price is less than or equal to limit price return marketPrice <= order.GetPrice(); } else // SELL { // Sell if market price is greater than or equal to limit price return marketPrice >= order.GetPrice(); } } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/Strategy/MarketOrderStrategy.cs ================================================ class MarketOrderStrategy : IExecutionStrategy { public bool CanExecute(Order order, double marketPrice) { return true; // Market orders can always execute } } ================================================ FILE: solutions/csharp/onlinestockbrokeragesystem/onlinestockbrokeragesystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/parkinglot/Enums/VehicleSize.cs ================================================ enum VehicleSize { SMALL, MEDIUM, LARGE } ================================================ FILE: solutions/csharp/parkinglot/Models/ParkingFloor.cs ================================================ class ParkingFloor { private readonly int floorNumber; private readonly Dictionary spots; private readonly object lockObject = new object(); public ParkingFloor(int floorNumber) { this.floorNumber = floorNumber; this.spots = new Dictionary(); } public void AddSpot(ParkingSpot spot) { spots[spot.GetSpotId()] = spot; } public ParkingSpot FindAvailableSpot(Vehicle vehicle) { lock (lockObject) { var availableSpots = spots.Values .Where(spot => !spot.IsOccupiedSpot() && spot.CanFitVehicle(vehicle)) .OrderBy(spot => (int)spot.GetSpotSize()) .ToList(); return availableSpots.FirstOrDefault(); } } public void DisplayAvailability() { Console.WriteLine($"--- Floor {floorNumber} Availability ---"); var availableCounts = new Dictionary { { VehicleSize.SMALL, 0 }, { VehicleSize.MEDIUM, 0 }, { VehicleSize.LARGE, 0 } }; foreach (var spot in spots.Values) { if (!spot.IsOccupiedSpot()) { availableCounts[spot.GetSpotSize()]++; } } foreach (VehicleSize size in Enum.GetValues(typeof(VehicleSize))) { Console.WriteLine($" {size} spots: {availableCounts[size]}"); } } } ================================================ FILE: solutions/csharp/parkinglot/Models/ParkingSpot.cs ================================================ class ParkingSpot { private readonly string spotId; private readonly VehicleSize spotSize; private bool isOccupied; private Vehicle parkedVehicle; private readonly object lockObject = new object(); public ParkingSpot(string spotId, VehicleSize spotSize) { this.spotId = spotId; this.spotSize = spotSize; this.isOccupied = false; this.parkedVehicle = null; } public string GetSpotId() { return spotId; } public VehicleSize GetSpotSize() { return spotSize; } public bool IsAvailable() { lock (lockObject) { return !isOccupied; } } public bool IsOccupiedSpot() { return isOccupied; } public void ParkVehicle(Vehicle vehicle) { lock (lockObject) { this.parkedVehicle = vehicle; this.isOccupied = true; } } public void UnparkVehicle() { lock (lockObject) { this.parkedVehicle = null; this.isOccupied = false; } } public bool CanFitVehicle(Vehicle vehicle) { if (isOccupied) return false; switch (vehicle.GetSize()) { case VehicleSize.SMALL: return spotSize == VehicleSize.SMALL; case VehicleSize.MEDIUM: return spotSize == VehicleSize.MEDIUM || spotSize == VehicleSize.LARGE; case VehicleSize.LARGE: return spotSize == VehicleSize.LARGE; default: return false; } } } ================================================ FILE: solutions/csharp/parkinglot/Models/ParkingTicket.cs ================================================ class ParkingTicket { private readonly string ticketId; private readonly Vehicle vehicle; private readonly ParkingSpot spot; private readonly long entryTimestamp; private long exitTimestamp; public ParkingTicket(Vehicle vehicle, ParkingSpot spot) { this.ticketId = Guid.NewGuid().ToString(); this.vehicle = vehicle; this.spot = spot; this.entryTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); this.exitTimestamp = 0; } public string GetTicketId() { return ticketId; } public Vehicle GetVehicle() { return vehicle; } public ParkingSpot GetSpot() { return spot; } public long GetEntryTimestamp() { return entryTimestamp; } public long GetExitTimestamp() { return exitTimestamp; } public void SetExitTimestamp() { this.exitTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); } } ================================================ FILE: solutions/csharp/parkinglot/Models/Vehicle.cs ================================================ abstract class Vehicle { protected readonly string licenseNumber; protected readonly VehicleSize size; public Vehicle(string licenseNumber, VehicleSize size) { this.licenseNumber = licenseNumber; this.size = size; } public string GetLicenseNumber() { return licenseNumber; } public VehicleSize GetSize() { return size; } } class Bike : Vehicle { public Bike(string licenseNumber) : base(licenseNumber, VehicleSize.SMALL) { } } class Car : Vehicle { public Car(string licenseNumber) : base(licenseNumber, VehicleSize.MEDIUM) { } } class Truck : Vehicle { public Truck(string licenseNumber) : base(licenseNumber, VehicleSize.LARGE) { } } ================================================ FILE: solutions/csharp/parkinglot/ParkingLot.cs ================================================ using System.Collections.Concurrent; class ParkingLot { private static ParkingLot instance; private static readonly object instanceLock = new object(); private readonly List floors; private readonly ConcurrentDictionary activeTickets; private IFeeStrategy feeStrategy; private IParkingStrategy parkingStrategy; private readonly object mainLock = new object(); private ParkingLot() { floors = new List(); activeTickets = new ConcurrentDictionary(); feeStrategy = new FlatRateFeeStrategy(); parkingStrategy = new NearestFirstStrategy(); } public static ParkingLot GetInstance() { if (instance == null) { lock (instanceLock) { if (instance == null) { instance = new ParkingLot(); } } } return instance; } public void AddFloor(ParkingFloor floor) { floors.Add(floor); } public void SetFeeStrategy(IFeeStrategy feeStrategy) { this.feeStrategy = feeStrategy; } public void SetParkingStrategy(IParkingStrategy parkingStrategy) { this.parkingStrategy = parkingStrategy; } public ParkingTicket ParkVehicle(Vehicle vehicle) { lock (mainLock) { var spot = parkingStrategy.FindSpot(floors, vehicle); if (spot != null) { spot.ParkVehicle(vehicle); var ticket = new ParkingTicket(vehicle, spot); activeTickets.TryAdd(vehicle.GetLicenseNumber(), ticket); Console.WriteLine($"Vehicle {vehicle.GetLicenseNumber()} parked at spot {spot.GetSpotId()}"); return ticket; } else { Console.WriteLine($"No available spot for vehicle {vehicle.GetLicenseNumber()}"); return null; } } } public double? UnparkVehicle(string licenseNumber) { lock (mainLock) { if (!activeTickets.TryRemove(licenseNumber, out ParkingTicket ticket)) { Console.WriteLine($"Ticket not found for vehicle {licenseNumber}"); return null; } ticket.GetSpot().UnparkVehicle(); ticket.SetExitTimestamp(); double fee = feeStrategy.CalculateFee(ticket); Console.WriteLine($"Vehicle {licenseNumber} unparked from spot {ticket.GetSpot().GetSpotId()}"); return fee; } } } ================================================ FILE: solutions/csharp/parkinglot/ParkingLotDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class ParkingLotDemo { public static void Main() { var parkingLot = ParkingLot.GetInstance(); // 1. Initialize the parking lot with floors and spots var floor1 = new ParkingFloor(1); floor1.AddSpot(new ParkingSpot("F1-S1", VehicleSize.SMALL)); floor1.AddSpot(new ParkingSpot("F1-M1", VehicleSize.MEDIUM)); floor1.AddSpot(new ParkingSpot("F1-L1", VehicleSize.LARGE)); var floor2 = new ParkingFloor(2); floor2.AddSpot(new ParkingSpot("F2-M1", VehicleSize.MEDIUM)); floor2.AddSpot(new ParkingSpot("F2-M2", VehicleSize.MEDIUM)); parkingLot.AddFloor(floor1); parkingLot.AddFloor(floor2); parkingLot.SetFeeStrategy(new VehicleBasedFeeStrategy()); // 2. Simulate vehicle entries Console.WriteLine("\n--- Vehicle Entries ---"); floor1.DisplayAvailability(); floor2.DisplayAvailability(); var bike = new Bike("B-123"); var car = new Car("C-456"); var truck = new Truck("T-789"); var bikeTicket = parkingLot.ParkVehicle(bike); var carTicket = parkingLot.ParkVehicle(car); var truckTicket = parkingLot.ParkVehicle(truck); Console.WriteLine("\n--- Availability after parking ---"); floor1.DisplayAvailability(); floor2.DisplayAvailability(); // 3. Simulate another car entry (should go to floor 2) var car2 = new Car("C-999"); var car2Ticket = parkingLot.ParkVehicle(car2); // 4. Simulate a vehicle entry that fails (no available spots) var bike2 = new Bike("B-000"); var failedBikeTicket = parkingLot.ParkVehicle(bike2); // 5. Simulate vehicle exits and fee calculation Console.WriteLine("\n--- Vehicle Exits ---"); if (carTicket != null) { var fee = parkingLot.UnparkVehicle(car.GetLicenseNumber()); if (fee.HasValue) { Console.WriteLine($"Car C-456 unparked. Fee: ${fee.Value:F2}"); } } Console.WriteLine("\n--- Availability after one car leaves ---"); floor1.DisplayAvailability(); floor2.DisplayAvailability(); } } ================================================ FILE: solutions/csharp/parkinglot/README.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot should have multiple levels, each level with a certain number of parking spots. 2. The parking lot should support different types of vehicles, such as cars, motorcycles, and trucks. 3. Each parking spot should be able to accommodate a specific type of vehicle. 4. The system should assign a parking spot to a vehicle upon entry and release it when the vehicle exits. 5. The system should track the availability of parking spots and provide real-time information to customers. 6. The system should handle multiple entry and exit points and support concurrent access. ## Classes, Interfaces and Enumerations 1. The **ParkingLot** class follows the Singleton pattern to ensure only one instance of the parking lot exists. It maintains a list of levels and provides methods to park and unpark vehicles. 2. The **Level** class represents a level in the parking lot and contains a list of parking spots. It handles parking and unparking of vehicles within the level. 3. The **ParkingSpot** class represents an individual parking spot and tracks the availability and the parked vehicle. 4. The **Vehicle** class is an abstract base class for different types of vehicles. It is extended by Car, Motorcycle, and Truck classes. 5. The **VehicleType** enum defines the different types of vehicles supported by the parking lot. 6. Multi-threading is achieved through the use of synchronized keyword on critical sections to ensure thread safety. 7. The **Main** class demonstrates the usage of the parking lot system. ## Design Patterns Used: 1. Singleton Pattern: Ensures only one instance of the ParkingLot class. 2. Factory Pattern (optional extension): Could be used for creating vehicles based on input. 3. Observer Pattern (optional extension): Could notify customers about available spots. ================================================ FILE: solutions/csharp/parkinglot/Strategies/Fee/FlatRateFeeStrategy.cs ================================================ class FlatRateFeeStrategy : IFeeStrategy { private const double RATE_PER_HOUR = 10.0; public double CalculateFee(ParkingTicket parkingTicket) { long duration = parkingTicket.GetExitTimestamp() - parkingTicket.GetEntryTimestamp(); long hours = (duration / (1000 * 60 * 60)) + 1; return hours * RATE_PER_HOUR; } } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Fee/IFeeStrategy.cs ================================================ interface IFeeStrategy { double CalculateFee(ParkingTicket parkingTicket); } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Fee/VehicleBasedFeeStrategy.cs ================================================ class VehicleBasedFeeStrategy : IFeeStrategy { private static readonly Dictionary HOURLY_RATES = new Dictionary { { VehicleSize.SMALL, 10.0 }, { VehicleSize.MEDIUM, 20.0 }, { VehicleSize.LARGE, 30.0 } }; public double CalculateFee(ParkingTicket parkingTicket) { long duration = parkingTicket.GetExitTimestamp() - parkingTicket.GetEntryTimestamp(); long hours = (duration / (1000 * 60 * 60)) + 1; return hours * HOURLY_RATES[parkingTicket.GetVehicle().GetSize()]; } } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Parking/BestFitStrategy.cs ================================================ class BestFitStrategy : IParkingStrategy { public ParkingSpot FindSpot(List floors, Vehicle vehicle) { ParkingSpot bestSpot = null; foreach (var floor in floors) { var spotOnThisFloor = floor.FindAvailableSpot(vehicle); if (spotOnThisFloor != null) { if (bestSpot == null) { bestSpot = spotOnThisFloor; } else { if ((int)spotOnThisFloor.GetSpotSize() < (int)bestSpot.GetSpotSize()) { bestSpot = spotOnThisFloor; } } } } return bestSpot; } } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Parking/FarthestFirstStrategy.cs ================================================ class FarthestFirstStrategy : IParkingStrategy { public ParkingSpot FindSpot(List floors, Vehicle vehicle) { var reversedFloors = floors.AsEnumerable().Reverse().ToList(); foreach (var floor in reversedFloors) { var spot = floor.FindAvailableSpot(vehicle); if (spot != null) { return spot; } } return null; } } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Parking/IParkingStrategy.cs ================================================ interface IParkingStrategy { ParkingSpot FindSpot(List floors, Vehicle vehicle); } ================================================ FILE: solutions/csharp/parkinglot/Strategies/Parking/NearestFirstStrategy.cs ================================================ class NearestFirstStrategy : IParkingStrategy { public ParkingSpot FindSpot(List floors, Vehicle vehicle) { foreach (var floor in floors) { var spot = floor.FindAvailableSpot(vehicle); if (spot != null) { return spot; } } return null; } } ================================================ FILE: solutions/csharp/parkinglot/parkinglot.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/pubsubsystem/Models/Message.cs ================================================ class Message { private readonly string payload; private readonly DateTime timestamp; public Message(string payload) { this.payload = payload; this.timestamp = DateTime.Now; } public string GetPayload() { return payload; } public override string ToString() { return $"Message{{payload='{payload}'}}"; } } ================================================ FILE: solutions/csharp/pubsubsystem/Models/Topic.cs ================================================ class Topic { private readonly string name; private readonly HashSet subscribers; private readonly object subscribersLock = new object(); public Topic(string name) { this.name = name; this.subscribers = new HashSet(); } public string GetName() { return name; } public void AddSubscriber(ISubscriber subscriber) { lock (subscribersLock) { subscribers.Add(subscriber); } } public void RemoveSubscriber(ISubscriber subscriber) { lock (subscribersLock) { subscribers.Remove(subscriber); } } public void Broadcast(Message message) { List currentSubscribers; lock (subscribersLock) { currentSubscribers = new List(subscribers); } List deliveryTasks = new List(); foreach (ISubscriber subscriber in currentSubscribers) { deliveryTasks.Add(Task.Run(() => { try { subscriber.OnMessage(message); } catch (Exception e) { Console.Error.WriteLine($"Error delivering message to subscriber {subscriber.GetId()}: {e.Message}"); } })); } Task.WaitAll(deliveryTasks.ToArray()); } } ================================================ FILE: solutions/csharp/pubsubsystem/PubSubDemo.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; public class PubSubDemo { public static void Main(string[] args) { PubSubService pubSubService = PubSubService.GetInstance(); // --- Create Subscribers --- ISubscriber sportsFan1 = new NewsSubscriber("SportsFan1"); ISubscriber sportsFan2 = new NewsSubscriber("SportsFan2"); ISubscriber techie1 = new NewsSubscriber("Techie1"); ISubscriber allNewsReader = new NewsSubscriber("AllNewsReader"); ISubscriber systemAdmin = new AlertSubscriber("SystemAdmin"); // --- Create Topics and Subscriptions --- const string SPORTS_TOPIC = "SPORTS"; const string TECH_TOPIC = "TECH"; const string WEATHER_TOPIC = "WEATHER"; pubSubService.CreateTopic(SPORTS_TOPIC); pubSubService.CreateTopic(TECH_TOPIC); pubSubService.CreateTopic(WEATHER_TOPIC); pubSubService.Subscribe(SPORTS_TOPIC, sportsFan1); pubSubService.Subscribe(SPORTS_TOPIC, sportsFan2); pubSubService.Subscribe(SPORTS_TOPIC, allNewsReader); pubSubService.Subscribe(SPORTS_TOPIC, systemAdmin); pubSubService.Subscribe(TECH_TOPIC, techie1); pubSubService.Subscribe(TECH_TOPIC, allNewsReader); Console.WriteLine("\n--- Publishing Messages ---"); // --- Publish to SPORTS topic --- pubSubService.Publish(SPORTS_TOPIC, new Message("Team A wins the championship!")); // Expected: SportsFan1, SportsFan2, AllNewsReader, SystemAdmin receive this. // --- Publish to TECH topic --- pubSubService.Publish(TECH_TOPIC, new Message("New AI model released.")); // Expected: Techie1, AllNewsReader receive this. // --- Publish to WEATHER topic (no subscribers) --- pubSubService.Publish(WEATHER_TOPIC, new Message("Sunny with a high of 75°F.")); // Expected: Message is dropped. // Allow some time for async messages to be processed Thread.Sleep(500); Console.WriteLine("\n--- Unsubscribing a user and re-publishing ---"); // SportsFan2 gets tired of sports news pubSubService.Unsubscribe(SPORTS_TOPIC, sportsFan2); // Publish another message to SPORTS pubSubService.Publish(SPORTS_TOPIC, new Message("Major player traded to Team B.")); // Expected: SportsFan1, AllNewsReader, SystemAdmin receive this. SportsFan2 does NOT. // Give messages time to be delivered Thread.Sleep(500); // --- Shutdown the service --- pubSubService.Shutdown(); } } ================================================ FILE: solutions/csharp/pubsubsystem/PubSubService.cs ================================================ using System.Collections.Concurrent; class PubSubService { private static PubSubService instance; private static readonly object instanceLock = new object(); private readonly ConcurrentDictionary topicRegistry; private PubSubService() { topicRegistry = new ConcurrentDictionary(); } public static PubSubService GetInstance() { if (instance == null) { lock (instanceLock) { if (instance == null) { instance = new PubSubService(); } } } return instance; } public void CreateTopic(string topicName) { topicRegistry.TryAdd(topicName, new Topic(topicName)); Console.WriteLine($"Topic {topicName} created"); } public void Subscribe(string topicName, ISubscriber subscriber) { if (!topicRegistry.TryGetValue(topicName, out Topic topic)) { throw new ArgumentException($"Topic not found: {topicName}"); } topic.AddSubscriber(subscriber); Console.WriteLine($"Subscriber '{subscriber.GetId()}' subscribed to topic: {topicName}"); } public void Unsubscribe(string topicName, ISubscriber subscriber) { if (topicRegistry.TryGetValue(topicName, out Topic topic)) { topic.RemoveSubscriber(subscriber); } Console.WriteLine($"Subscriber '{subscriber.GetId()}' unsubscribed from topic: {topicName}"); } public void Publish(string topicName, Message message) { Console.WriteLine($"Publishing message to topic: {topicName}"); if (!topicRegistry.TryGetValue(topicName, out Topic topic)) { throw new ArgumentException($"Topic not found: {topicName}"); } topic.Broadcast(message); } public void Shutdown() { Console.WriteLine("PubSubService shutting down..."); Console.WriteLine("PubSubService shutdown complete."); } } ================================================ FILE: solutions/csharp/pubsubsystem/README.md ================================================ # Designing a Pub-Sub System in Java ## Requirements 1. The Pub-Sub system should allow publishers to publish messages to specific topics. 2. Subscribers should be able to subscribe to topics of interest and receive messages published to those topics. 3. The system should support multiple publishers and subscribers. 4. Messages should be delivered to all subscribers of a topic in real-time. 5. The system should handle concurrent access and ensure thread safety. 6. The Pub-Sub system should be scalable and efficient in terms of message delivery. ## Classes, Interfaces and Enumerations 1. The **Message** class represents a message that can be published and received by subscribers. It contains the message content. 2. The **Topic** class represents a topic to which messages can be published. It maintains a set of subscribers and provides methods to add and remove subscribers, as well as publish messages to all subscribers. 3. The **Subscriber** interface defines the contract for subscribers. It declares the onMessage method that is invoked when a subscriber receives a message. 4. The **PrintSubscriber** class is a concrete implementation of the Subscriber interface. It receives messages and prints them to the console. 5. The **Publisher** class represents a publisher that publishes messages to a specific topic. 6. The **PubSubSystem** class is the main class that manages topics, subscribers, and message publishing. It uses a ConcurrentHashMap to store topics and an ExecutorService to handle concurrent message publishing. 7. The **PubSubDemo** class demonstrates the usage of the Pub-Sub system by creating topics, subscribers, and publishers, and publishing messages. ================================================ FILE: solutions/csharp/pubsubsystem/Subscribers/AlertSubscriber.cs ================================================ class AlertSubscriber : ISubscriber { private readonly string id; public AlertSubscriber(string id) { this.id = id; } public string GetId() { return id; } public void OnMessage(Message message) { Console.WriteLine($"!!! [ALERT - {id}] : '{message.GetPayload()}' !!!"); } } ================================================ FILE: solutions/csharp/pubsubsystem/Subscribers/ISubscriber.cs ================================================ interface ISubscriber { string GetId(); void OnMessage(Message message); } ================================================ FILE: solutions/csharp/pubsubsystem/Subscribers/NewsSubscriber.cs ================================================ class NewsSubscriber : ISubscriber { private readonly string id; public NewsSubscriber(string id) { this.id = id; } public string GetId() { return id; } public void OnMessage(Message message) { Console.WriteLine($"[Subscriber {id}] received message '{message.GetPayload()}'"); } } ================================================ FILE: solutions/csharp/pubsubsystem/pubsubsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Commands/ICommand.cs ================================================ interface ICommand { void Execute(); } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Commands/PrepareOrderCommand.cs ================================================ class PrepareOrderCommand : ICommand { private readonly Order order; private readonly Chef chef; public PrepareOrderCommand(Order order, Chef chef) { this.order = order; this.chef = chef; } public void Execute() { chef.PrepareOrder(order); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Commands/ServeOrderCommand.cs ================================================ class ServeOrderCommand : ICommand { private readonly Order order; private readonly Waiter waiter; public ServeOrderCommand(Order order, Waiter waiter) { this.order = order; this.waiter = waiter; } public void Execute() { waiter.ServeOrder(order); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Decorators/BillDecorator.cs ================================================ abstract class BillDecorator : IBillComponent { protected IBillComponent wrapped; public BillDecorator(IBillComponent component) { this.wrapped = component; } public virtual double CalculateTotal() { return wrapped.CalculateTotal(); } public virtual string GetDescription() { return wrapped.GetDescription(); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Decorators/ServiceChargeDecorator.cs ================================================ class ServiceChargeDecorator : BillDecorator { private readonly double serviceCharge; public ServiceChargeDecorator(IBillComponent component, double charge) : base(component) { this.serviceCharge = charge; } public override double CalculateTotal() { return base.CalculateTotal() + serviceCharge; } public override string GetDescription() { return base.GetDescription() + ", Service Charge"; } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Decorators/TaxDecorator.cs ================================================ class TaxDecorator : BillDecorator { private readonly double taxRate; public TaxDecorator(IBillComponent component, double taxRate) : base(component) { this.taxRate = taxRate; } public override double CalculateTotal() { return base.CalculateTotal() * (1 + taxRate); } public override string GetDescription() { return base.GetDescription() + $", Tax @{taxRate * 100}%"; } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Enum/TableStatus.cs ================================================ enum TableStatus { AVAILABLE, OCCUPIED, RESERVED } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/BaseBill.cs ================================================ class BaseBill : IBillComponent { private readonly Order order; public BaseBill(Order order) { this.order = order; } public double CalculateTotal() => order.GetTotalPrice(); public string GetDescription() => "Order Items"; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Bill.cs ================================================ class Bill { private readonly IBillComponent component; public Bill(IBillComponent component) { this.component = component; } public void PrintBill() { Console.WriteLine("\n--- BILL ---"); Console.WriteLine($"Description: {component.GetDescription()}"); Console.WriteLine($"Total: ${component.CalculateTotal():F2}"); Console.WriteLine("------------"); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Chef.cs ================================================ class Chef : Staff { public Chef(string id, string name) : base(id, name) { } public void PrepareOrder(Order order) { Console.WriteLine($"Chef {name} received order {order.GetOrderId()} and is starting preparation."); foreach (var item in order.GetOrderItems()) { item.ChangeState(new PreparingState()); } } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/IBillComponent.cs ================================================ interface IBillComponent { double CalculateTotal(); string GetDescription(); } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Menu.cs ================================================ class Menu { private readonly Dictionary items = new Dictionary(); public void AddItem(MenuItem item) { items[item.GetId()] = item; } public MenuItem GetItem(string id) { if (!items.TryGetValue(id, out MenuItem item)) { throw new ArgumentException($"Menu item with ID {id} not found."); } return item; } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/MenuItem.cs ================================================ class MenuItem { private readonly string id; private readonly string name; private readonly double price; public MenuItem(string id, string name, double price) { this.id = id; this.name = name; this.price = price; } public string GetId() => id; public string GetName() => name; public double GetPrice() => price; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Order.cs ================================================ class Order { private readonly int orderId; private readonly int tableId; private readonly List items = new List(); public Order(int orderId, int tableId) { this.orderId = orderId; this.tableId = tableId; } public void AddItem(OrderItem item) { items.Add(item); } public double GetTotalPrice() { return items.Sum(item => item.GetMenuItem().GetPrice()); } public int GetOrderId() => orderId; public int GetTableId() => tableId; public List GetOrderItems() => items; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/OrderItem.cs ================================================ class OrderItem { private readonly MenuItem menuItem; private readonly Order order; private IOrderItemState state; private readonly List observers = new List(); public OrderItem(MenuItem menuItem, Order order) { this.menuItem = menuItem; this.order = order; this.state = new OrderedState(); } public void ChangeState(IOrderItemState newState) { this.state = newState; Console.WriteLine($"Item '{menuItem.GetName()}' state changed to: {newState.GetStatus()}"); } public void NextState() { state.Next(this); } public void SetState(IOrderItemState state) { this.state = state; } public void AddObserver(IOrderObserver observer) { observers.Add(observer); } public void NotifyObservers() { foreach (var observer in observers.ToList()) { observer.Update(this); } } public MenuItem GetMenuItem() => menuItem; public Order GetOrder() => order; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Restaurant.cs ================================================ class Restaurant { private static Restaurant instance; private static readonly object lockObject = new object(); private readonly Dictionary waiters = new Dictionary(); private readonly Dictionary chefs = new Dictionary(); private readonly Dictionary tables = new Dictionary(); private readonly Menu menu = new Menu(); private Restaurant() { } public static Restaurant GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new Restaurant(); } } } return instance; } public void AddWaiter(Waiter waiter) => waiters[waiter.GetId()] = waiter; public Waiter GetWaiter(string id) => waiters.TryGetValue(id, out Waiter waiter) ? waiter : null; public void AddChef(Chef chef) => chefs[chef.GetId()] = chef; public Chef GetChef(string id) => chefs.TryGetValue(id, out Chef chef) ? chef : null; public List GetChefs() => chefs.Values.ToList(); public List GetWaiters() => waiters.Values.ToList(); public void AddTable(Table table) => tables[table.GetId()] = table; public Menu GetMenu() => menu; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Staff.cs ================================================ abstract class Staff { protected string id; protected string name; public Staff(string id, string name) { this.id = id; this.name = name; } public string GetId() => id; public string GetName() => name; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Table.cs ================================================ class Table { private readonly int id; private readonly int capacity; private TableStatus status; public Table(int id, int capacity) { this.id = id; this.capacity = capacity; this.status = TableStatus.AVAILABLE; } public int GetId() => id; public int GetCapacity() => capacity; public TableStatus GetStatus() => status; public void SetStatus(TableStatus status) => this.status = status; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Models/Waiter.cs ================================================ class Waiter : Staff, IOrderObserver { public Waiter(string id, string name) : base(id, name) { } public void ServeOrder(Order order) { Console.WriteLine($"Waiter {name} is serving order {order.GetOrderId()}"); foreach (var item in order.GetOrderItems()) { item.ChangeState(new ServedState()); } } public void Update(OrderItem item) { Console.WriteLine($">>> WAITER {name} NOTIFIED: Item '{item.GetMenuItem().GetName()}' " + $"for table {item.GetOrder().GetTableId()} is READY FOR PICKUP."); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/Observer/IOrderObserver.cs ================================================ interface IOrderObserver { void Update(OrderItem item); } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/README.md ================================================ # Designing Restaurant Management System ## Requirements 1. The restaurant management system should allow customers to place orders, view the menu, and make reservations. 2. The system should manage the restaurant's inventory, including ingredients and menu items. 3. The system should handle order processing, including order preparation, billing, and payment. 4. The system should support multiple payment methods, such as cash, credit card, and mobile payments. 5. The system should manage staff information, including roles, schedules, and performance tracking. 6. The system should generate reports and analytics for management, such as sales reports and inventory analysis. 7. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **MenuItem** class represents a menu item in the restaurant, with properties such as ID, name, description, price, and availability. 2. The **Order** class represents an order placed by a customer, with properties such as ID, list of menu items, total amount, order status, and timestamp. 3. The **OrderStatus** enum represents the different statuses an order can have, such as pending, preparing, ready, completed, or cancelled. 4. The **Reservation** class represents a reservation made by a customer, with properties such as ID, customer name, contact number, party size, and reservation time. 5. The **Payment** class represents a payment made for an order, with properties such as ID, amount, payment method, and payment status. 6. The **PaymentMethod** enum represents the different payment methods supported by the restaurant, such as cash, credit card, or mobile payment. 7. The **PaymentStatus** enum represents the status of a payment, which can be pending, completed, or failed. 8. The Staff class represents a staff member of the restaurant, with properties such as ID, name, role, and contact number. 9. The **Restaurant** class is the main class that manages the restaurant operations. It follows the Singleton pattern to ensure only one instance of the restaurant exists. 10. The Restaurant class provides methods for managing menu items, placing orders, updating order status, making reservations, processing payments, and managing staff. 11. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as orders and reservations. 12. The notifyKitchen and notifyStaff methods are placeholders for notifying relevant staff about order updates and status changes. 13. The **RestaurantManagementDemo** class demonstrates the usage of the restaurant management system by adding menu items, placing an order, making a reservation, processing a payment, updating order status, adding staff, and retrieving the menu. ================================================ FILE: solutions/csharp/restaurantmanagementsystem/RestaurantManagementSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class RestaurantManagementSystemDemo { public static void Main(string[] args) { Console.WriteLine("=== Initializing Restaurant System ==="); RestaurantManagementSystemFacade rmsFacade = RestaurantManagementSystemFacade.GetInstance(); Table table1 = rmsFacade.AddTable(1, 4); Chef chef1 = rmsFacade.AddChef("CHEF01", "Gordon"); Waiter waiter1 = rmsFacade.AddWaiter("W01", "Alice"); MenuItem pizza = rmsFacade.AddMenuItem("PIZZA01", "Margherita Pizza", 12.50); MenuItem pasta = rmsFacade.AddMenuItem("PASTA01", "Carbonara Pasta", 15.00); MenuItem coke = rmsFacade.AddMenuItem("DRINK01", "Coke", 2.50); Console.WriteLine("Initialization Complete.\n"); Console.WriteLine("=== SCENARIO 1: Taking an order ==="); Order order1 = rmsFacade.TakeOrder(table1.GetId(), waiter1.GetId(), new List { pizza.GetId(), coke.GetId() }); Console.WriteLine($"Order taken successfully. Order ID: {order1.GetOrderId()}"); Console.WriteLine("\n=== SCENARIO 2: Chef prepares, Waiter gets notified ==="); rmsFacade.MarkItemsAsReady(order1.GetOrderId()); rmsFacade.ServeOrder(waiter1.GetId(), order1.GetOrderId()); Console.WriteLine("\n=== SCENARIO 3: Generating the bill ==="); Bill finalBill = rmsFacade.GenerateBill(order1.GetOrderId()); finalBill.PrintBill(); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/RestaurantManagementSystemFacade.cs ================================================ class RestaurantManagementSystemFacade { private static RestaurantManagementSystemFacade instance; private static readonly object lockObject = new object(); private readonly Restaurant restaurant = Restaurant.GetInstance(); private int orderIdCounter = 1; private readonly Dictionary orders = new Dictionary(); private RestaurantManagementSystemFacade() { } public static RestaurantManagementSystemFacade GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new RestaurantManagementSystemFacade(); } } } return instance; } public Table AddTable(int id, int capacity) { Table table = new Table(id, capacity); restaurant.AddTable(table); return table; } public Waiter AddWaiter(string id, string name) { Waiter waiter = new Waiter(id, name); restaurant.AddWaiter(waiter); return waiter; } public Chef AddChef(string id, string name) { Chef chef = new Chef(id, name); restaurant.AddChef(chef); return chef; } public MenuItem AddMenuItem(string id, string name, double price) { MenuItem item = new MenuItem(id, name, price); restaurant.GetMenu().AddItem(item); return item; } public Order TakeOrder(int tableId, string waiterId, List menuItemIds) { Waiter waiter = restaurant.GetWaiter(waiterId); if (waiter == null) { throw new ArgumentException("Invalid waiter ID."); } var chefs = restaurant.GetChefs(); if (!chefs.Any()) { throw new InvalidOperationException("No chefs available."); } Chef chef = chefs.First(); Order order = new Order(Interlocked.Increment(ref orderIdCounter) - 1, tableId); foreach (string itemId in menuItemIds) { MenuItem menuItem = restaurant.GetMenu().GetItem(itemId); OrderItem orderItem = new OrderItem(menuItem, order); orderItem.AddObserver(waiter); order.AddItem(orderItem); } ICommand prepareOrderCommand = new PrepareOrderCommand(order, chef); prepareOrderCommand.Execute(); orders[order.GetOrderId()] = order; return order; } public void MarkItemsAsReady(int orderId) { Order order = orders[orderId]; Console.WriteLine($"\nChef has finished preparing order {order.GetOrderId()}"); foreach (var item in order.GetOrderItems()) { item.NextState(); item.NextState(); } } public void ServeOrder(string waiterId, int orderId) { Order order = orders[orderId]; Waiter waiter = restaurant.GetWaiter(waiterId); ICommand serveOrderCommand = new ServeOrderCommand(order, waiter); serveOrderCommand.Execute(); } public Bill GenerateBill(int orderId) { Order order = orders[orderId]; IBillComponent billComponent = new BaseBill(order); billComponent = new TaxDecorator(billComponent, 0.08); billComponent = new ServiceChargeDecorator(billComponent, 5.00); return new Bill(billComponent); } } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/States/IOrderItemState.cs ================================================ interface IOrderItemState { void Next(OrderItem item); void Prev(OrderItem item); string GetStatus(); } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/States/OrderedState.cs ================================================ class OrderedState : IOrderItemState { public void Next(OrderItem item) { item.SetState(new PreparingState()); } public void Prev(OrderItem item) { Console.WriteLine("This is the initial state."); } public string GetStatus() => "ORDERED"; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/States/PreparingState.cs ================================================ class PreparingState : IOrderItemState { public void Next(OrderItem item) { item.SetState(new ReadyForPickupState()); } public void Prev(OrderItem item) { item.SetState(new OrderedState()); } public string GetStatus() => "PREPARING"; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/States/ReadyForPickupState.cs ================================================ class ReadyForPickupState : IOrderItemState { public void Next(OrderItem item) { item.NotifyObservers(); } public void Prev(OrderItem item) { item.SetState(new PreparingState()); } public string GetStatus() => "READY_FOR_PICKUP"; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/States/ServedState.cs ================================================ class ServedState : IOrderItemState { public void Next(OrderItem item) { Console.WriteLine("This is the final state."); } public void Prev(OrderItem item) { Console.WriteLine("Cannot revert a served item."); } public string GetStatus() => "SERVED"; } ================================================ FILE: solutions/csharp/restaurantmanagementsystem/restaurantmanagementsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/ridesharingservice/Enums/DriverStatus.cs ================================================ enum DriverStatus { ONLINE, IN_TRIP, OFFLINE } ================================================ FILE: solutions/csharp/ridesharingservice/Enums/RideType.cs ================================================ enum RideType { SEDAN, SUV, AUTO } ================================================ FILE: solutions/csharp/ridesharingservice/Enums/TripStatus.cs ================================================ enum TripStatus { REQUESTED, ASSIGNED, IN_PROGRESS, COMPLETED, CANCELLED } ================================================ FILE: solutions/csharp/ridesharingservice/Models/Driver.cs ================================================ class Driver : User { private Vehicle vehicle; private Location currentLocation; private DriverStatus status; public Driver(string name, string contact, Vehicle v, Location loc) : base(name, contact) { vehicle = v; currentLocation = loc; status = DriverStatus.OFFLINE; } public Vehicle Vehicle => vehicle; public DriverStatus Status => status; public void SetStatus(DriverStatus s) { status = s; Console.WriteLine($"Driver {Name} is now {s}"); } public Location CurrentLocation => currentLocation; public void SetCurrentLocation(Location loc) { currentLocation = loc; } public override void OnUpdate(Trip trip) { Console.WriteLine($"--- Notification for Driver {Name} ---"); Console.WriteLine($" Trip {trip.Id} status: {trip.Status}."); if (trip.Status == TripStatus.REQUESTED) { Console.WriteLine(" A new ride is available for you to accept."); } Console.WriteLine("--------------------------------\n"); } } ================================================ FILE: solutions/csharp/ridesharingservice/Models/Location.cs ================================================ class Location { private readonly double latitude; private readonly double longitude; public Location(double lat, double lng) { latitude = lat; longitude = lng; } public double DistanceTo(Location other) { double dx = latitude - other.latitude; double dy = longitude - other.longitude; return Math.Sqrt(dx * dx + dy * dy); } public double Latitude => latitude; public double Longitude => longitude; public override string ToString() { return $"Location({latitude}, {longitude})"; } } ================================================ FILE: solutions/csharp/ridesharingservice/Models/Rider.cs ================================================ class Rider : User { public Rider(string name, string contact) : base(name, contact) { } public override void OnUpdate(Trip trip) { Console.WriteLine($"--- Notification for Rider {Name} ---"); Console.WriteLine($" Trip {trip.Id} is now {trip.Status}."); if (trip.Driver != null) { Console.WriteLine($" Driver: {trip.Driver.Name} in a {trip.Driver.Vehicle.Model} ({trip.Driver.Vehicle.LicenseNumber})"); } Console.WriteLine("--------------------------------\n"); } } ================================================ FILE: solutions/csharp/ridesharingservice/Models/Trip.cs ================================================ class Trip { private readonly string id; private readonly Rider rider; private Driver driver; private readonly Location pickupLocation; private readonly Location dropoffLocation; private readonly double fare; private TripStatus status; private ITripState currentState; private readonly List observers = new List(); public static int idCounter = 0; public Trip(TripBuilder builder) { id = builder.Id; rider = builder.Rider; driver = null; pickupLocation = builder.PickupLocation; dropoffLocation = builder.DropoffLocation; fare = builder.Fare; status = TripStatus.REQUESTED; currentState = new RequestedState(); } public void AddObserver(ITripObserver observer) { observers.Add(observer); } private void NotifyObservers() { foreach (var obs in observers) { obs.OnUpdate(this); } } public void AssignDriver(Driver d) { currentState.Assign(this, d); AddObserver(d); NotifyObservers(); } public void StartTrip() { currentState.Start(this); NotifyObservers(); } public void EndTrip() { currentState.End(this); NotifyObservers(); } // Getters public string Id => id; public Rider Rider => rider; public Driver Driver => driver; public Location PickupLocation => pickupLocation; public Location DropoffLocation => dropoffLocation; public double Fare => fare; public TripStatus Status => status; // Setters (internal, only to be called by State objects) public void SetState(ITripState state) { currentState = state; } public void SetStatus(TripStatus s) { status = s; } public void SetDriver(Driver d) { driver = d; } public override string ToString() { return $"Trip [id={id}, status={status}, fare=${fare:F2}]"; } } class TripBuilder { private readonly string id; private Rider rider; private Location pickupLocation; private Location dropoffLocation; private double fare; public TripBuilder() { id = $"trip_{++Trip.idCounter}"; } public TripBuilder WithRider(Rider r) { rider = r; return this; } public TripBuilder WithPickupLocation(Location loc) { pickupLocation = loc; return this; } public TripBuilder WithDropoffLocation(Location loc) { dropoffLocation = loc; return this; } public TripBuilder WithFare(double f) { fare = f; return this; } public Trip Build() { if (rider == null || pickupLocation == null || dropoffLocation == null) { throw new InvalidOperationException("Rider, pickup, and dropoff locations are required to build a trip."); } return new Trip(this); } internal string Id => id; internal Rider Rider => rider; internal Location PickupLocation => pickupLocation; internal Location DropoffLocation => dropoffLocation; internal double Fare => fare; } ================================================ FILE: solutions/csharp/ridesharingservice/Models/User.cs ================================================ abstract class User : ITripObserver { private readonly string id; private readonly string name; private readonly string contact; private readonly List tripHistory; private static int idCounter = 0; public User(string n, string c) { id = $"user_{++idCounter}"; name = n; contact = c; tripHistory = new List(); } public void AddTripToHistory(Trip trip) { tripHistory.Add(trip); } public List TripHistory => tripHistory; public string Id => id; public string Name => name; public string Contact => contact; public abstract void OnUpdate(Trip trip); } ================================================ FILE: solutions/csharp/ridesharingservice/Models/Vehicle.cs ================================================ class Vehicle { private readonly string licenseNumber; private readonly string model; private readonly RideType type; public Vehicle(string license, string m, RideType t) { licenseNumber = license; model = m; type = t; } public string LicenseNumber => licenseNumber; public string Model => model; public RideType Type => type; } ================================================ FILE: solutions/csharp/ridesharingservice/Observer/ITripObserver.cs ================================================ interface ITripObserver { void OnUpdate(Trip trip); } ================================================ FILE: solutions/csharp/ridesharingservice/README.md ================================================ # Designing a Ride-Sharing Service Like Uber ## Requirements 1. The ride sharing service should allow passengers to request rides and drivers to accept and fulfill those ride requests. 2. Passengers should be able to specify their pickup location, destination, and desired ride type (e.g., regular, premium). 3. Drivers should be able to see available ride requests and choose to accept or decline them. 4. The system should match ride requests with available drivers based on proximity and other factors. 5. The system should calculate the fare for each ride based on distance, time, and ride type. 6. The system should handle payments and process transactions between passengers and drivers. 7. The system should provide real-time tracking of ongoing rides and notify passengers and drivers about ride status updates. 8. The system should handle concurrent requests and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Passenger** class represents a passenger in the ride sharing service, with properties such as ID, name, contact information, and location. 2. The **Driver** class represents a driver in the ride sharing service, with properties such as ID, name, contact information, license plate, location, and status (available or busy). 3. The **Ride** class represents a ride requested by a passenger and accepted by a driver, with properties such as ID, passenger, driver, source location, destination location, status, and fare. 4. The **Location** class represents a geographical location with latitude and longitude coordinates. 5. The **Payment** class represents a payment made for a ride, with properties such as ID, ride, amount, and payment status. 6. The **RideService** class is the main class that manages the ride sharing service. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The RideService class provides methods for adding passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. 8. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and ConcurrentLinkedQueue) to handle concurrent access to shared data, such as ride requests and driver availability. 9. The notifyDrivers, notifyPassenger, and notifyDriver methods are placeholders for notifying relevant parties about ride status updates. 10. The calculateFare and processPayment methods are placeholders for calculating ride fares and processing payments, respectively. 11. The **RideSharingDemo** class demonstrates the usage of the ride sharing service by creating passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. ================================================ FILE: solutions/csharp/ridesharingservice/RideSharingService.cs ================================================ class RideSharingService { private static volatile RideSharingService instance; private static readonly object lockObject = new object(); private readonly Dictionary riders = new Dictionary(); private readonly Dictionary drivers = new Dictionary(); private readonly Dictionary trips = new Dictionary(); private IPricingStrategy pricingStrategy; private IDriverMatchingStrategy driverMatchingStrategy; private RideSharingService() { } public static RideSharingService Instance { get { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new RideSharingService(); } } } return instance; } } public void SetPricingStrategy(IPricingStrategy strategy) { pricingStrategy = strategy; } public void SetDriverMatchingStrategy(IDriverMatchingStrategy strategy) { driverMatchingStrategy = strategy; } public Rider RegisterRider(string name, string contact) { var rider = new Rider(name, contact); riders[rider.Id] = rider; return rider; } public Driver RegisterDriver(string name, string contact, Vehicle vehicle, Location initialLocation) { var driver = new Driver(name, contact, vehicle, initialLocation); drivers[driver.Id] = driver; return driver; } public Trip RequestRide(string riderId, Location pickup, Location dropoff, RideType rideType) { if (!riders.TryGetValue(riderId, out Rider rider)) { throw new ArgumentException("Rider not found"); } Console.WriteLine($"\n--- New Ride Request from {rider.Name} ---"); // 1. Find available drivers var availableDrivers = driverMatchingStrategy.FindDrivers(drivers.Values.ToList(), pickup, rideType); if (!availableDrivers.Any()) { Console.WriteLine("No drivers available for your request. Please try again later."); return null; } Console.WriteLine($"Found {availableDrivers.Count} available driver(s)."); // 2. Calculate fare double fare = pricingStrategy.CalculateFare(pickup, dropoff, rideType); Console.WriteLine($"Estimated fare: ${fare:F2}"); // 3. Create a trip using the Builder var trip = new TripBuilder() .WithRider(rider) .WithPickupLocation(pickup) .WithDropoffLocation(dropoff) .WithFare(fare) .Build(); trips[trip.Id] = trip; // 4. Notify nearby drivers Console.WriteLine("Notifying nearby drivers of the new ride request..."); foreach (var driver in availableDrivers) { Console.WriteLine($" > Notifying {driver.Name} at {driver.CurrentLocation}"); driver.OnUpdate(trip); } return trip; } public void AcceptRide(string driverId, string tripId) { if (!drivers.TryGetValue(driverId, out Driver driver) || !trips.TryGetValue(tripId, out Trip trip)) { throw new ArgumentException("Driver or Trip not found"); } Console.WriteLine($"\n--- Driver {driver.Name} accepted the ride ---"); driver.SetStatus(DriverStatus.IN_TRIP); trip.AssignDriver(driver); } public void StartTrip(string tripId) { if (!trips.TryGetValue(tripId, out Trip trip)) { throw new ArgumentException("Trip not found"); } Console.WriteLine($"\n--- Trip {trip.Id} is starting ---"); trip.StartTrip(); } public void EndTrip(string tripId) { if (!trips.TryGetValue(tripId, out Trip trip)) { throw new ArgumentException("Trip not found"); } Console.WriteLine($"\n--- Trip {trip.Id} is ending ---"); trip.EndTrip(); // Update statuses and history var driver = trip.Driver; driver.SetStatus(DriverStatus.ONLINE); driver.SetCurrentLocation(trip.DropoffLocation); var rider = trip.Rider; driver.AddTripToHistory(trip); rider.AddTripToHistory(trip); Console.WriteLine($"Driver {driver.Name} is now back online at {driver.CurrentLocation}"); } } ================================================ FILE: solutions/csharp/ridesharingservice/RideSharingServiceDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; public class RideSharingServiceDemo { public static void Main() { // 1. Setup the system using singleton instance var service = RideSharingService.Instance; service.SetDriverMatchingStrategy(new NearestDriverMatchingStrategy()); service.SetPricingStrategy(new VehicleBasedPricingStrategy()); // 2. Register riders and drivers var alice = service.RegisterRider("Alice", "123-456-7890"); var bobVehicle = new Vehicle("KA01-1234", "Toyota Prius", RideType.SEDAN); var bob = service.RegisterDriver("Bob", "243-987-2860", bobVehicle, new Location(1.0, 1.0)); var charlieVehicle = new Vehicle("KA02-5678", "Honda CRV", RideType.SUV); var charlie = service.RegisterDriver("Charlie", "313-486-2691", charlieVehicle, new Location(2.0, 2.0)); var davidVehicle = new Vehicle("KA03-9012", "Honda CRV", RideType.SEDAN); var david = service.RegisterDriver("David", "613-586-3241", davidVehicle, new Location(1.2, 1.2)); // 3. Drivers go online bob.SetStatus(DriverStatus.ONLINE); charlie.SetStatus(DriverStatus.ONLINE); david.SetStatus(DriverStatus.ONLINE); // David is online but will be too far for the first request david.SetCurrentLocation(new Location(10.0, 10.0)); // 4. Alice requests a ride var pickupLocation = new Location(0.0, 0.0); var dropoffLocation = new Location(5.0, 5.0); // Rider wants a SEDAN var trip1 = service.RequestRide(alice.Id, pickupLocation, dropoffLocation, RideType.SEDAN); if (trip1 != null) { // 5. One of the nearby drivers accepts the ride service.AcceptRide(bob.Id, trip1.Id); // 6. The trip progresses service.StartTrip(trip1.Id); service.EndTrip(trip1.Id); } Console.WriteLine("\n--- Checking Trip History ---"); Console.WriteLine($"Alice's trip history: {alice.TripHistory.Count} trips"); Console.WriteLine($"Bob's trip history: {bob.TripHistory.Count} trips"); // --- Second ride request --- Console.WriteLine("\n============================================="); var harry = service.RegisterRider("Harry", "167-342-7834"); // Harry requests an SUV var trip2 = service.RequestRide(harry.Id, new Location(2.5, 2.5), new Location(8.0, 8.0), RideType.SUV); if (trip2 != null) { // Only Charlie is available for an SUV ride service.AcceptRide(charlie.Id, trip2.Id); service.StartTrip(trip2.Id); service.EndTrip(trip2.Id); } } } ================================================ FILE: solutions/csharp/ridesharingservice/States/AssignedState.cs ================================================ class AssignedState : ITripState { public void Request(Trip trip) { Console.WriteLine("Trip has already been requested and assigned."); } public void Assign(Trip trip, Driver driver) { Console.WriteLine("Trip is already assigned. To re-assign, cancel first."); } public void Start(Trip trip) { trip.SetStatus(TripStatus.IN_PROGRESS); trip.SetState(new InProgressState()); } public void End(Trip trip) { Console.WriteLine("Cannot end a trip that has not started."); } } ================================================ FILE: solutions/csharp/ridesharingservice/States/CompletedState.cs ================================================ class CompletedState : ITripState { public void Request(Trip trip) { Console.WriteLine("Cannot request a trip that is already completed."); } public void Assign(Trip trip, Driver driver) { Console.WriteLine("Cannot assign a driver to a completed trip."); } public void Start(Trip trip) { Console.WriteLine("Cannot start a completed trip."); } public void End(Trip trip) { Console.WriteLine("Trip is already completed."); } } ================================================ FILE: solutions/csharp/ridesharingservice/States/ITripState.cs ================================================ interface ITripState { void Request(Trip trip); void Assign(Trip trip, Driver driver); void Start(Trip trip); void End(Trip trip); } ================================================ FILE: solutions/csharp/ridesharingservice/States/InProgressState.cs ================================================ class InProgressState : ITripState { public void Request(Trip trip) { Console.WriteLine("Trip is already in progress."); } public void Assign(Trip trip, Driver driver) { Console.WriteLine("Cannot assign a new driver while trip is in progress."); } public void Start(Trip trip) { Console.WriteLine("Trip is already in progress."); } public void End(Trip trip) { trip.SetStatus(TripStatus.COMPLETED); trip.SetState(new CompletedState()); } } ================================================ FILE: solutions/csharp/ridesharingservice/States/RequestedState.cs ================================================ class RequestedState : ITripState { public void Request(Trip trip) { Console.WriteLine("Trip is already in requested state."); } public void Assign(Trip trip, Driver driver) { trip.SetDriver(driver); trip.SetStatus(TripStatus.ASSIGNED); trip.SetState(new AssignedState()); } public void Start(Trip trip) { Console.WriteLine("Cannot start a trip that has not been assigned a driver."); } public void End(Trip trip) { Console.WriteLine("Cannot end a trip that has not been assigned a driver."); } } ================================================ FILE: solutions/csharp/ridesharingservice/Strategies/Matching/IDriverMatchingStrategy.cs ================================================ interface IDriverMatchingStrategy { List FindDrivers(List allDrivers, Location pickupLocation, RideType rideType); } ================================================ FILE: solutions/csharp/ridesharingservice/Strategies/Matching/NearestDriverMatchingStrategy.cs ================================================ class NearestDriverMatchingStrategy : IDriverMatchingStrategy { private const double MAX_DISTANCE_KM = 5.0; public List FindDrivers(List allDrivers, Location pickupLocation, RideType rideType) { Console.WriteLine($"Finding nearest drivers for ride type: {rideType}"); return allDrivers .Where(driver => driver.Status == DriverStatus.ONLINE) .Where(driver => driver.Vehicle.Type == rideType) .Where(driver => pickupLocation.DistanceTo(driver.CurrentLocation) <= MAX_DISTANCE_KM) .OrderBy(driver => pickupLocation.DistanceTo(driver.CurrentLocation)) .ToList(); } } ================================================ FILE: solutions/csharp/ridesharingservice/Strategies/Pricing/FlatRatePricingStrategy.cs ================================================ class FlatRatePricingStrategy : IPricingStrategy { private const double BASE_FARE = 5.0; private const double FLAT_RATE = 1.5; public double CalculateFare(Location pickup, Location dropoff, RideType rideType) { double distance = pickup.DistanceTo(dropoff); return BASE_FARE + distance * FLAT_RATE; } } ================================================ FILE: solutions/csharp/ridesharingservice/Strategies/Pricing/IPricingStrategy.cs ================================================ interface IPricingStrategy { double CalculateFare(Location pickup, Location dropoff, RideType rideType); } ================================================ FILE: solutions/csharp/ridesharingservice/Strategies/Pricing/VehicleBasedPricingStrategy.cs ================================================ class VehicleBasedPricingStrategy : IPricingStrategy { private const double BASE_FARE = 2.50; private readonly Dictionary ratePerKm = new Dictionary { { RideType.SEDAN, 1.50 }, { RideType.SUV, 2.00 }, { RideType.AUTO, 1.00 } }; public double CalculateFare(Location pickup, Location dropoff, RideType rideType) { return BASE_FARE + ratePerKm[rideType] * pickup.DistanceTo(dropoff); } } ================================================ FILE: solutions/csharp/ridesharingservice/ridesharingservice.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/snakeandladdergame/Enums/GameStatus.cs ================================================ enum GameStatus { NOT_STARTED, RUNNING, FINISHED } ================================================ FILE: solutions/csharp/snakeandladdergame/Game.cs ================================================ class Game { private readonly Board board; private readonly Queue players; private readonly Dice dice; private GameStatus status; private Player winner; public Game(Board board, Queue players, Dice dice) { this.board = board; this.players = new Queue(players); this.dice = dice; this.status = GameStatus.NOT_STARTED; this.winner = null; } public void Play() { if (players.Count < 2) { Console.WriteLine("Cannot start game. At least 2 players are required."); return; } this.status = GameStatus.RUNNING; Console.WriteLine("Game started!"); while (status == GameStatus.RUNNING) { Player currentPlayer = players.Dequeue(); TakeTurn(currentPlayer); if (status == GameStatus.RUNNING) { players.Enqueue(currentPlayer); } } Console.WriteLine("Game Finished!"); if (winner != null) { Console.WriteLine("The winner is " + winner.GetName() + "!"); } } private void TakeTurn(Player player) { int roll = dice.Roll(); Console.WriteLine(); Console.WriteLine(player.GetName() + "'s turn. Rolled a " + roll + "."); int currentPosition = player.GetPosition(); int nextPosition = currentPosition + roll; if (nextPosition > board.GetSize()) { Console.WriteLine("Oops, " + player.GetName() + " needs to land exactly on " + board.GetSize() + ". Turn skipped."); return; } if (nextPosition == board.GetSize()) { player.SetPosition(nextPosition); this.winner = player; this.status = GameStatus.FINISHED; Console.WriteLine("Hooray! " + player.GetName() + " reached the final square " + board.GetSize() + " and won!"); return; } int finalPosition = board.GetFinalPosition(nextPosition); if (finalPosition > nextPosition) // Ladder { Console.WriteLine("Wow! " + player.GetName() + " found a ladder 🪜 at " + nextPosition + " and climbed to " + finalPosition + "."); } else if (finalPosition < nextPosition) // Snake { Console.WriteLine("Oh no! " + player.GetName() + " was bitten by a snake 🐍 at " + nextPosition + " and slid down to " + finalPosition + "."); } else { Console.WriteLine(player.GetName() + " moved from " + currentPosition + " to " + finalPosition + "."); } player.SetPosition(finalPosition); if (roll == 6) { Console.WriteLine(player.GetName() + " rolled a 6 and gets another turn!"); TakeTurn(player); } } } class GameBuilder { private Board board; private Queue players; private Dice dice; public GameBuilder SetBoard(int boardSize, List boardEntities) { this.board = new Board(boardSize, boardEntities); return this; } public GameBuilder SetPlayers(List playerNames) { this.players = new Queue(); foreach (string name in playerNames) { players.Enqueue(new Player(name)); } return this; } public GameBuilder SetDice(Dice dice) { this.dice = dice; return this; } public Game Build() { if (board == null || players == null || dice == null) { throw new InvalidOperationException("Board, Players, and Dice must be set."); } return new Game(board, players, dice); } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/Board.cs ================================================ class Board { private readonly int size; private readonly Dictionary snakesAndLadders; public Board(int size, List entities) { this.size = size; this.snakesAndLadders = new Dictionary(); foreach (BoardEntity entity in entities) { snakesAndLadders[entity.GetStart()] = entity.GetEnd(); } } public int GetSize() { return size; } public int GetFinalPosition(int position) { if (snakesAndLadders.ContainsKey(position)) { return snakesAndLadders[position]; } return position; } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/BoardEntity.cs ================================================ abstract class BoardEntity { protected readonly int start; protected readonly int end; public BoardEntity(int start, int end) { this.start = start; this.end = end; } public int GetStart() { return start; } public int GetEnd() { return end; } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/Dice.cs ================================================ class Dice { private readonly int minValue; private readonly int maxValue; private readonly Random random = new Random(); public Dice(int minValue, int maxValue) { this.minValue = minValue; this.maxValue = maxValue; } public int Roll() { return (int)(random.NextDouble() * (maxValue - minValue + 1) + minValue); } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/Ladder.cs ================================================ class Ladder : BoardEntity { public Ladder(int start, int end) : base(start, end) { if (start >= end) { throw new ArgumentException("Ladder bottom must be at a lower position than its top."); } } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/Player.cs ================================================ class Player { private readonly string name; private int position; public Player(string name) { this.name = name; this.position = 0; } public string GetName() { return name; } public int GetPosition() { return position; } public void SetPosition(int position) { this.position = position; } } ================================================ FILE: solutions/csharp/snakeandladdergame/Models/Snake.cs ================================================ class Snake : BoardEntity { public Snake(int start, int end) : base(start, end) { if (start <= end) { throw new ArgumentException("Snake head must be at a higher position than its tail."); } } } ================================================ FILE: solutions/csharp/snakeandladdergame/README.md ================================================ # Designing Snake and Ladder Game ## Requirements 1. The game should be played on a board with numbered cells, typically with 100 cells. 2. The board should have a predefined set of snakes and ladders, connecting certain cells. 3. The game should support multiple players, each represented by a unique game piece. 4. Players should take turns rolling a dice to determine the number of cells to move forward. 5. If a player lands on a cell with the head of a snake, they should slide down to the cell with the tail of the snake. 6. If a player lands on a cell with the base of a ladder, they should climb up to the cell at the top of the ladder. 7. The game should continue until one of the players reaches the final cell on the board. 8. The game should handle multiple game sessions concurrently, allowing different groups of players to play independently. ## Classes, Interfaces and Enumerations 1. The **Board** class represents the game board with a fixed size (e.g., 100 cells). It contains the positions of snakes and ladders and provides methods to initialize them and retrieve the new position after encountering a snake or ladder. 2. The **Player** class represents a player in the game, with properties such as name and current position on the board. 3. The **Snake** class represents a snake on the board, with properties for the start and end positions. 4. The **Ladder** class represents a ladder on the board, with properties for the start and end positions. 5. The **Dice** class represents a dice used in the game, with a method to roll the dice and return a random value between 1 and 6. 6. The **SnakeAndLadderGame** class represents a single game session. It initializes the game with a board, a list of players, and a dice. The play method handles the game loop, where players take turns rolling the dice and moving their positions on the board. It checks for snakes and ladders and updates the player's position accordingly. The game continues until a player reaches the final position on the board. 7. The **GameManager** class is a singleton that manages multiple game sessions. It maintains a list of active games and provides a method to start a new game with a list of player names. Each game is started in a separate thread to allow concurrent game sessions. 8. The **SnakeAndLadderDemo** class demonstrates the usage of the game by creating an instance of the GameManager and starting two separate game sessions with different sets of players. ================================================ FILE: solutions/csharp/snakeandladdergame/SnakeAndLadderDemo.cs ================================================ using System; using System.Collections.Generic; public class SnakeAndLadderDemo { public static void Main() { List boardEntities = new List { new Snake(17, 7), new Snake(54, 34), new Snake(62, 19), new Snake(98, 79), new Ladder(3, 38), new Ladder(24, 33), new Ladder(42, 93), new Ladder(72, 84) }; List players = new List { "Alice", "Bob", "Charlie" }; Game game = new GameBuilder() .SetBoard(100, boardEntities) .SetPlayers(players) .SetDice(new Dice(1, 6)) .Build(); game.Play(); } } ================================================ FILE: solutions/csharp/snakeandladdergame/snakeandladdergame.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/socialnetworkingservice/Models/Comment.cs ================================================ class Comment : CommentableEntity { public Comment(User author, string content) : base(author, content) { } public List GetReplies() { return GetComments(); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Models/CommentableEntity.cs ================================================ abstract class CommentableEntity { protected readonly string id; protected readonly User author; protected readonly string content; protected readonly DateTime timestamp; private readonly HashSet likes = new HashSet(); protected readonly List comments = new List(); public CommentableEntity(User author, string content) { this.id = Guid.NewGuid().ToString(); this.author = author; this.content = content; this.timestamp = DateTime.Now; } public void AddLike(User user) { likes.Add(user); } public void AddComment(Comment comment) { comments.Add(comment); } public string GetId() { return id; } public User GetAuthor() { return author; } public string GetContent() { return content; } public DateTime GetTimestamp() { return timestamp; } public List GetComments() { return comments; } public HashSet GetLikes() { return likes; } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Models/Post.cs ================================================ class Post : CommentableEntity { public Post(User author, string content) : base(author, content) { } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Models/User.cs ================================================ class User { private readonly string id; private readonly string name; private readonly string email; private readonly HashSet friends = new HashSet(); private readonly List posts = new List(); public User(string name, string email) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; } public void AddFriend(User friend) { friends.Add(friend); } public void AddPost(Post post) { posts.Add(post); } public string GetId() { return id; } public string GetName() { return name; } public HashSet GetFriends() { return friends; } public List GetPosts() { return posts; } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Observer/IPostObserver.cs ================================================ interface IPostObserver { void OnPostCreated(Post post); void OnLike(Post post, User user); void OnComment(Post post, Comment comment); } ================================================ FILE: solutions/csharp/socialnetworkingservice/Observer/UserNotifier.cs ================================================ class UserNotifier : IPostObserver { public void OnPostCreated(Post post) { User author = post.GetAuthor(); foreach (User friend in author.GetFriends()) { Console.WriteLine($"Notification for {friend.GetName()}: {author.GetName()} created a new post: {post.GetContent()}"); } } public void OnLike(Post post, User user) { User author = post.GetAuthor(); Console.WriteLine($"Notification for {author.GetName()}: {user.GetName()} liked your post"); } public void OnComment(Post post, Comment comment) { User author = post.GetAuthor(); Console.WriteLine($"Notification for {author.GetName()}: {comment.GetAuthor().GetName()} commented on your post"); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/README.md ================================================ # Designing a Social Network Like Facebook ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their personal information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their information, such as profile picture, bio, and interests. - Users should be able to update their profile information. #### Friend Connections: - Users should be able to send friend requests to other users. - Users should be able to accept or decline friend requests. - Users should be able to view their list of friends. #### Posts and Newsfeed: - Users should be able to create posts with text, images, or videos. - Users should be able to view a newsfeed consisting of posts from their friends and their own posts. - The newsfeed should be sorted in reverse chronological order. #### Likes and Comments: - Users should be able to like and comment on posts. - Users should be able to view the list of likes and comments on a post. #### Privacy and Security: - Users should be able to control the visibility of their posts and profile information. - The system should enforce secure access control to ensure data privacy. #### Notifications: - Users should receive notifications for events such as friend requests, likes, comments, and mentions. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the social networking system, containing properties such as ID, name, email, password, profile picture, bio, list of friends, and list of posts. 2. The **Post** class represents a post created by a user, containing properties such as ID, user ID, content, image URLs, video URLs, timestamp, likes, and comments. 3. The **Comment** class represents a comment made by a user on a post, containing properties such as ID, user ID, post ID, content, and timestamp. 4. The **Notification** class represents a notification generated for a user, containing properties such as ID, user ID, notification type, content, and timestamp. 5. The **NotificationType** enum defines the different types of notifications, such as friend request, friend request accepted, like, comment, and mention. 6. The **SocialNetworkingService** class is the main class that manages the social networking system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SocialNetworkingService class provides methods for user registration, login, profile updates, friend requests, post creation, newsfeed generation, likes, comments, and notifications. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SocialNetworkingDemo** class demonstrates the usage of the social networking system by registering users, logging in, sending friend requests, creating posts, liking posts, commenting on posts, and retrieving newsfeed and notifications. ================================================ FILE: solutions/csharp/socialnetworkingservice/Repositories/PostRepository.cs ================================================ class PostRepository { private static readonly PostRepository INSTANCE = new PostRepository(); private readonly Dictionary posts = new Dictionary(); private PostRepository() { } public static PostRepository GetInstance() { return INSTANCE; } public void Save(Post post) { posts[post.GetId()] = post; } public Post FindById(string id) { posts.TryGetValue(id, out Post post); return post; } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Repositories/UserRepository.cs ================================================ class UserRepository { private static readonly UserRepository INSTANCE = new UserRepository(); private readonly Dictionary users = new Dictionary(); private UserRepository() { } public static UserRepository GetInstance() { return INSTANCE; } public void Save(User user) { users[user.GetId()] = user; } public User FindById(string id) { users.TryGetValue(id, out User user); return user; } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Services/NewsFeedService.cs ================================================ class NewsFeedService { private INewsFeedGenerationStrategy strategy; public NewsFeedService() { this.strategy = new ChronologicalStrategy(); // Default strategy } public void SetStrategy(INewsFeedGenerationStrategy strategy) { this.strategy = strategy; } public List GetNewsFeed(User user) { return strategy.GenerateFeed(user); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Services/PostService.cs ================================================ class PostService { private readonly PostRepository postRepository = PostRepository.GetInstance(); private readonly List observers = new List(); public void AddObserver(IPostObserver observer) { observers.Add(observer); } public Post CreatePost(User author, string content) { Post post = new Post(author, content); postRepository.Save(post); author.AddPost(post); foreach (var observer in observers) { observer.OnPostCreated(post); } return post; } public void LikePost(User user, string postId) { Post post = postRepository.FindById(postId); post.AddLike(user); foreach (var observer in observers) { observer.OnLike(post, user); } } public void AddComment(User author, string commentableId, string content) { Comment comment = new Comment(author, content); Post post = postRepository.FindById(commentableId); post.AddComment(comment); foreach (var observer in observers) { observer.OnComment(post, comment); } } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Services/UserService.cs ================================================ class UserService { private readonly UserRepository userRepository = UserRepository.GetInstance(); public User CreateUser(string name, string email) { User user = new User(name, email); userRepository.Save(user); return user; } public void AddFriend(string userId1, string userId2) { User user1 = userRepository.FindById(userId1); User user2 = userRepository.FindById(userId2); user1.AddFriend(user2); user2.AddFriend(user1); } public User GetUserById(string userId) { return userRepository.FindById(userId); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/SocialNetworkFacade.cs ================================================ class SocialNetworkFacade { private readonly UserService userService; private readonly PostService postService; private readonly NewsFeedService newsFeedService; public SocialNetworkFacade() { this.userService = new UserService(); this.postService = new PostService(); this.newsFeedService = new NewsFeedService(); // Wire up the observer postService.AddObserver(new UserNotifier()); } public User CreateUser(string name, string email) { return userService.CreateUser(name, email); } public void AddFriend(string userId1, string userId2) { userService.AddFriend(userId1, userId2); } public Post CreatePost(string authorId, string content) { User author = userService.GetUserById(authorId); return postService.CreatePost(author, content); } public void AddComment(string userId, string postId, string content) { User user = userService.GetUserById(userId); postService.AddComment(user, postId, content); } public void LikePost(string userId, string postId) { User user = userService.GetUserById(userId); postService.LikePost(user, postId); } public List GetNewsFeed(string userId) { User user = userService.GetUserById(userId); return newsFeedService.GetNewsFeed(user); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/SocialNetworkingDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; public class SocialNetworkDemo { private static void PrintFeed(List feed) { if (feed.Count == 0) { Console.WriteLine(" No posts in the feed."); return; } foreach (Post post in feed) { Console.WriteLine($" Post by {post.GetAuthor().GetName()} at {post.GetTimestamp()}"); Console.WriteLine($" \"{post.GetContent()}\""); Console.WriteLine($" Likes: {post.GetLikes().Count}, Comments: {post.GetComments().Count}"); } } public static void Main(string[] args) { SocialNetworkFacade socialNetwork = new SocialNetworkFacade(); Console.WriteLine("----------- 1. Creating Users -----------"); User alice = socialNetwork.CreateUser("Alice", "alice@example.com"); User bob = socialNetwork.CreateUser("Bob", "bob@example.com"); User charlie = socialNetwork.CreateUser("Charlie", "charlie@example.com"); Console.WriteLine($"Created users: {alice.GetName()}, {bob.GetName()}, {charlie.GetName()}"); Console.WriteLine("\n----------- 2. Building Friendships -----------"); socialNetwork.AddFriend(alice.GetId(), bob.GetId()); socialNetwork.AddFriend(bob.GetId(), charlie.GetId()); Console.WriteLine($"{alice.GetName()} and {bob.GetName()} are now friends."); Console.WriteLine($"{bob.GetName()} and {charlie.GetName()} are now friends."); Console.WriteLine("\n----------- 3. Users Create Posts -----------"); Post alicePost = socialNetwork.CreatePost(alice.GetId(), "Hello from Alice!"); Post bobPost = socialNetwork.CreatePost(bob.GetId(), "It's a beautiful day!"); Post charliePost = socialNetwork.CreatePost(charlie.GetId(), "Thinking about design patterns."); Console.WriteLine("\n----------- 4. Users Interact with Posts -----------"); socialNetwork.AddComment(bob.GetId(), alicePost.GetId(), "Hey Alice, nice to see you here!"); socialNetwork.LikePost(charlie.GetId(), alicePost.GetId()); Console.WriteLine("\n----------- 5. Viewing News Feeds (Strategy Pattern) -----------"); Console.WriteLine("\n--- Alice's News Feed (should see Bob's post) ---"); List alicesFeed = socialNetwork.GetNewsFeed(alice.GetId()); PrintFeed(alicesFeed); Console.WriteLine("\n--- Bob's News Feed (should see Alice's, and Charlie's post) ---"); List bobsFeed = socialNetwork.GetNewsFeed(bob.GetId()); PrintFeed(bobsFeed); Console.WriteLine("\n--- Charlie's News Feed (should see Bob's post) ---"); List charliesFeed = socialNetwork.GetNewsFeed(charlie.GetId()); PrintFeed(charliesFeed); } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Strategy/ChronologicalStrategy.cs ================================================ class ChronologicalStrategy : INewsFeedGenerationStrategy { public List GenerateFeed(User user) { HashSet friends = user.GetFriends(); List feed = new List(); foreach (User friend in friends) { feed.AddRange(friend.GetPosts()); } // Sort posts by timestamp in reverse (most recent first) feed.Sort((p1, p2) => p2.GetTimestamp().CompareTo(p1.GetTimestamp())); return feed; } } ================================================ FILE: solutions/csharp/socialnetworkingservice/Strategy/INewsFeedGenerationStrategy.cs ================================================ interface INewsFeedGenerationStrategy { List GenerateFeed(User user); } ================================================ FILE: solutions/csharp/socialnetworkingservice/socialnetworkingservice.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/splitwise/Models/BalanceSheet.cs ================================================ class BalanceSheet { private readonly User owner; private readonly Dictionary balances = new Dictionary(); private readonly object balanceLock = new object(); public BalanceSheet(User owner) { this.owner = owner; } public Dictionary GetBalances() => balances; public void AdjustBalance(User otherUser, double amount) { lock (balanceLock) { if (owner.Equals(otherUser)) { return; // Cannot owe yourself } if (balances.ContainsKey(otherUser)) { balances[otherUser] += amount; } else { balances[otherUser] = amount; } } } public void ShowBalances() { Console.WriteLine($"--- Balance Sheet for {owner.GetName()} ---"); if (balances.Count == 0) { Console.WriteLine("All settled up!"); return; } double totalOwedToMe = 0; double totalIOwe = 0; foreach (var entry in balances) { User otherUser = entry.Key; double amount = entry.Value; if (amount > 0.01) { Console.WriteLine($"{otherUser.GetName()} owes {owner.GetName()} ${amount:F2}"); totalOwedToMe += amount; } else if (amount < -0.01) { Console.WriteLine($"{owner.GetName()} owes {otherUser.GetName()} ${-amount:F2}"); totalIOwe += (-amount); } } Console.WriteLine($"Total Owed to {owner.GetName()}: ${totalOwedToMe:F2}"); Console.WriteLine($"Total {owner.GetName()} Owes: ${totalIOwe:F2}"); Console.WriteLine("---------------------------------"); } } ================================================ FILE: solutions/csharp/splitwise/Models/Expense.cs ================================================ class Expense { private readonly string id; private readonly string description; private readonly double amount; private readonly User paidBy; private readonly List splits; private readonly DateTime timestamp; public Expense(ExpenseBuilder builder) { this.id = builder.Id; this.description = builder.Description; this.amount = builder.Amount; this.paidBy = builder.PaidBy; this.timestamp = DateTime.Now; // Use the strategy to calculate splits this.splits = builder.SplitStrategy.CalculateSplits( builder.Amount, builder.PaidBy, builder.Participants, builder.SplitValues); } public string GetId() => id; public string GetDescription() => description; public double GetAmount() => amount; public User GetPaidBy() => paidBy; public List GetSplits() => splits; } class ExpenseBuilder { public string Id { get; set; } public string Description { get; set; } public double Amount { get; set; } public User PaidBy { get; set; } public List Participants { get; set; } public SplitStrategy SplitStrategy { get; set; } public List SplitValues { get; set; } public ExpenseBuilder SetId(string id) { this.Id = id; return this; } public ExpenseBuilder SetDescription(string description) { this.Description = description; return this; } public ExpenseBuilder SetAmount(double amount) { this.Amount = amount; return this; } public ExpenseBuilder SetPaidBy(User paidBy) { this.PaidBy = paidBy; return this; } public ExpenseBuilder SetParticipants(List participants) { this.Participants = participants; return this; } public ExpenseBuilder SetSplitStrategy(SplitStrategy splitStrategy) { this.SplitStrategy = splitStrategy; return this; } public ExpenseBuilder SetSplitValues(List splitValues) { this.SplitValues = splitValues; return this; } public Expense Build() { if (SplitStrategy == null) { throw new InvalidOperationException("Split strategy is required."); } return new Expense(this); } } ================================================ FILE: solutions/csharp/splitwise/Models/Group.cs ================================================ class Group { private readonly string id; private readonly string name; private readonly List members; public Group(string name, List members) { this.id = Guid.NewGuid().ToString(); this.name = name; this.members = members; } public string GetId() => id; public string GetName() => name; public List GetMembers() => new List(members); } ================================================ FILE: solutions/csharp/splitwise/Models/Split.cs ================================================ class Split { private readonly User user; private readonly double amount; public Split(User user, double amount) { this.user = user; this.amount = amount; } public User GetUser() => user; public double GetAmount() => amount; } ================================================ FILE: solutions/csharp/splitwise/Models/Transaction.cs ================================================ class Transaction { private readonly User from; private readonly User to; private readonly double amount; public Transaction(User from, User to, double amount) { this.from = from; this.to = to; this.amount = amount; } public override string ToString() { return $"{from.GetName()} should pay {to.GetName()} ${amount:F2}"; } } ================================================ FILE: solutions/csharp/splitwise/Models/User.cs ================================================ class User { private readonly string id; private readonly string name; private readonly string email; private readonly BalanceSheet balanceSheet; public User(string name, string email) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; this.balanceSheet = new BalanceSheet(this); } public string GetId() => id; public string GetName() => name; public BalanceSheet GetBalanceSheet() => balanceSheet; } ================================================ FILE: solutions/csharp/splitwise/README.md ================================================ # Designing Splitwise ## Requirements 1. The system should allow users to create accounts and manage their profile information. 2. Users should be able to create groups and add other users to the groups. 3. Users should be able to add expenses within a group, specifying the amount, description, and participants. 4. The system should automatically split the expenses among the participants based on their share. 5. Users should be able to view their individual balances with other users and settle up the balances. 6. The system should support different split methods, such as equal split, percentage split, and exact amounts. 7. Users should be able to view their transaction history and group expenses. 8. The system should handle concurrent transactions and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the Splitwise system, with properties such as ID, name, email, and a map to store balances with other users. 2. The **Group** class represents a group in Splitwise, containing a list of member users and a list of expenses. 3. The **Expense** class represents an expense within a group, with properties such as ID, amount, description, the user who paid, and a list of splits. 4. The **Split** class is an abstract class representing the split of an expense. It is extended by EqualSplit, PercentSplit, and ExactSplit classes to handle different split methods. 5. The **Transaction** class represents a transaction between two users, with properties such as ID, sender, receiver, and amount. 6. The **SplitwiseService** class is the main class that manages the Splitwise system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SplitwiseService class provides methods for adding users, groups, and expenses, splitting expenses, updating balances, settling balances, and creating transactions. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SplitwiseDemo** class demonstrates the usage of the Splitwise system by creating users, a group, adding an expense, settling balances, and printing user balances. ================================================ FILE: solutions/csharp/splitwise/SplitwiseDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class SplitwiseDemo { public static void Main(string[] args) { // 1. Setup the service SplitwiseService service = SplitwiseService.GetInstance(); // 2. Create users and groups User alice = service.AddUser("Alice", "alice@a.com"); User bob = service.AddUser("Bob", "bob@b.com"); User charlie = service.AddUser("Charlie", "charlie@c.com"); User david = service.AddUser("David", "david@d.com"); Group friendsGroup = service.AddGroup("Friends Trip", new List { alice, bob, charlie, david }); Console.WriteLine("--- System Setup Complete ---\n"); // 3. Use Case 1: Equal Split Console.WriteLine("--- Use Case 1: Equal Split ---"); service.CreateExpense(new ExpenseBuilder() .SetDescription("Dinner") .SetAmount(1000) .SetPaidBy(alice) .SetParticipants(new List { alice, bob, charlie, david }) .SetSplitStrategy(new EqualSplitStrategy())); service.ShowBalanceSheet(alice.GetId()); service.ShowBalanceSheet(bob.GetId()); Console.WriteLine(); // 4. Use Case 2: Exact Split Console.WriteLine("--- Use Case 2: Exact Split ---"); service.CreateExpense(new ExpenseBuilder() .SetDescription("Movie Tickets") .SetAmount(370) .SetPaidBy(alice) .SetParticipants(new List { bob, charlie }) .SetSplitStrategy(new ExactSplitStrategy()) .SetSplitValues(new List { 120.0, 250.0 })); service.ShowBalanceSheet(alice.GetId()); service.ShowBalanceSheet(bob.GetId()); Console.WriteLine(); // 5. Use Case 3: Percentage Split Console.WriteLine("--- Use Case 3: Percentage Split ---"); service.CreateExpense(new ExpenseBuilder() .SetDescription("Groceries") .SetAmount(500) .SetPaidBy(david) .SetParticipants(new List { alice, bob, charlie }) .SetSplitStrategy(new PercentageSplitStrategy()) .SetSplitValues(new List { 40.0, 30.0, 30.0 })); // 40%, 30%, 30% Console.WriteLine("--- Balances After All Expenses ---"); service.ShowBalanceSheet(alice.GetId()); service.ShowBalanceSheet(bob.GetId()); service.ShowBalanceSheet(charlie.GetId()); service.ShowBalanceSheet(david.GetId()); Console.WriteLine(); // 6. Use Case 4: Simplify Group Debts Console.WriteLine("--- Use Case 4: Simplify Group Debts for 'Friends Trip' ---"); List simplifiedDebts = service.SimplifyGroupDebts(friendsGroup.GetId()); if (simplifiedDebts.Count == 0) { Console.WriteLine("All debts are settled within the group!"); } else { foreach (Transaction debt in simplifiedDebts) { Console.WriteLine(debt.ToString()); } } Console.WriteLine(); service.ShowBalanceSheet(bob.GetId()); // 7. Use Case 5: Partial Settlement Console.WriteLine("--- Use Case 5: Partial Settlement ---"); // From the simplified debts, we see Bob should pay Alice. Let's say Bob pays 100. service.SettleUp(bob.GetId(), alice.GetId(), 100); Console.WriteLine("--- Balances After Partial Settlement ---"); service.ShowBalanceSheet(alice.GetId()); service.ShowBalanceSheet(bob.GetId()); } } ================================================ FILE: solutions/csharp/splitwise/SplitwiseService.cs ================================================ class SplitwiseService { private static SplitwiseService instance; private static readonly object lockObject = new object(); private readonly Dictionary users = new Dictionary(); private readonly Dictionary groups = new Dictionary(); private SplitwiseService() { } public static SplitwiseService GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new SplitwiseService(); } } } return instance; } public User AddUser(string name, string email) { User user = new User(name, email); users[user.GetId()] = user; return user; } public Group AddGroup(string name, List members) { Group group = new Group(name, members); groups[group.GetId()] = group; return group; } public User GetUser(string id) { return users.TryGetValue(id, out User user) ? user : null; } public Group GetGroup(string id) { return groups.TryGetValue(id, out Group group) ? group : null; } public void CreateExpense(ExpenseBuilder builder) { lock (lockObject) { Expense expense = builder.Build(); User paidBy = expense.GetPaidBy(); foreach (Split split in expense.GetSplits()) { User participant = split.GetUser(); double amount = split.GetAmount(); if (!paidBy.Equals(participant)) { paidBy.GetBalanceSheet().AdjustBalance(participant, amount); participant.GetBalanceSheet().AdjustBalance(paidBy, -amount); } } Console.WriteLine($"Expense '{expense.GetDescription()}' of amount {expense.GetAmount()} created."); } } public void SettleUp(string payerId, string payeeId, double amount) { lock (lockObject) { User payer = users[payerId]; User payee = users[payeeId]; Console.WriteLine($"{payer.GetName()} is settling up {amount} with {payee.GetName()}"); // Settlement is like a reverse expense. payer owes less to payee. payee.GetBalanceSheet().AdjustBalance(payer, -amount); payer.GetBalanceSheet().AdjustBalance(payee, amount); } } public void ShowBalanceSheet(string userId) { User user = users[userId]; user.GetBalanceSheet().ShowBalances(); } public List SimplifyGroupDebts(string groupId) { Group group = groups[groupId]; if (group == null) { throw new ArgumentException("Group not found"); } // Calculate net balance for each member within the group context Dictionary netBalances = new Dictionary(); foreach (User member in group.GetMembers()) { double balance = 0; foreach (var entry in member.GetBalanceSheet().GetBalances()) { // Consider only balances with other group members if (group.GetMembers().Contains(entry.Key)) { balance += entry.Value; } } netBalances[member] = balance; } // Separate into creditors and debtors var creditors = netBalances.Where(e => e.Value > 0).OrderByDescending(e => e.Value).ToList(); var debtors = netBalances.Where(e => e.Value < 0).OrderBy(e => e.Value).ToList(); List transactions = new List(); int i = 0, j = 0; while (i < creditors.Count && j < debtors.Count) { var creditor = creditors[i]; var debtor = debtors[j]; double amountToSettle = Math.Min(creditor.Value, -debtor.Value); transactions.Add(new Transaction(debtor.Key, creditor.Key, amountToSettle)); // Update the values creditors[i] = new KeyValuePair(creditor.Key, creditor.Value - amountToSettle); debtors[j] = new KeyValuePair(debtor.Key, debtor.Value + amountToSettle); if (Math.Abs(creditors[i].Value) < 0.01) i++; if (Math.Abs(debtors[j].Value) < 0.01) j++; } return transactions; } } ================================================ FILE: solutions/csharp/splitwise/Strategy/EqualSplitStrategy.cs ================================================ class EqualSplitStrategy : SplitStrategy { public override List CalculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { List splits = new List(); double amountPerPerson = totalAmount / participants.Count; foreach (User participant in participants) { splits.Add(new Split(participant, amountPerPerson)); } return splits; } } ================================================ FILE: solutions/csharp/splitwise/Strategy/ExactSplitStrategy.cs ================================================ class ExactSplitStrategy : SplitStrategy { public override List CalculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { if (participants.Count != splitValues.Count) { throw new ArgumentException("Number of participants and split values must match."); } if (Math.Abs(splitValues.Sum() - totalAmount) > 0.01) { throw new ArgumentException("Sum of exact amounts must equal the total expense amount."); } List splits = new List(); for (int i = 0; i < participants.Count; i++) { splits.Add(new Split(participants[i], splitValues[i])); } return splits; } } ================================================ FILE: solutions/csharp/splitwise/Strategy/PercentageSplitStrategy.cs ================================================ class PercentageSplitStrategy : SplitStrategy { public override List CalculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { if (participants.Count != splitValues.Count) { throw new ArgumentException("Number of participants and split values must match."); } if (Math.Abs(splitValues.Sum() - 100.0) > 0.01) { throw new ArgumentException("Sum of percentages must be 100."); } List splits = new List(); for (int i = 0; i < participants.Count; i++) { double amount = (totalAmount * splitValues[i]) / 100.0; splits.Add(new Split(participants[i], amount)); } return splits; } } ================================================ FILE: solutions/csharp/splitwise/Strategy/SplitStrategy.cs ================================================ abstract class SplitStrategy { public abstract List CalculateSplits(double totalAmount, User paidBy, List participants, List splitValues); } ================================================ FILE: solutions/csharp/splitwise/splitwise.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/stackoverflow/Enums/EventType.cs ================================================ enum EventType { UPVOTE_QUESTION, DOWNVOTE_QUESTION, UPVOTE_ANSWER, DOWNVOTE_ANSWER, ACCEPT_ANSWER } ================================================ FILE: solutions/csharp/stackoverflow/Enums/VoteType.cs ================================================ enum VoteType { UPVOTE, DOWNVOTE } ================================================ FILE: solutions/csharp/stackoverflow/Models/Answer.cs ================================================ class Answer : Post { private bool isAccepted = false; public Answer(string body, User author) : base(Guid.NewGuid().ToString(), body, author) { } public void SetAccepted(bool accepted) { isAccepted = accepted; } public bool IsAcceptedAnswer() { return isAccepted; } } ================================================ FILE: solutions/csharp/stackoverflow/Models/Comment.cs ================================================ class Comment : Content { public Comment(string body, User author) : base(Guid.NewGuid().ToString(), body, author) { } } ================================================ FILE: solutions/csharp/stackoverflow/Models/Content.cs ================================================ abstract class Content { protected readonly string id; protected readonly string body; protected readonly User author; protected readonly DateTime creationTime; public Content(string id, string body, User author) { this.id = id; this.body = body; this.author = author; this.creationTime = DateTime.Now; } public string GetId() { return id; } public string GetBody() { return body; } public User GetAuthor() { return author; } } ================================================ FILE: solutions/csharp/stackoverflow/Models/Post.cs ================================================ using System.Collections.Concurrent; abstract class Post : Content { private int voteCount = 0; private readonly ConcurrentDictionary voters = new ConcurrentDictionary(); private readonly List comments = new List(); private readonly List observers = new List(); private readonly object postLock = new object(); public Post(string id, string body, User author) : base(id, body, author) { } public void AddObserver(IPostObserver observer) { observers.Add(observer); } protected void NotifyObservers(Event eventObj) { foreach (var observer in observers) { observer.OnPostEvent(eventObj); } } public void Vote(User user, VoteType voteType) { lock (postLock) { string userId = user.GetId(); if (voters.TryGetValue(userId, out VoteType existingVote) && existingVote == voteType) return; // Already voted int scoreChange = 0; if (voters.ContainsKey(userId)) // User is changing their vote { scoreChange = (voteType == VoteType.UPVOTE) ? 2 : -2; } else // New vote { scoreChange = (voteType == VoteType.UPVOTE) ? 1 : -1; } voters[userId] = voteType; voteCount += scoreChange; EventType eventType; if (this is Question) { eventType = (voteType == VoteType.UPVOTE) ? EventType.UPVOTE_QUESTION : EventType.DOWNVOTE_QUESTION; } else { eventType = (voteType == VoteType.UPVOTE) ? EventType.UPVOTE_ANSWER : EventType.DOWNVOTE_ANSWER; } NotifyObservers(new Event(eventType, user, this)); } } } ================================================ FILE: solutions/csharp/stackoverflow/Models/Question.cs ================================================ class Question : Post { private readonly string title; private readonly HashSet tags; private readonly List answers = new List(); private Answer acceptedAnswer; public Question(string title, string body, User author, HashSet tags) : base(Guid.NewGuid().ToString(), body, author) { this.title = title; this.tags = tags; } public void AddAnswer(Answer answer) { answers.Add(answer); } public void AcceptAnswer(Answer answer) { lock (this) { if (!author.GetId().Equals(answer.GetAuthor().GetId()) && acceptedAnswer == null) { acceptedAnswer = answer; answer.SetAccepted(true); NotifyObservers(new Event(EventType.ACCEPT_ANSWER, answer.GetAuthor(), answer)); } } } public string GetTitle() { return title; } public HashSet GetTags() { return tags; } public List GetAnswers() { return answers; } } ================================================ FILE: solutions/csharp/stackoverflow/Models/Tag.cs ================================================ class Tag : IComparable { private readonly string name; public Tag(string name) { this.name = name; } public string GetName() { return name; } public int CompareTo(Tag other) { return string.Compare(name, other.name, StringComparison.Ordinal); } public override bool Equals(object obj) { if (obj is Tag other) { return name.Equals(other.name, StringComparison.OrdinalIgnoreCase); } return false; } public override int GetHashCode() { return name.ToLower().GetHashCode(); } } ================================================ FILE: solutions/csharp/stackoverflow/Models/User.cs ================================================ class User { private readonly string id; private readonly string name; private int reputation; private readonly object reputationLock = new object(); public User(string name) { this.id = Guid.NewGuid().ToString(); this.name = name; this.reputation = 0; } public void UpdateReputation(int change) { lock (reputationLock) { reputation += change; } } public string GetId() { return id; } public string GetName() { return name; } public int GetReputation() { lock (reputationLock) { return reputation; } } } ================================================ FILE: solutions/csharp/stackoverflow/Observer/Event.cs ================================================ class Event { private readonly EventType type; private readonly User actor; private readonly Post targetPost; public Event(EventType type, User actor, Post targetPost) { this.type = type; this.actor = actor; this.targetPost = targetPost; } public EventType GetEventType() { return type; } public User GetActor() { return actor; } public Post GetTargetPost() { return targetPost; } } ================================================ FILE: solutions/csharp/stackoverflow/Observer/IPostObserver.cs ================================================ interface IPostObserver { void OnPostEvent(Event eventObj); } ================================================ FILE: solutions/csharp/stackoverflow/Observer/ReputationManager.cs ================================================ class ReputationManager : IPostObserver { private const int QUESTION_UPVOTE_REP = 5; private const int ANSWER_UPVOTE_REP = 10; private const int ACCEPTED_ANSWER_REP = 15; private const int DOWNVOTE_REP_PENALTY = -1; private const int POST_DOWNVOTED_REP_PENALTY = -2; public void OnPostEvent(Event eventObj) { User postAuthor = eventObj.GetTargetPost().GetAuthor(); switch (eventObj.GetEventType()) { case EventType.UPVOTE_QUESTION: postAuthor.UpdateReputation(QUESTION_UPVOTE_REP); break; case EventType.DOWNVOTE_QUESTION: postAuthor.UpdateReputation(DOWNVOTE_REP_PENALTY); eventObj.GetActor().UpdateReputation(POST_DOWNVOTED_REP_PENALTY); break; case EventType.UPVOTE_ANSWER: postAuthor.UpdateReputation(ANSWER_UPVOTE_REP); break; case EventType.DOWNVOTE_ANSWER: postAuthor.UpdateReputation(DOWNVOTE_REP_PENALTY); eventObj.GetActor().UpdateReputation(POST_DOWNVOTED_REP_PENALTY); break; case EventType.ACCEPT_ANSWER: postAuthor.UpdateReputation(ACCEPTED_ANSWER_REP); break; } } } ================================================ FILE: solutions/csharp/stackoverflow/README.md ================================================ # Designing Stack Overflow ## Requirements 1. Users can post questions, answer questions, and comment on questions and answers. 2. Users can vote on questions and answers. 3. Questions should have tags associated with them. 4. Users can search for questions based on keywords, tags, or user profiles. 5. The system should assign reputation score to users based on their activity and the quality of their contributions. 6. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the Stack Overflow system, with properties such as id, username, email, and reputation. 2. The **Question** class represents a question posted by a user, with properties such as id, title, content, author, answers, comments, tags, votes and creation date. 3. The **Answer** class represents an answer to a question, with properties such as id, content, author, associated question, comments, votes and creation date. 4. The **Comment** class represents a comment on a question or an answer, with properties such as id, content, author, and creation date. 5. The **Tag** class represents a tag associated with a question, with properties such as id and name. 6. The **Vote** class represents vote associated with a question/answer. 7. The **StackOverflow** class is the main class that manages the Stack Overflow system. It provides methods for creating user, posting questions, answers, and comments, voting on questions and answers, searching for questions, and retrieving questions by tags and users. 8. The **StackOverflowDemo** class demonstrates the usage of the Stack Overflow system by creating users, posting questions and answers, voting, searching for questions, and retrieving questions by tags and users. ================================================ FILE: solutions/csharp/stackoverflow/StackOverflowDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class StackOverflowDemo { public static void Main(string[] args) { StackOverflowService service = new StackOverflowService(); // 1. Create Users User alice = service.CreateUser("Alice"); User bob = service.CreateUser("Bob"); User charlie = service.CreateUser("Charlie"); // 2. Alice posts a question Console.WriteLine("--- Alice posts a question ---"); Tag javaTag = new Tag("java"); Tag designPatternsTag = new Tag("design-patterns"); HashSet tags = new HashSet { javaTag, designPatternsTag }; Question question = service.PostQuestion(alice.GetId(), "How to implement Observer Pattern?", "Details about Observer Pattern...", tags); PrintReputations(alice, bob, charlie); // 3. Bob and Charlie post answers Console.WriteLine("\n--- Bob and Charlie post answers ---"); Answer bobAnswer = service.PostAnswer(bob.GetId(), question.GetId(), "You can use the java.util.Observer interface."); Answer charlieAnswer = service.PostAnswer(charlie.GetId(), question.GetId(), "A better way is to create your own Observer interface."); PrintReputations(alice, bob, charlie); // 4. Voting happens Console.WriteLine("\n--- Voting Occurs ---"); service.VoteOnPost(alice.GetId(), question.GetId(), VoteType.UPVOTE); service.VoteOnPost(bob.GetId(), charlieAnswer.GetId(), VoteType.UPVOTE); service.VoteOnPost(alice.GetId(), bobAnswer.GetId(), VoteType.DOWNVOTE); PrintReputations(alice, bob, charlie); // 5. Alice accepts Charlie's answer Console.WriteLine("\n--- Alice accepts Charlie's answer ---"); service.AcceptAnswer(question.GetId(), charlieAnswer.GetId()); PrintReputations(alice, bob, charlie); // 6. Search for questions Console.WriteLine("\n--- (C) Combined Search: Questions by 'Alice' with tag 'java' ---"); List filtersC = new List { new UserSearchStrategy(alice), new TagSearchStrategy(javaTag) }; List searchResults = service.SearchQuestions(filtersC); foreach (var q in searchResults) { Console.WriteLine($" - Found: {q.GetTitle()}"); } } private static void PrintReputations(params User[] users) { Console.WriteLine("--- Current Reputations ---"); foreach (User user in users) { Console.WriteLine($"{user.GetName()}: {user.GetReputation()}"); } } } ================================================ FILE: solutions/csharp/stackoverflow/StackOverflowService.cs ================================================ using System.Collections.Concurrent; class StackOverflowService { private readonly ConcurrentDictionary users = new ConcurrentDictionary(); private readonly ConcurrentDictionary questions = new ConcurrentDictionary(); private readonly ConcurrentDictionary answers = new ConcurrentDictionary(); private readonly IPostObserver reputationManager = new ReputationManager(); public User CreateUser(string name) { User user = new User(name); users.TryAdd(user.GetId(), user); return user; } public Question PostQuestion(string userId, string title, string body, HashSet tags) { User author = users[userId]; Question question = new Question(title, body, author, tags); question.AddObserver(reputationManager); questions.TryAdd(question.GetId(), question); return question; } public Answer PostAnswer(string userId, string questionId, string body) { User author = users[userId]; Question question = questions[questionId]; Answer answer = new Answer(body, author); answer.AddObserver(reputationManager); question.AddAnswer(answer); answers.TryAdd(answer.GetId(), answer); return answer; } public void VoteOnPost(string userId, string postId, VoteType voteType) { User user = users[userId]; Post post = FindPostById(postId); post.Vote(user, voteType); } public void AcceptAnswer(string questionId, string answerId) { Question question = questions[questionId]; Answer answer = answers[answerId]; question.AcceptAnswer(answer); } public List SearchQuestions(List strategies) { List results = questions.Values.ToList(); foreach (var strategy in strategies) { results = strategy.Filter(results); } return results; } public User GetUser(string userId) { return users[userId]; } private Post FindPostById(string postId) { if (questions.TryGetValue(postId, out Question question)) { return question; } else if (answers.TryGetValue(postId, out Answer answer)) { return answer; } throw new KeyNotFoundException("Post not found"); } } ================================================ FILE: solutions/csharp/stackoverflow/Strategy/ISearchStrategy.cs ================================================ interface ISearchStrategy { List Filter(List questions); } ================================================ FILE: solutions/csharp/stackoverflow/Strategy/KeywordSearchStrategy.cs ================================================ class KeywordSearchStrategy : ISearchStrategy { private readonly string keyword; public KeywordSearchStrategy(string keyword) { this.keyword = keyword.ToLower(); } public List Filter(List questions) { return questions .Where(q => q.GetTitle().ToLower().Contains(keyword) || q.GetBody().ToLower().Contains(keyword)) .ToList(); } } ================================================ FILE: solutions/csharp/stackoverflow/Strategy/TagSearchStrategy.cs ================================================ class TagSearchStrategy : ISearchStrategy { private readonly Tag tag; public TagSearchStrategy(Tag tag) { this.tag = tag; } public List Filter(List questions) { return questions .Where(q => q.GetTags().Any(t => t.GetName().Equals(tag.GetName(), StringComparison.OrdinalIgnoreCase))) .ToList(); } } ================================================ FILE: solutions/csharp/stackoverflow/Strategy/UserSearchStrategy.cs ================================================ class UserSearchStrategy : ISearchStrategy { private readonly User user; public UserSearchStrategy(User user) { this.user = user; } public List Filter(List questions) { return questions .Where(q => q.GetAuthor().GetId().Equals(user.GetId())) .ToList(); } } ================================================ FILE: solutions/csharp/stackoverflow/stackoverflow.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/taskmanagementsystem/Enums/TaskPriority.cs ================================================ enum TaskPriority { LOW, MEDIUM, HIGH, CRITICAL } ================================================ FILE: solutions/csharp/taskmanagementsystem/Enums/TaskStatus.cs ================================================ enum TaskStatus { TODO, IN_PROGRESS, DONE, BLOCKED } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/ActivityLog.cs ================================================ class ActivityLog { private readonly string description; private readonly DateTime timestamp; public ActivityLog(string description) { this.description = description; this.timestamp = DateTime.Now; } public override string ToString() { return $"[{timestamp}] {description}"; } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/Comment.cs ================================================ class Comment { private readonly string id; private readonly string content; private readonly User author; private readonly DateTime timestamp; public Comment(string content, User author) { this.id = Guid.NewGuid().ToString(); this.content = content; this.author = author; this.timestamp = DateTime.Now; } public User GetAuthor() => author; } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/Tag.cs ================================================ class Tag { private readonly string name; public Tag(string name) { this.name = name; } public string GetName() => name; } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/Task.cs ================================================ class Task { private readonly string id; private string title; private string description; private string dueDate; private TaskPriority priority; private readonly User createdBy; private User assignee; private TaskState currentState; private readonly HashSet tags; private readonly List comments; private readonly List subtasks; private readonly List activityLogs; private readonly List observers; private readonly object taskLock = new object(); public Task(TaskBuilder builder) { this.id = builder.Id; this.title = builder.Title; this.description = builder.Description; this.dueDate = builder.DueDate; this.priority = builder.Priority; this.createdBy = builder.CreatedBy; this.assignee = builder.Assignee; this.tags = builder.Tags; this.currentState = new TodoState(); // Initial state this.comments = new List(); this.subtasks = new List(); this.activityLogs = new List(); this.observers = new List(); AddLog($"Task created with title: {title}"); } public void SetAssignee(User user) { lock (taskLock) { this.assignee = user; AddLog($"Assigned to {user.GetName()}"); NotifyObservers("assignee"); } } public void UpdatePriority(TaskPriority priority) { lock (taskLock) { this.priority = priority; NotifyObservers("priority"); } } public void AddComment(Comment comment) { lock (taskLock) { comments.Add(comment); AddLog($"Comment added by {comment.GetAuthor().GetName()}"); NotifyObservers("comment"); } } public void AddSubtask(Task subtask) { lock (taskLock) { subtasks.Add(subtask); AddLog($"Subtask added: {subtask.GetTitle()}"); NotifyObservers("subtask_added"); } } // State Pattern Methods public void SetState(TaskState state) { this.currentState = state; AddLog($"Status changed to: {state.GetStatus()}"); NotifyObservers("status"); } public void StartProgress() => currentState.StartProgress(this); public void CompleteTask() => currentState.CompleteTask(this); public void ReopenTask() => currentState.ReopenTask(this); // Observer Pattern Methods public void AddObserver(ITaskObserver observer) => observers.Add(observer); public void RemoveObserver(ITaskObserver observer) => observers.Remove(observer); public void NotifyObservers(string changeType) { foreach (var observer in observers) { observer.Update(this, changeType); } } public void AddLog(string logDescription) { activityLogs.Add(new ActivityLog(logDescription)); } public bool IsComposite() => subtasks.Count > 0; public void Display(string indent = "") { Console.WriteLine($"{indent}- {title} [{GetStatus()}, {priority}, Due: {dueDate}]"); if (IsComposite()) { foreach (var subtask in subtasks) { subtask.Display(indent + " "); } } } // Getters public string GetId() => id; public string GetTitle() => title; public string GetDescription() => description; public TaskPriority GetPriority() => priority; public string GetDueDate() => dueDate; public User GetAssignee() => assignee; public TaskStatus GetStatus() => currentState.GetStatus(); public void SetTitle(string title) => this.title = title; public void SetDescription(string description) => this.description = description; } // Builder Pattern class TaskBuilder { public string Id { get; private set; } public string Title { get; private set; } public string Description { get; private set; } = ""; public string DueDate { get; private set; } public TaskPriority Priority { get; private set; } public User CreatedBy { get; private set; } public User Assignee { get; private set; } public HashSet Tags { get; private set; } = new HashSet(); public TaskBuilder(string title) { this.Id = Guid.NewGuid().ToString(); this.Title = title; } public TaskBuilder SetDescription(string description) { this.Description = description; return this; } public TaskBuilder SetDueDate(string dueDate) { this.DueDate = dueDate; return this; } public TaskBuilder SetPriority(TaskPriority priority) { this.Priority = priority; return this; } public TaskBuilder SetAssignee(User assignee) { this.Assignee = assignee; return this; } public TaskBuilder SetCreatedBy(User createdBy) { this.CreatedBy = createdBy; return this; } public TaskBuilder SetTags(HashSet tags) { this.Tags = tags; return this; } public Task Build() { return new Task(this); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/TaskList.cs ================================================ class TaskList { private readonly string id; private readonly string name; private readonly List tasks; private readonly object listLock = new object(); public TaskList(string name) { this.id = Guid.NewGuid().ToString(); this.name = name; this.tasks = new List(); } public void AddTask(Task task) { lock (listLock) { tasks.Add(task); } } public List GetTasks() { lock (listLock) { return new List(tasks); // Return copy } } public string GetId() => id; public string GetName() => name; public void Display() { Console.WriteLine($"--- Task List: {name} ---"); foreach (var task in tasks) { task.Display(""); } Console.WriteLine("-----------------------------------"); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Models/User.cs ================================================ class User { private readonly string id; private readonly string name; private readonly string email; public User(string name, string email) { this.id = Guid.NewGuid().ToString(); this.name = name; this.email = email; } public string GetId() => id; public string GetEmail() => email; public string GetName() => name; } ================================================ FILE: solutions/csharp/taskmanagementsystem/Observer/ActivityLogger.cs ================================================ class ActivityLogger : ITaskObserver { public void Update(Task task, string changeType) { Console.WriteLine($"LOGGER: Task '{task.GetTitle()}' was updated. Change: {changeType}"); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Observer/ITaskObserver.cs ================================================ interface ITaskObserver { void Update(Task task, string changeType); } ================================================ FILE: solutions/csharp/taskmanagementsystem/README.md ================================================ # Designing a Task Management System ## Requirements 1. The task management system should allow users to create, update, and delete tasks. 2. Each task should have a title, description, due date, priority, and status (e.g., pending, in progress, completed). 3. Users should be able to assign tasks to other users and set reminders for tasks. 4. The system should support searching and filtering tasks based on various criteria (e.g., priority, due date, assigned user). 5. Users should be able to mark tasks as completed and view their task history. 6. The system should handle concurrent access to tasks and ensure data consistency. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the task management system, with properties such as id, name, and email. 2. The **TaskStatus** enum defines the possible states of a task, such as pending, in progress, and completed. 3. The **Task** class represents a task in the system, with properties like id, title, description, due date, priority, status, and assigned user. 4. The **TaskManager** class is the core of the task management system and follows the Singleton pattern to ensure a single instance of the task manager. 5. The TaskManager class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to tasks and ensure thread safety. 6. The TaskManager class provides methods for creating, updating, deleting, searching, and filtering tasks, as well as marking tasks as completed and retrieving task history for a user. 7. The **TaskManagementSystem** class serves as the entry point of the application and demonstrates the usage of the task management system. ================================================ FILE: solutions/csharp/taskmanagementsystem/State/DoneState.cs ================================================ class DoneState : TaskState { public override void StartProgress(Task task) { Console.WriteLine("Cannot start a completed task. Reopen it first."); } public override void CompleteTask(Task task) { Console.WriteLine("Task is already done."); } public override void ReopenTask(Task task) { task.SetState(new TodoState()); } public override TaskStatus GetStatus() => TaskStatus.DONE; } ================================================ FILE: solutions/csharp/taskmanagementsystem/State/InProgressState.cs ================================================ class InProgressState : TaskState { public override void StartProgress(Task task) { Console.WriteLine("Task is already in progress."); } public override void CompleteTask(Task task) { task.SetState(new DoneState()); } public override void ReopenTask(Task task) { task.SetState(new TodoState()); } public override TaskStatus GetStatus() => TaskStatus.IN_PROGRESS; } ================================================ FILE: solutions/csharp/taskmanagementsystem/State/TaskState.cs ================================================ abstract class TaskState { public abstract void StartProgress(Task task); public abstract void CompleteTask(Task task); public abstract void ReopenTask(Task task); public abstract TaskStatus GetStatus(); } ================================================ FILE: solutions/csharp/taskmanagementsystem/State/TodoState.cs ================================================ class TodoState : TaskState { public override void StartProgress(Task task) { task.SetState(new InProgressState()); } public override void CompleteTask(Task task) { Console.WriteLine("Cannot complete a task that is not in progress."); } public override void ReopenTask(Task task) { Console.WriteLine("Task is already in TO-DO state."); } public override TaskStatus GetStatus() => TaskStatus.TODO; } ================================================ FILE: solutions/csharp/taskmanagementsystem/Strategy/SortByDueDate.cs ================================================ class SortByDueDate : TaskSortStrategy { public override void Sort(List tasks) { tasks.Sort((a, b) => string.Compare(a.GetDueDate(), b.GetDueDate(), StringComparison.Ordinal)); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Strategy/SortByPriority.cs ================================================ class SortByPriority : TaskSortStrategy { public override void Sort(List tasks) { // Higher priority comes first tasks.Sort((a, b) => b.GetPriority().CompareTo(a.GetPriority())); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/Strategy/TaskSortStrategy.cs ================================================ abstract class TaskSortStrategy { public abstract void Sort(List tasks); } ================================================ FILE: solutions/csharp/taskmanagementsystem/TaskManagementSystem.cs ================================================ class TaskManagementSystem { private static TaskManagementSystem instance; private static readonly object lockObject = new object(); private readonly Dictionary users = new Dictionary(); private readonly Dictionary tasks = new Dictionary(); private readonly Dictionary taskLists = new Dictionary(); private TaskManagementSystem() { } public static TaskManagementSystem GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new TaskManagementSystem(); } } } return instance; } public User CreateUser(string name, string email) { User user = new User(name, email); users[user.GetId()] = user; return user; } public TaskList CreateTaskList(string listName) { TaskList taskList = new TaskList(listName); taskLists[taskList.GetId()] = taskList; return taskList; } public Task CreateTask(string title, string description, string dueDate, TaskPriority priority, string createdByUserId) { if (!users.TryGetValue(createdByUserId, out User createdBy)) { throw new ArgumentException("User not found."); } Task task = new TaskBuilder(title) .SetDescription(description) .SetDueDate(dueDate) .SetPriority(priority) .SetCreatedBy(createdBy) .Build(); task.AddObserver(new ActivityLogger()); tasks[task.GetId()] = task; return task; } public List ListTasksByUser(string userId) { if (!users.TryGetValue(userId, out User user)) { return new List(); } return tasks.Values.Where(task => task.GetAssignee() == user).ToList(); } public List ListTasksByStatus(TaskStatus status) { return tasks.Values.Where(task => task.GetStatus() == status).ToList(); } public void DeleteTask(string taskId) { tasks.Remove(taskId); } public List SearchTasks(string keyword, TaskSortStrategy sortingStrategy) { List matchingTasks = new List(); foreach (var task in tasks.Values) { if (task.GetTitle().Contains(keyword) || task.GetDescription().Contains(keyword)) { matchingTasks.Add(task); } } sortingStrategy.Sort(matchingTasks); return matchingTasks; } } ================================================ FILE: solutions/csharp/taskmanagementsystem/TaskManagementSystemDemo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading; public class TaskManagementSystemDemo { public static void Main() { TaskManagementSystem taskManagementSystem = TaskManagementSystem.GetInstance(); // Create users User user1 = taskManagementSystem.CreateUser("John Doe", "john@example.com"); User user2 = taskManagementSystem.CreateUser("Jane Smith", "jane@example.com"); // Create task lists TaskList taskList1 = taskManagementSystem.CreateTaskList("Enhancements"); TaskList taskList2 = taskManagementSystem.CreateTaskList("Bug Fix"); // Create tasks Task task1 = taskManagementSystem.CreateTask("Enhancement Task", "Launch New Feature", "2024-02-15", TaskPriority.LOW, user1.GetId()); Task subtask1 = taskManagementSystem.CreateTask("Enhancement sub task", "Design UI/UX", "2024-02-14", TaskPriority.MEDIUM, user1.GetId()); Task task2 = taskManagementSystem.CreateTask("Bug Fix Task", "Fix API Bug", "2024-02-16", TaskPriority.HIGH, user2.GetId()); task1.AddSubtask(subtask1); taskList1.AddTask(task1); taskList2.AddTask(task2); taskList1.Display(); // Update task status subtask1.StartProgress(); // Assign task subtask1.SetAssignee(user2); taskList1.Display(); // Search tasks List searchResults = taskManagementSystem.SearchTasks("Task", new SortByDueDate()); Console.WriteLine("\nTasks with keyword Task:"); foreach (Task task in searchResults) { Console.WriteLine(task.GetTitle()); } // Filter tasks by status List filteredTasks = taskManagementSystem.ListTasksByStatus(TaskStatus.TODO); Console.WriteLine("\nTODO Tasks:"); foreach (Task task in filteredTasks) { Console.WriteLine(task.GetTitle()); } // Mark a task as done subtask1.CompleteTask(); // Get tasks assigned to a user List userTaskList = taskManagementSystem.ListTasksByUser(user2.GetId()); Console.WriteLine($"\nTask for {user2.GetName()}:"); foreach (Task task in userTaskList) { Console.WriteLine(task.GetTitle()); } taskList1.Display(); // Delete a task taskManagementSystem.DeleteTask(task2.GetId()); } } ================================================ FILE: solutions/csharp/taskmanagementsystem/taskmanagementsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/tictactoe/Enums/GameStatus.cs ================================================ enum GameStatus { IN_PROGRESS, WINNER_X, WINNER_O, DRAW } ================================================ FILE: solutions/csharp/tictactoe/Enums/Symbol.cs ================================================ enum Symbol { X, O, EMPTY } ================================================ FILE: solutions/csharp/tictactoe/Exceptions/InvalidMoveException.cs ================================================ class InvalidMoveException : Exception { public InvalidMoveException(string message) : base(message) { } } ================================================ FILE: solutions/csharp/tictactoe/Models/Board.cs ================================================ using System; class Board { private readonly int size; private int movesCount; private readonly Cell[,] board; public Board(int size) { this.size = size; this.board = new Cell[size, size]; movesCount = 0; InitializeBoard(); } private void InitializeBoard() { for (int row = 0; row < size; row++) { for (int col = 0; col < size; col++) { board[row, col] = new Cell(); } } } public bool PlaceSymbol(int row, int col, Symbol symbol) { if (row < 0 || row >= size || col < 0 || col >= size) { throw new InvalidMoveException("Invalid position: out of bounds."); } if (board[row, col].GetSymbol() != Symbol.EMPTY) { throw new InvalidMoveException("Invalid position: cell is already occupied."); } board[row, col].SetSymbol(symbol); movesCount++; return true; } public Cell GetCell(int row, int col) { if (row < 0 || row >= size || col < 0 || col >= size) { return null; } return board[row, col]; } public bool IsFull() { return movesCount == size * size; } public void PrintBoard() { Console.WriteLine("-------------"); for (int i = 0; i < size; i++) { Console.Write("| "); for (int j = 0; j < size; j++) { Console.Write(board[i, j].GetSymbolChar() + " | "); } Console.WriteLine(); Console.WriteLine("-------------"); } } public int GetSize() => size; } ================================================ FILE: solutions/csharp/tictactoe/Models/Cell.cs ================================================ class Cell { private Symbol symbol; public Cell() { symbol = Symbol.EMPTY; } public Symbol GetSymbol() { return symbol; } public void SetSymbol(Symbol symbol) { this.symbol = symbol; } public char GetSymbolChar() { switch (symbol) { case Symbol.X: return 'X'; case Symbol.O: return 'O'; case Symbol.EMPTY: return '_'; default: return '_'; } } } ================================================ FILE: solutions/csharp/tictactoe/Models/Game.cs ================================================ using System; class Game : GameSubject { private readonly Board board; private readonly Player player1; private readonly Player player2; private Player currentPlayer; private Player winner; private GameStatus status; private IGameState state; private readonly List winningStrategies; public Game(Player player1, Player player2) { board = new Board(3); this.player1 = player1; this.player2 = player2; currentPlayer = player1; // Player 1 starts winner = null; status = GameStatus.IN_PROGRESS; state = new InProgressState(); winningStrategies = new List { new RowWinningStrategy(), new ColumnWinningStrategy(), new DiagonalWinningStrategy() }; } public void MakeMove(Player player, int row, int col) { state.HandleMove(this, player, row, col); } public bool CheckWinner(Player player) { foreach (var strategy in winningStrategies) { if (strategy.CheckWinner(board, player)) { return true; } } return false; } public void SwitchPlayer() { if (currentPlayer == player1) { currentPlayer = player2; } else { currentPlayer = player1; } } public Board GetBoard() => board; public Player GetCurrentPlayer() => currentPlayer; public Player GetWinner() => winner; public void SetWinner(Player winner) => this.winner = winner; public GameStatus GetStatus() => status; public void SetState(IGameState state) => this.state = state; public void SetStatus(GameStatus status) { this.status = status; // Notify observers when the status changes to a finished state if (status != GameStatus.IN_PROGRESS) { NotifyObservers(); } } } ================================================ FILE: solutions/csharp/tictactoe/Models/Player.cs ================================================ class Player { private readonly string name; private readonly Symbol symbol; public Player(string name, Symbol symbol) { this.name = name; this.symbol = symbol; } public string GetName() { return name; } public Symbol GetSymbol() { return symbol; } public char GetSymbolChar() { switch (symbol) { case Symbol.X: return 'X'; case Symbol.O: return 'O'; case Symbol.EMPTY: return '_'; default: return '_'; } } } ================================================ FILE: solutions/csharp/tictactoe/Observer/GameSubject.cs ================================================ abstract class GameSubject { private readonly List observers = new List(); public void AddObserver(IGameObserver observer) { observers.Add(observer); } public void RemoveObserver(IGameObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (var observer in observers) { observer.Update((Game)this); } } } ================================================ FILE: solutions/csharp/tictactoe/Observer/IGameObserver.cs ================================================ interface IGameObserver { void Update(Game game); } ================================================ FILE: solutions/csharp/tictactoe/Observer/Scoreboard.cs ================================================ using System.Collections.Concurrent; class Scoreboard : IGameObserver { private readonly ConcurrentDictionary scores; public Scoreboard() { scores = new ConcurrentDictionary(); } public void Update(Game game) { // The scoreboard only cares about finished games with a winner if (game.GetWinner() != null) { string winnerName = game.GetWinner().GetName(); scores.AddOrUpdate(winnerName, 1, (key, value) => value + 1); Console.WriteLine("[Scoreboard] " + winnerName + " wins! Their new score is " + scores[winnerName] + "."); } } public void PrintScores() { Console.WriteLine("\n--- Overall Scoreboard ---"); if (scores.IsEmpty) { Console.WriteLine("No games with a winner have been played yet."); return; } foreach (var kvp in scores) { Console.WriteLine("Player: " + kvp.Key + " | Wins: " + kvp.Value); } Console.WriteLine("--------------------------\n"); } } ================================================ FILE: solutions/csharp/tictactoe/README.md ================================================ # Designing a Tic Tac Toe Game ## Requirements 1. The Tic-Tac-Toe game should be played on a 3x3 grid. 2. Two players take turns marking their symbols (X or O) on the grid. 3. The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins the game. 4. If all the cells on the grid are filled and no player has won, the game ends in a draw. 5. The game should have a user interface to display the grid and allow players to make their moves. 6. The game should handle player turns and validate moves to ensure they are legal. 7. The game should detect and announce the winner or a draw at the end of the game. ## Classes, Interfaces and Enumerations 1. The **Player** class represents a player in the game, with a name and a symbol (X or O). 2. The **Board** class represents the game board, which is a 3x3 grid. It provides methods to make moves, check for a winner, and check if the board is full. 3. The **Game** class manages the game flow and player interactions. It handles player turns, validates moves, and determines the winner or a draw. 4. The **TicTacToe** class is the entry point of the application and creates instances of the players and the game. ================================================ FILE: solutions/csharp/tictactoe/States/DrawState.cs ================================================ class DrawState : IGameState { public void HandleMove(Game game, Player player, int row, int col) { throw new InvalidMoveException("Game is already over. It was a draw."); } } ================================================ FILE: solutions/csharp/tictactoe/States/IGameState.cs ================================================ interface IGameState { void HandleMove(Game game, Player player, int row, int col); } ================================================ FILE: solutions/csharp/tictactoe/States/InProgressState.cs ================================================ class InProgressState : IGameState { public void HandleMove(Game game, Player player, int row, int col) { if (game.GetCurrentPlayer() != player) { throw new InvalidMoveException("Not your turn!"); } // Place the piece on the board game.GetBoard().PlaceSymbol(row, col, player.GetSymbol()); // Check for a winner or a draw if (game.CheckWinner(player)) { game.SetWinner(player); if (player.GetSymbol() == Symbol.X) { game.SetStatus(GameStatus.WINNER_X); } else { game.SetStatus(GameStatus.WINNER_O); } game.SetState(new WinnerState()); } else if (game.GetBoard().IsFull()) { game.SetStatus(GameStatus.DRAW); game.SetState(new DrawState()); } else { // If the game is still in progress, switch players game.SwitchPlayer(); } } } ================================================ FILE: solutions/csharp/tictactoe/States/WinnerState.cs ================================================ class WinnerState : IGameState { public void HandleMove(Game game, Player player, int row, int col) { throw new InvalidMoveException("Game is already over. " + game.GetWinner().GetName() + " has won."); } } ================================================ FILE: solutions/csharp/tictactoe/Strategy/ColumnWinningStrategy.cs ================================================ class ColumnWinningStrategy : IWinningStrategy { public bool CheckWinner(Board board, Player player) { for (int col = 0; col < board.GetSize(); col++) { bool colWin = true; for (int row = 0; row < board.GetSize(); row++) { if (board.GetCell(row, col).GetSymbol() != player.GetSymbol()) { colWin = false; break; } } if (colWin) return true; } return false; } } ================================================ FILE: solutions/csharp/tictactoe/Strategy/DiagonalWinningStrategy.cs ================================================ class DiagonalWinningStrategy : IWinningStrategy { public bool CheckWinner(Board board, Player player) { // Main diagonal bool mainDiagWin = true; for (int i = 0; i < board.GetSize(); i++) { if (board.GetCell(i, i).GetSymbol() != player.GetSymbol()) { mainDiagWin = false; break; } } if (mainDiagWin) return true; // Anti-diagonal bool antiDiagWin = true; for (int i = 0; i < board.GetSize(); i++) { if (board.GetCell(i, board.GetSize() - 1 - i).GetSymbol() != player.GetSymbol()) { antiDiagWin = false; break; } } return antiDiagWin; } } ================================================ FILE: solutions/csharp/tictactoe/Strategy/IWinningStrategy.cs ================================================ interface IWinningStrategy { bool CheckWinner(Board board, Player player); } ================================================ FILE: solutions/csharp/tictactoe/Strategy/RowWinningStrategy.cs ================================================ class RowWinningStrategy : IWinningStrategy { public bool CheckWinner(Board board, Player player) { for (int row = 0; row < board.GetSize(); row++) { bool rowWin = true; for (int col = 0; col < board.GetSize(); col++) { if (board.GetCell(row, col).GetSymbol() != player.GetSymbol()) { rowWin = false; break; } } if (rowWin) return true; } return false; } } ================================================ FILE: solutions/csharp/tictactoe/TicTacToeDemo.cs ================================================ using System; using System.Collections.Generic; public class TicTacToeDemo { public static void Main() { TicTacToeSystem system = TicTacToeSystem.GetInstance(); Player alice = new Player("Alice", Symbol.X); Player bob = new Player("Bob", Symbol.O); // --- GAME 1: Alice wins --- Console.WriteLine("--- GAME 1: Alice (X) vs. Bob (O) ---"); system.CreateGame(alice, bob); system.PrintBoard(); system.MakeMove(alice, 0, 0); system.MakeMove(bob, 1, 0); system.MakeMove(alice, 0, 1); system.MakeMove(bob, 1, 1); system.MakeMove(alice, 0, 2); // Alice wins, scoreboard is notified Console.WriteLine("----------------------------------------\n"); // --- GAME 2: Bob wins --- Console.WriteLine("--- GAME 2: Alice (X) vs. Bob (O) ---"); system.CreateGame(alice, bob); // A new game instance system.PrintBoard(); system.MakeMove(alice, 0, 0); system.MakeMove(bob, 1, 0); system.MakeMove(alice, 0, 1); system.MakeMove(bob, 1, 1); system.MakeMove(alice, 2, 2); system.MakeMove(bob, 1, 2); // Bob wins, scoreboard is notified Console.WriteLine("----------------------------------------\n"); // --- GAME 3: A Draw --- Console.WriteLine("--- GAME 3: Alice (X) vs. Bob (O) - Draw ---"); system.CreateGame(alice, bob); system.PrintBoard(); system.MakeMove(alice, 0, 0); system.MakeMove(bob, 0, 1); system.MakeMove(alice, 0, 2); system.MakeMove(bob, 1, 1); system.MakeMove(alice, 1, 0); system.MakeMove(bob, 1, 2); system.MakeMove(alice, 2, 1); system.MakeMove(bob, 2, 0); system.MakeMove(alice, 2, 2); // Draw, scoreboard is not notified of a winner Console.WriteLine("----------------------------------------\n"); // --- Final Scoreboard --- // We get the scoreboard from the system and print its final state system.PrintScoreBoard(); } } ================================================ FILE: solutions/csharp/tictactoe/TicTacToeSystem.cs ================================================ class TicTacToeSystem { private static volatile TicTacToeSystem instance; private static readonly object lockObject = new object(); private Game game; private readonly Scoreboard scoreboard; // The system now manages a scoreboard private TicTacToeSystem() { scoreboard = new Scoreboard(); // Create the scoreboard on initialization } public static TicTacToeSystem GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new TicTacToeSystem(); } } } return instance; } public void CreateGame(Player player1, Player player2) { game = new Game(player1, player2); // Register the scoreboard as an observer for this new game game.AddObserver(scoreboard); Console.WriteLine("Game started between " + player1.GetName() + " (X) and " + player2.GetName() + " (O)."); } public void MakeMove(Player player, int row, int col) { if (game == null) { Console.WriteLine("No game in progress. Please create a game first."); return; } try { Console.WriteLine(player.GetName() + " plays at (" + row + ", " + col + ")"); game.MakeMove(player, row, col); PrintBoard(); Console.WriteLine("Game Status: " + game.GetStatus()); if (game.GetWinner() != null) { Console.WriteLine("Winner: " + game.GetWinner().GetName()); } } catch (InvalidMoveException e) { Console.WriteLine("Error: " + e.Message); } } public void PrintBoard() { game.GetBoard().PrintBoard(); } public void PrintScoreBoard() { scoreboard.PrintScores(); } } ================================================ FILE: solutions/csharp/tictactoe/tictactoe.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/trafficsignalsystem/Enums/Direction.cs ================================================ enum Direction { NORTH, SOUTH, EAST, WEST } ================================================ FILE: solutions/csharp/trafficsignalsystem/Enums/LightColor.cs ================================================ enum LightColor { GREEN, YELLOW, RED } ================================================ FILE: solutions/csharp/trafficsignalsystem/IntersectionController.cs ================================================ class IntersectionController { private readonly int id; private readonly Dictionary trafficLights; private IIntersectionState currentState; private readonly long greenDuration; private readonly long yellowDuration; private volatile bool running = true; public IntersectionController(int id, Dictionary trafficLights, long greenDuration, long yellowDuration) { this.id = id; this.trafficLights = trafficLights; this.greenDuration = greenDuration; this.yellowDuration = yellowDuration; this.currentState = new NorthSouthGreenState(); // Initial state for the intersection } public int GetId() => id; public long GetGreenDuration() => greenDuration; public long GetYellowDuration() => yellowDuration; public TrafficLight GetLight(Direction direction) => trafficLights[direction]; public void SetState(IIntersectionState state) { this.currentState = state; } public void Start() { Task.Run(() => Run()); } public void Stop() { this.running = false; } public void Run() { while (running) { try { currentState.Handle(this); } catch (Exception e) { Console.WriteLine($"Intersection {id} encountered an error: {e.Message}"); running = false; } } } } // Builder Pattern class IntersectionControllerBuilder { private readonly int id; private long greenDuration = 5000; // default 5s private long yellowDuration = 2000; // default 2s private readonly List observers = new List(); public IntersectionControllerBuilder(int id) { this.id = id; } public IntersectionControllerBuilder WithDurations(long green, long yellow) { this.greenDuration = green; this.yellowDuration = yellow; return this; } public IntersectionControllerBuilder AddObserver(ITrafficObserver observer) { this.observers.Add(observer); return this; } public IntersectionController Build() { var lights = new Dictionary(); foreach (Direction dir in Enum.GetValues(typeof(Direction)).Cast()) { TrafficLight light = new TrafficLight(id, dir); // Attach all registered observers to each light foreach (var observer in observers) { light.AddObserver(observer); } lights[dir] = light; } return new IntersectionController(id, lights, greenDuration, yellowDuration); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/Observer/CentralMonitor.cs ================================================ class CentralMonitor : ITrafficObserver { public void Update(int intersectionId, Direction direction, LightColor color) { Console.WriteLine($"[MONITOR] Intersection {intersectionId}: Light for {direction} direction changed to {color}."); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/Observer/ITrafficObserver.cs ================================================ interface ITrafficObserver { void Update(int intersectionId, Direction direction, LightColor color); } ================================================ FILE: solutions/csharp/trafficsignalsystem/README.md ================================================ # Designing a Traffic Signal Control System ## Requirements 1. The traffic signal system should control the flow of traffic at an intersection with multiple roads. 2. The system should support different types of signals, such as red, yellow, and green. 3. The duration of each signal should be configurable and adjustable based on traffic conditions. 4. The system should handle the transition between signals smoothly, ensuring safe and efficient traffic flow. 5. The system should be able to detect and handle emergency situations, such as an ambulance or fire truck approaching the intersection. 6. The system should be scalable and extensible to support additional features and functionality. ## Classes, Interfaces and Enumerations 1. The **Signal** enum represents the different states of a traffic light: red, yellow, and green. 2. The **Road** class represents a road in the traffic signal system, with properties such as ID, name, and an associated traffic light. 3. The **TrafficLight** class represents a traffic light, with properties such as ID, current signal, and durations for each signal state. It provides methods to change the signal and notify observers (e.g., roads) about signal changes. 4. The **TrafficController** class serves as the central controller for the traffic signal system. It follows the Singleton pattern to ensure a single instance of the controller. It manages the roads and their associated traffic lights, starts the traffic control process, and handles emergency situations. 5. The **TrafficSignalSystemDemo** class is the main entry point of the application. It demonstrates the usage of the traffic signal system by creating roads, traffic lights, assigning traffic lights to roads, and starting the traffic control process. ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Intersection/EastWestGreenState.cs ================================================ class EastWestGreenState : IIntersectionState { public void Handle(IntersectionController context) { Console.WriteLine($"\n--- INTERSECTION {context.GetId()}: Cycle -> East-West GREEN ---"); // Turn East and West green, ensure North and South are red context.GetLight(Direction.EAST).StartGreen(); context.GetLight(Direction.WEST).StartGreen(); context.GetLight(Direction.NORTH).SetColor(LightColor.RED); context.GetLight(Direction.SOUTH).SetColor(LightColor.RED); // Wait for green light duration Thread.Sleep((int)context.GetGreenDuration()); // Transition East and West to Yellow context.GetLight(Direction.EAST).Transition(); context.GetLight(Direction.WEST).Transition(); // Wait for yellow light duration Thread.Sleep((int)context.GetYellowDuration()); // Transition East and West to Red context.GetLight(Direction.EAST).Transition(); context.GetLight(Direction.WEST).Transition(); // Change the intersection's state back to let North-South go context.SetState(new NorthSouthGreenState()); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Intersection/IIntersectionState.cs ================================================ interface IIntersectionState { void Handle(IntersectionController context); } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Intersection/NorthSouthGreenState.cs ================================================ class NorthSouthGreenState : IIntersectionState { public void Handle(IntersectionController context) { Console.WriteLine($"\n--- INTERSECTION {context.GetId()}: Cycle Start -> North-South GREEN ---"); // Turn North and South green, ensure East and West are red context.GetLight(Direction.NORTH).StartGreen(); context.GetLight(Direction.SOUTH).StartGreen(); context.GetLight(Direction.EAST).SetColor(LightColor.RED); context.GetLight(Direction.WEST).SetColor(LightColor.RED); // Wait for green light duration Thread.Sleep((int)context.GetGreenDuration()); // Transition North and South to Yellow context.GetLight(Direction.NORTH).Transition(); context.GetLight(Direction.SOUTH).Transition(); // Wait for yellow light duration Thread.Sleep((int)context.GetYellowDuration()); // Transition North and South to Red context.GetLight(Direction.NORTH).Transition(); context.GetLight(Direction.SOUTH).Transition(); // Change the intersection's state to let East-West go context.SetState(new EastWestGreenState()); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Light/GreenState.cs ================================================ class GreenState : ISignalState { public void Handle(TrafficLight context) { context.SetColor(LightColor.GREEN); // After being green, the next state is yellow. context.SetNextState(new YellowState()); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Light/ISignalState.cs ================================================ interface ISignalState { void Handle(TrafficLight context); } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Light/RedState.cs ================================================ class RedState : ISignalState { public void Handle(TrafficLight context) { context.SetColor(LightColor.RED); // Red is a stable state, it transitions to green only when the intersection controller commands it. // So, the next state is self. context.SetNextState(new RedState()); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/States/Light/YellowState.cs ================================================ class YellowState : ISignalState { public void Handle(TrafficLight context) { context.SetColor(LightColor.YELLOW); // After being yellow, the next state is red. context.SetNextState(new RedState()); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/TrafficControlSystem.cs ================================================ class TrafficControlSystem { private static TrafficControlSystem instance; private static readonly object lockObject = new object(); private readonly List intersections = new List(); private readonly List tasks = new List(); private TrafficControlSystem() { } public static TrafficControlSystem GetInstance() { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new TrafficControlSystem(); } } } return instance; } public void AddIntersection(int intersectionId, int greenDuration, int yellowDuration) { IntersectionController intersection = new IntersectionControllerBuilder(intersectionId) .WithDurations(greenDuration, yellowDuration) .AddObserver(new CentralMonitor()) .Build(); intersections.Add(intersection); } public void StartSystem() { if (intersections.Count == 0) { Console.WriteLine("No intersections to manage. System not starting."); return; } Console.WriteLine("--- Starting Traffic Control System ---"); foreach (var intersection in intersections) { Task task = Task.Run(() => intersection.Run()); tasks.Add(task); } } public void StopSystem() { Console.WriteLine("\n--- Shutting Down Traffic Control System ---"); foreach (var intersection in intersections) { intersection.Stop(); } Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(5)); Console.WriteLine("All intersections stopped. System shut down."); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/TrafficLight.cs ================================================ class TrafficLight { private readonly int intersectionId; private readonly Direction direction; private LightColor currentColor; private ISignalState currentState; private ISignalState nextState; private readonly List observers = new List(); public TrafficLight(int intersectionId, Direction direction) { this.intersectionId = intersectionId; this.direction = direction; this.currentState = new RedState(); // Default state is Red this.currentState.Handle(this); } // This is called by the IntersectionController to initiate a G-Y-R cycle public void StartGreen() { this.currentState = new GreenState(); this.currentState.Handle(this); } // This is called by the IntersectionController to transition from G->Y or Y->R public void Transition() { this.currentState = this.nextState; this.currentState.Handle(this); } public void SetColor(LightColor color) { if (this.currentColor != color) { this.currentColor = color; NotifyObservers(); } } public void SetNextState(ISignalState state) { this.nextState = state; } public LightColor GetCurrentColor() => currentColor; public Direction GetDirection() => direction; // Observer pattern methods public void AddObserver(ITrafficObserver observer) { observers.Add(observer); } public void RemoveObserver(ITrafficObserver observer) { observers.Remove(observer); } private void NotifyObservers() { foreach (var observer in observers) { observer.Update(intersectionId, direction, currentColor); } } } ================================================ FILE: solutions/csharp/trafficsignalsystem/TrafficSystemDemo.cs ================================================ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; public class TrafficSystemDemo { public static void Main(string[] args) { // 1. Get the singleton TrafficControlSystem instance TrafficControlSystem system = TrafficControlSystem.GetInstance(); // 2. Add intersections to the system system.AddIntersection(1, 500, 200); system.AddIntersection(2, 700, 150); // 3. Start the system system.StartSystem(); // 4. Let the simulation run for a while (e.g., 5 seconds) try { Thread.Sleep(5000); } catch (ThreadInterruptedException) { Thread.CurrentThread.Interrupt(); } // 5. Stop the system gracefully system.StopSystem(); } } ================================================ FILE: solutions/csharp/trafficsignalsystem/trafficsignalsystem.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/vendingmachine/Enum/Coin.cs ================================================ enum Coin { PENNY = 1, NICKEL = 5, DIME = 10, QUARTER = 25 } ================================================ FILE: solutions/csharp/vendingmachine/Models/Inventory.cs ================================================ class Inventory { private readonly Dictionary itemMap = new Dictionary(); private readonly Dictionary stockMap = new Dictionary(); public void AddItem(string code, Item item, int quantity) { itemMap[code] = item; stockMap[code] = quantity; } public Item GetItem(string code) { return itemMap.GetValueOrDefault(code); } public bool IsAvailable(string code) { return stockMap.GetValueOrDefault(code, 0) > 0; } public void ReduceStock(string code) { if (stockMap.ContainsKey(code)) { stockMap[code] = stockMap[code] - 1; } } } ================================================ FILE: solutions/csharp/vendingmachine/Models/Item.cs ================================================ class Item { private string code; private string name; private int price; public Item(string code, string name, int price) { this.code = code; this.name = name; this.price = price; } public string GetName() { return name; } public int GetPrice() { return price; } } ================================================ FILE: solutions/csharp/vendingmachine/README.md ================================================ # Designing a Vending Machine ## Requirements 1. The vending machine should support multiple products with different prices and quantities. 1. The machine should accept coins and notes of different denominations. 1. The machine should dispense the selected product and return change if necessary. 1. The machine should keep track of the available products and their quantities. 1. The machine should handle multiple transactions concurrently and ensure data consistency. 1. The machine should provide an interface for restocking products and collecting money. 1. The machine should handle exceptional scenarios, such as insufficient funds or out-of-stock products. ## Classes, Interfaces and Enumerations 1. The **Product** class represents a product in the vending machine, with properties such as name and price. 2. The **Coin** and **Note** enums represent the different denominations of coins and notes accepted by the vending machine. 3. The **Inventory** class manages the available products and their quantities in the vending machine. It uses a concurrent hash map to ensure thread safety. 4. The **VendingMachineState** interface defines the behavior of the vending machine in different states, such as idle, ready, and dispense. 5. The **IdleState**, **ReadyState**, and **DispenseState** classes implement the VendingMachineState interface and define the specific behaviors for each state. 6. The **VendingMachine** class is the main class that represents the vending machine. It follows the Singleton pattern to ensure only one instance of the vending machine exists. 7. The VendingMachine class maintains the current state, selected product, total payment, and provides methods for state transitions and payment handling. 8. The **VendingMachineDemo** class demonstrates the usage of the vending machine by adding products to the inventory, selecting products, inserting coins and notes, dispensing products, and returning change. ================================================ FILE: solutions/csharp/vendingmachine/States/DispensingState.cs ================================================ class DispensingState : VendingMachineState { public DispensingState(VendingMachine machine) : base(machine) { } public override void InsertCoin(Coin coin) { Console.WriteLine("Currently dispensing. Please wait."); } public override void SelectItem(string code) { Console.WriteLine("Currently dispensing. Please wait."); } public override void Dispense() { // already triggered by HasMoneyState } public override void Refund() { Console.WriteLine("Dispensing in progress. Refund not allowed."); } } ================================================ FILE: solutions/csharp/vendingmachine/States/HasMoneyState.cs ================================================ class HasMoneyState : VendingMachineState { public HasMoneyState(VendingMachine machine) : base(machine) { } public override void InsertCoin(Coin coin) { Console.WriteLine("Already received full amount."); } public override void SelectItem(string code) { Console.WriteLine("Item already selected."); } public override void Dispense() { machine.SetState(new DispensingState(machine)); machine.DispenseItem(); } public override void Refund() { machine.RefundBalance(); machine.Reset(); machine.SetState(new IdleState(machine)); } } ================================================ FILE: solutions/csharp/vendingmachine/States/IdleState.cs ================================================ class IdleState : VendingMachineState { public IdleState(VendingMachine machine) : base(machine) { } public override void InsertCoin(Coin coin) { Console.WriteLine("Please select an item before inserting money."); } public override void SelectItem(string code) { if (!machine.GetInventory().IsAvailable(code)) { Console.WriteLine("Item not available."); return; } machine.SetSelectedItemCode(code); machine.SetState(new ItemSelectedState(machine)); Console.WriteLine("Item selected: " + code); } public override void Dispense() { Console.WriteLine("No item selected."); } public override void Refund() { Console.WriteLine("No money to refund."); } } ================================================ FILE: solutions/csharp/vendingmachine/States/ItemSelectedState.cs ================================================ class ItemSelectedState : VendingMachineState { public ItemSelectedState(VendingMachine machine) : base(machine) { } public override void InsertCoin(Coin coin) { machine.AddBalance((int)coin); Console.WriteLine("Coin Inserted: " + (int)coin); int price = machine.GetSelectedItem().GetPrice(); if (machine.GetBalance() >= price) { Console.WriteLine("Sufficient money received."); machine.SetState(new HasMoneyState(machine)); } } public override void SelectItem(string code) { Console.WriteLine("Item already selected."); } public override void Dispense() { Console.WriteLine("Please insert sufficient money."); } public override void Refund() { machine.Reset(); machine.SetState(new IdleState(machine)); } } ================================================ FILE: solutions/csharp/vendingmachine/States/VendingMachineState.cs ================================================ abstract class VendingMachineState { protected VendingMachine machine; public VendingMachineState(VendingMachine machine) { this.machine = machine; } public abstract void InsertCoin(Coin coin); public abstract void SelectItem(string code); public abstract void Dispense(); public abstract void Refund(); } ================================================ FILE: solutions/csharp/vendingmachine/VendingMachine.cs ================================================ class VendingMachine { private static readonly VendingMachine INSTANCE = new VendingMachine(); private readonly Inventory inventory = new Inventory(); private VendingMachineState currentState; private int balance = 0; private string selectedItemCode; public VendingMachine() { currentState = new IdleState(this); } public static VendingMachine GetInstance() { return INSTANCE; } public void InsertCoin(Coin coin) { currentState.InsertCoin(coin); } public Item AddItem(string code, string name, int price, int quantity) { Item item = new Item(code, name, price); inventory.AddItem(code, item, quantity); return item; } public void SelectItem(string code) { currentState.SelectItem(code); } public void Dispense() { currentState.Dispense(); } public void DispenseItem() { Item item = inventory.GetItem(selectedItemCode); if (balance >= item.GetPrice()) { inventory.ReduceStock(selectedItemCode); balance -= item.GetPrice(); Console.WriteLine("Dispensed: " + item.GetName()); if (balance > 0) { Console.WriteLine("Returning change: " + balance); } } Reset(); SetState(new IdleState(this)); } public void RefundBalance() { Console.WriteLine("Refunding: " + balance); balance = 0; } public void Reset() { selectedItemCode = null; balance = 0; } public void AddBalance(int value) { balance += value; } public Item GetSelectedItem() { return inventory.GetItem(selectedItemCode); } public void SetSelectedItemCode(string code) { this.selectedItemCode = code; } public void SetState(VendingMachineState state) { this.currentState = state; } public Inventory GetInventory() { return inventory; } public int GetBalance() { return balance; } } ================================================ FILE: solutions/csharp/vendingmachine/VendingMachineDemo.cs ================================================ using System; using System.Collections.Generic; public class VendingMachineDemo { public static void Main() { VendingMachine vendingMachine = VendingMachine.GetInstance(); // Add products to the inventory vendingMachine.AddItem("A1", "Coke", 25, 3); vendingMachine.AddItem("A2", "Pepsi", 25, 2); vendingMachine.AddItem("B1", "Water", 10, 5); // Select a product Console.WriteLine("\n--- Step 1: Select an item ---"); vendingMachine.SelectItem("A1"); // Insert coins Console.WriteLine("\n--- Step 2: Insert coins ---"); vendingMachine.InsertCoin(Coin.DIME); // 10 vendingMachine.InsertCoin(Coin.DIME); // 10 vendingMachine.InsertCoin(Coin.NICKEL); // 5 // Dispense the product Console.WriteLine("\n--- Step 3: Dispense item ---"); vendingMachine.Dispense(); // Should dispense Coke // Select another item Console.WriteLine("\n--- Step 4: Select another item ---"); vendingMachine.SelectItem("B1"); // Insert more amount Console.WriteLine("\n--- Step 5: Insert more than needed ---"); vendingMachine.InsertCoin(Coin.QUARTER); // 25 // Try to dispense the product Console.WriteLine("\n--- Step 6: Dispense and return change ---"); vendingMachine.Dispense(); } } ================================================ FILE: solutions/csharp/vendingmachine/vendingmachine.csproj ================================================  Exe net8.0 enable enable ================================================ FILE: solutions/csharp/votingsystem/README.md ================================================ ### Airline Management System This is a simple airline management system that allows you to manage flights, passengers, and bookings. ================================================ FILE: solutions/golang/airlinemanagementsystem/README.md ================================================ # Designing an Airline Management System ## Requirements 1. The airline management system should allow users to search for flights based on source, destination, and date. 2. Users should be able to book flights, select seats, and make payments. 3. The system should manage flight schedules, aircraft assignments, and crew assignments. 4. The system should handle passenger information, including personal details and baggage information. 5. The system should support different types of users, such as passengers, airline staff, and administrators. 6. The system should be able to handle cancellations, refunds, and flight changes. 7. The system should ensure data consistency and handle concurrent access to shared resources. 8. The system should be scalable and extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Flight** class represents a flight in the airline management system, with properties such as flight number, source, destination, departure time, arrival time, and available seats. 2. The **Aircraft** class represents an aircraft, with properties like tail number, model, and total seats. 3. The **Passenger** class represents a passenger, with properties such as ID, name, email, and phone number. 4. The **Booking** class represents a booking made by a passenger for a specific flight and seat, with properties such as booking number, flight, passenger, seat, price, and booking status. 5. The **Seat** class represents a seat on a flight, with properties like seat number, seat type, and seat status. 6. The **Payment** class represents a payment made for a booking, with properties such as payment ID, payment method, amount, and payment status. 7. The **FlightSearch** class provides functionality to search for flights based on source, destination, and date. 8. The **BookingManager** class manages the creation and cancellation of bookings. It follows the Singleton pattern to ensure a single instance of the booking manager. 9. The **PaymentProcessor** class handles the processing of payments. It follows the Singleton pattern to ensure a single instance of the payment processor. 10. The **AirlineManagementSystem** class serves as the main entry point of the system, combining all the components and providing methods for flight management, booking, payment processing, and other operations. ================================================ FILE: solutions/golang/airlinemanagementsystem/aircraft.go ================================================ package airlinemanagementsystem type Aircraft struct { TailNumber string Model string TotalSeats int } func NewAircraft(tailNumber, model string, totalSeats int) *Aircraft { return &Aircraft{ TailNumber: tailNumber, Model: model, TotalSeats: totalSeats, } } ================================================ FILE: solutions/golang/airlinemanagementsystem/airline_management_system.go ================================================ package airlinemanagementsystem import ( "sync" "time" ) type AirlineManagementSystem struct { flights []*Flight aircrafts []*Aircraft flightSearch *FlightSearch bookingManager *BookingManager paymentProcessor *PaymentProcessor mu sync.RWMutex } func NewAirlineManagementSystem() *AirlineManagementSystem { system := &AirlineManagementSystem{ flights: make([]*Flight, 0), aircrafts: make([]*Aircraft, 0), bookingManager: GetBookingManager(), paymentProcessor: GetPaymentProcessor(), } system.flightSearch = NewFlightSearch(system.flights) return system } func (ams *AirlineManagementSystem) AddFlight(flight *Flight) { ams.mu.Lock() defer ams.mu.Unlock() ams.flights = append(ams.flights, flight) } func (ams *AirlineManagementSystem) AddAircraft(aircraft *Aircraft) { ams.mu.Lock() defer ams.mu.Unlock() ams.aircrafts = append(ams.aircrafts, aircraft) } func (ams *AirlineManagementSystem) SearchFlights(source, destination string, date time.Time) []*Flight { return ams.flightSearch.SearchFlights(source, destination, date) } func (ams *AirlineManagementSystem) BookFlight(flight *Flight, passenger *Passenger, seat *Seat, price float64) *Booking { return ams.bookingManager.CreateBooking(flight, passenger, seat, price) } func (ams *AirlineManagementSystem) CancelBooking(bookingNumber string) { ams.bookingManager.CancelBooking(bookingNumber) } func (ams *AirlineManagementSystem) ProcessPayment(payment *Payment) { ams.paymentProcessor.ProcessPayment(payment) } ================================================ FILE: solutions/golang/airlinemanagementsystem/airline_management_system_demo.go ================================================ package airlinemanagementsystem import ( "fmt" "time" ) type Demo struct { system *AirlineManagementSystem } func NewDemo() *Demo { return &Demo{ system: NewAirlineManagementSystem(), } } func Run() { system := NewAirlineManagementSystem() // Create users passenger1 := NewPassenger( "U001", "John Doe", "john@example.com", "1234567890", ) // Create flights departureTime1 := time.Now().AddDate(0, 0, 1) arrivalTime1 := departureTime1.Add(2 * time.Hour) flight1 := NewFlight( "F001", "New York", "London", departureTime1, arrivalTime1, ) departureTime2 := time.Now().AddDate(0, 0, 3) arrivalTime2 := departureTime2.Add(5 * time.Hour) flight2 := NewFlight( "F002", "Paris", "Tokyo", departureTime2, arrivalTime2, ) system.AddFlight(flight1) system.AddFlight(flight2) // Create aircrafts aircraft1 := NewAircraft("A001", "Boeing 747", 300) aircraft2 := NewAircraft("A002", "Airbus A380", 500) system.AddAircraft(aircraft1) system.AddAircraft(aircraft2) // Search flights searchDate := time.Now().AddDate(0, 0, 1) searchResults := system.SearchFlights("New York", "London", searchDate) fmt.Println("Search Results:") for _, flight := range searchResults { fmt.Printf("Flight: %s - %s to %s\n", flight.FlightNumber, flight.Source, flight.Destination, ) } // Create seat seat := NewSeat("25A", SeatTypeEconomy) // Book a flight booking := system.BookFlight(flight1, passenger1, seat, 100.0) if booking != nil { fmt.Printf("Booking successful. Booking ID: %s\n", booking.BookingNumber) } else { fmt.Println("Booking failed.") } // Cancel the booking system.CancelBooking(booking.BookingNumber) fmt.Println("Booking cancelled.") } ================================================ FILE: solutions/golang/airlinemanagementsystem/booking.go ================================================ package airlinemanagementsystem import "sync" type Booking struct { BookingNumber string Flight *Flight Passenger *Passenger Seat *Seat Price float64 Status BookingStatus mu sync.RWMutex } func NewBooking(bookingNumber string, flight *Flight, passenger *Passenger, seat *Seat, price float64) *Booking { return &Booking{ BookingNumber: bookingNumber, Flight: flight, Passenger: passenger, Seat: seat, Price: price, Status: BookingStatusConfirmed, } } func (b *Booking) Cancel() { b.mu.Lock() defer b.mu.Unlock() b.Status = BookingStatusCancelled } ================================================ FILE: solutions/golang/airlinemanagementsystem/booking_manager.go ================================================ package airlinemanagementsystem import ( "fmt" "sync" "sync/atomic" "time" ) type BookingManager struct { bookings map[string]*Booking bookingCounter int64 mu sync.RWMutex } var ( bookingManager *BookingManager bookingOnce sync.Once ) func GetBookingManager() *BookingManager { bookingOnce.Do(func() { bookingManager = &BookingManager{ bookings: make(map[string]*Booking), } }) return bookingManager } func (bm *BookingManager) CreateBooking(flight *Flight, passenger *Passenger, seat *Seat, price float64) *Booking { bm.mu.Lock() defer bm.mu.Unlock() bookingNumber := bm.generateBookingNumber() booking := NewBooking(bookingNumber, flight, passenger, seat, price) bm.bookings[bookingNumber] = booking return booking } func (bm *BookingManager) CancelBooking(bookingNumber string) { bm.mu.Lock() defer bm.mu.Unlock() if booking, exists := bm.bookings[bookingNumber]; exists { booking.Cancel() } } func (bm *BookingManager) generateBookingNumber() string { counter := atomic.AddInt64(&bm.bookingCounter, 1) return fmt.Sprintf("BKG%s%06d", time.Now().Format("20060102150405"), counter) } ================================================ FILE: solutions/golang/airlinemanagementsystem/flight.go ================================================ package airlinemanagementsystem import ( "sync" "time" ) type Flight struct { FlightNumber string Source string Destination string DepartureTime time.Time ArrivalTime time.Time AvailableSeats []*Seat mu sync.RWMutex } func NewFlight(flightNumber, source, destination string, departureTime, arrivalTime time.Time) *Flight { return &Flight{ FlightNumber: flightNumber, Source: source, Destination: destination, DepartureTime: departureTime, ArrivalTime: arrivalTime, AvailableSeats: make([]*Seat, 0), } } ================================================ FILE: solutions/golang/airlinemanagementsystem/flight_search.go ================================================ package airlinemanagementsystem import ( "strings" "sync" "time" ) type FlightSearch struct { flights []*Flight mu sync.RWMutex } func NewFlightSearch(flights []*Flight) *FlightSearch { return &FlightSearch{ flights: flights, } } func (fs *FlightSearch) SearchFlights(source, destination string, date time.Time) []*Flight { fs.mu.RLock() defer fs.mu.RUnlock() var results []*Flight source = strings.ToLower(source) destination = strings.ToLower(destination) for _, flight := range fs.flights { if strings.ToLower(flight.Source) == source && strings.ToLower(flight.Destination) == destination && flight.DepartureTime.Year() == date.Year() && flight.DepartureTime.Month() == date.Month() && flight.DepartureTime.Day() == date.Day() { results = append(results, flight) } } return results } ================================================ FILE: solutions/golang/airlinemanagementsystem/passenger.go ================================================ package airlinemanagementsystem type Passenger struct { ID string Name string Email string Phone string } func NewPassenger(id, name, email, phone string) *Passenger { return &Passenger{ ID: id, Name: name, Email: email, Phone: phone, } } ================================================ FILE: solutions/golang/airlinemanagementsystem/payment.go ================================================ package airlinemanagementsystem import "sync" type Payment struct { PaymentID string PaymentMethod string Amount float64 status PaymentStatus mu sync.RWMutex } func NewPayment(paymentID, paymentMethod string, amount float64) *Payment { return &Payment{ PaymentID: paymentID, PaymentMethod: paymentMethod, Amount: amount, status: PaymentStatusPending, } } func (p *Payment) ProcessPayment() { p.mu.Lock() defer p.mu.Unlock() p.status = PaymentStatusCompleted } ================================================ FILE: solutions/golang/airlinemanagementsystem/payment_processor.go ================================================ package airlinemanagementsystem import "sync" type PaymentProcessor struct { mu sync.Mutex } var ( paymentProcessor *PaymentProcessor paymentOnce sync.Once ) func GetPaymentProcessor() *PaymentProcessor { paymentOnce.Do(func() { paymentProcessor = &PaymentProcessor{} }) return paymentProcessor } func (p *PaymentProcessor) ProcessPayment(payment *Payment) { p.mu.Lock() defer p.mu.Unlock() payment.ProcessPayment() } ================================================ FILE: solutions/golang/airlinemanagementsystem/seat.go ================================================ package airlinemanagementsystem import "sync" type Seat struct { SeatNumber string Type SeatType status SeatStatus mu sync.RWMutex } func NewSeat(seatNumber string, seatType SeatType) *Seat { return &Seat{ SeatNumber: seatNumber, Type: seatType, status: SeatStatusAvailable, } } func (s *Seat) Reserve() { s.mu.Lock() defer s.mu.Unlock() s.status = SeatStatusReserved } func (s *Seat) Release() { s.mu.Lock() defer s.mu.Unlock() s.status = SeatStatusAvailable } func (s *Seat) GetStatus() SeatStatus { s.mu.RLock() defer s.mu.RUnlock() return s.status } ================================================ FILE: solutions/golang/airlinemanagementsystem/types.go ================================================ package airlinemanagementsystem type SeatType int type SeatStatus int type BookingStatus int type PaymentStatus int const ( SeatTypeEconomy SeatType = iota SeatTypePremiumEconomy SeatTypeBusiness SeatTypeFirstClass ) const ( SeatStatusAvailable SeatStatus = iota SeatStatusReserved SeatStatusOccupied ) const ( BookingStatusConfirmed BookingStatus = iota BookingStatusCancelled BookingStatusPending BookingStatusExpired ) const ( PaymentStatusPending PaymentStatus = iota PaymentStatusCompleted PaymentStatusFailed PaymentStatusRefunded ) ================================================ FILE: solutions/golang/app.log ================================================ [DEBUG] 1730056952254 - This is a debug message [INFO] 1730056952255 - This is an information message [DEBUG] 1730091879648 - This is a debug message [INFO] 1730091879648 - This is an information message ================================================ FILE: solutions/golang/atm/README.md ================================================ # Designing an ATM System ## Requirements 1. The ATM system should support basic operations such as balance inquiry, cash withdrawal, and cash deposit. 2. Users should be able to authenticate themselves using a card and a PIN (Personal Identification Number). 3. The system should interact with a bank's backend system to validate user accounts and perform transactions. 4. The ATM should have a cash dispenser to dispense cash to users. 5. The system should handle concurrent access and ensure data consistency. 6. The ATM should have a user-friendly interface for users to interact with. ## Classes, Interfaces and Enumerations 1. The **Card** class represents an ATM card with a card number and PIN. 2. The **Account** class represents a bank account with an account number and balance. It provides methods to debit and credit the account balance. 3. The **Transaction** class is an abstract base class for different types of transactions, such as withdrawal and deposit. It is extended by WithdrawalTransaction and DepositTransaction classes. 4. The **BankingService** class manages the bank accounts and processes transactions. It uses a thread-safe ConcurrentHashMap to store and retrieve account information. 5. The **CashDispenser** class represents the ATM's cash dispenser and handles the dispensing of cash. It uses synchronization to ensure thread safety when dispensing cash. 6. The **ATM** class serves as the main interface for ATM operations. It interacts with the BankingService and CashDispenser to perform user authentication, balance inquiry, cash withdrawal, and cash deposit. 7. The **ATMDriver** class demonstrates the usage of the ATM system by creating sample accounts and performing ATM operations. ================================================ FILE: solutions/golang/atm/account.go ================================================ package atm import "sync" type Account struct { accountNumber string balance float64 mu sync.Mutex } func NewAccount(accountNumber string, balance float64) *Account { return &Account{ accountNumber: accountNumber, balance: balance, } } func (a *Account) GetAccountNumber() string { return a.accountNumber } func (a *Account) GetBalance() float64 { a.mu.Lock() defer a.mu.Unlock() return a.balance } func (a *Account) Debit(amount float64) error { a.mu.Lock() defer a.mu.Unlock() if a.balance < amount { return ErrInsufficientFunds } a.balance -= amount return nil } func (a *Account) Credit(amount float64) error { a.mu.Lock() defer a.mu.Unlock() a.balance += amount return nil } ================================================ FILE: solutions/golang/atm/atm.go ================================================ package atm import ( "errors" "fmt" "sync/atomic" "time" ) type ATM struct { bankingService *BankingService cashDispenser *CashDispenser txnCounter int64 } func NewATM(bankingService *BankingService, cashDispenser *CashDispenser) *ATM { return &ATM{ bankingService: bankingService, cashDispenser: cashDispenser, } } func (a *ATM) AuthenticateUser(card *Card) error { // Authentication logic would go here return nil } func (a *ATM) CheckBalance(accountNumber string) (float64, error) { account := a.bankingService.GetAccount(accountNumber) if account == nil { return 0, errors.New("account not found") } return account.GetBalance(), nil } func (a *ATM) WithdrawCash(accountNumber string, amount float64) error { account := a.bankingService.GetAccount(accountNumber) if account == nil { return errors.New("account not found") } transaction := NewWithdrawalTransaction(a.generateTransactionID(), account, amount) if err := a.bankingService.ProcessTransaction(transaction); err != nil { return err } return a.cashDispenser.DispenseCash(int(amount)) } func (a *ATM) DepositCash(accountNumber string, amount float64) error { account := a.bankingService.GetAccount(accountNumber) if account == nil { return errors.New("account not found") } transaction := NewDepositTransaction(a.generateTransactionID(), account, amount) return a.bankingService.ProcessTransaction(transaction) } func (a *ATM) generateTransactionID() string { txnNumber := atomic.AddInt64(&a.txnCounter, 1) timestamp := time.Now().Format("20060102150405") return fmt.Sprintf("TXN%s%010d", timestamp, txnNumber) } ================================================ FILE: solutions/golang/atm/atm_demo.go ================================================ package atm import ( "fmt" ) func Run() { bankingService := NewBankingService() cashDispenser := NewCashDispenser(10000) atmMachine := NewATM(bankingService, cashDispenser) // Create sample accounts bankingService.CreateAccount("1234567890", 1000.0) bankingService.CreateAccount("9876543210", 500.0) // Create card and authenticate card := NewCard("1234567890", "1234") if err := atmMachine.AuthenticateUser(card); err != nil { fmt.Printf("Authentication failed: %v\n", err) return } // Check balance if balance, err := atmMachine.CheckBalance("1234567890"); err == nil { fmt.Printf("Account balance: %.2f\n", balance) } else { fmt.Printf("Error checking balance: %v\n", err) } // Withdraw cash if err := atmMachine.WithdrawCash("1234567890", 500.0); err == nil { fmt.Println("Successfully withdrew $500") } else { fmt.Printf("Error withdrawing cash: %v\n", err) } // Deposit cash if err := atmMachine.DepositCash("9876543210", 200.0); err == nil { fmt.Println("Successfully deposited $200") } else { fmt.Printf("Error depositing cash: %v\n", err) } // Check updated balance if balance, err := atmMachine.CheckBalance("1234567890"); err == nil { fmt.Printf("Updated account balance: %.2f\n", balance) } else { fmt.Printf("Error checking balance: %v\n", err) } } ================================================ FILE: solutions/golang/atm/banking_service.go ================================================ package atm import ( "sync" ) type BankingService struct { accounts map[string]*Account mu sync.RWMutex } func NewBankingService() *BankingService { return &BankingService{ accounts: make(map[string]*Account), } } func (bs *BankingService) CreateAccount(accountNumber string, initialBalance float64) { bs.mu.Lock() defer bs.mu.Unlock() bs.accounts[accountNumber] = NewAccount(accountNumber, initialBalance) } func (bs *BankingService) GetAccount(accountNumber string) *Account { bs.mu.RLock() defer bs.mu.RUnlock() return bs.accounts[accountNumber] } func (bs *BankingService) ProcessTransaction(transaction Transaction) error { return transaction.Execute() } ================================================ FILE: solutions/golang/atm/card.go ================================================ package atm type Card struct { CardNumber string PIN string } func NewCard(cardNumber, pin string) *Card { return &Card{ CardNumber: cardNumber, PIN: pin, } } ================================================ FILE: solutions/golang/atm/cash_dispenser.go ================================================ package atm import ( "sync" ) type CashDispenser struct { cashAvailable int mu sync.Mutex } func NewCashDispenser(initialCash int) *CashDispenser { return &CashDispenser{ cashAvailable: initialCash, } } func (cd *CashDispenser) DispenseCash(amount int) error { cd.mu.Lock() defer cd.mu.Unlock() if amount > cd.cashAvailable { return ErrInsufficientCashInATM } cd.cashAvailable -= amount return nil } ================================================ FILE: solutions/golang/atm/deposit_transaction.go ================================================ package atm type DepositTransaction struct { BaseTransaction } func NewDepositTransaction(transactionID string, account *Account, amount float64) *DepositTransaction { return &DepositTransaction{ BaseTransaction: BaseTransaction{ TransactionID: transactionID, Account: account, Amount: amount, }, } } func (t *DepositTransaction) Execute() error { return t.Account.Credit(t.Amount) } ================================================ FILE: solutions/golang/atm/errors.go ================================================ package atm import "errors" var ( ErrInsufficientFunds = errors.New("insufficient funds in account") ErrInsufficientCashInATM = errors.New("insufficient cash available in ATM") ErrInvalidCard = errors.New("invalid card") ErrInvalidPIN = errors.New("invalid PIN") ) ================================================ FILE: solutions/golang/atm/transaction.go ================================================ package atm type Transaction interface { Execute() error } type BaseTransaction struct { TransactionID string Account *Account Amount float64 } ================================================ FILE: solutions/golang/atm/withdrawal_transaction.go ================================================ package atm type WithdrawalTransaction struct { BaseTransaction } func NewWithdrawalTransaction(transactionID string, account *Account, amount float64) *WithdrawalTransaction { return &WithdrawalTransaction{ BaseTransaction: BaseTransaction{ TransactionID: transactionID, Account: account, Amount: amount, }, } } func (t *WithdrawalTransaction) Execute() error { return t.Account.Debit(t.Amount) } ================================================ FILE: solutions/golang/carrentalsystem/README.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: solutions/golang/carrentalsystem/car.go ================================================ package carrentalsystem import "sync" type Car struct { Make string Model string Year int LicensePlate string RentalPricePerDay float64 available bool mu sync.Mutex } func NewCar(make, model string, year int, licensePlate string, rentalPricePerDay float64) *Car { return &Car{ Make: make, Model: model, Year: year, LicensePlate: licensePlate, RentalPricePerDay: rentalPricePerDay, available: true, } } func (c *Car) IsAvailable() bool { c.mu.Lock() defer c.mu.Unlock() return c.available } func (c *Car) SetAvailable(available bool) { c.mu.Lock() defer c.mu.Unlock() c.available = available } ================================================ FILE: solutions/golang/carrentalsystem/car_rental_system_demo.go ================================================ package carrentalsystem import ( "fmt" "time" ) func Run() { rentalSystem := GetRentalSystem() // Add cars to the rental system rentalSystem.AddCar(NewCar("Toyota", "Camry", 2022, "ABC123", 50.0)) rentalSystem.AddCar(NewCar("Honda", "Civic", 2021, "XYZ789", 45.0)) rentalSystem.AddCar(NewCar("Ford", "Mustang", 2023, "DEF456", 80.0)) // Create customer customer := NewCustomer("John Doe", "john@example.com", "DL1234") // Make reservation startDate := time.Now() endDate := startDate.AddDate(0, 0, 3) availableCars := rentalSystem.SearchCars("Toyota", "Camry", startDate, endDate) if len(availableCars) > 0 { selectedCar := availableCars[0] reservation, err := rentalSystem.MakeReservation(customer, selectedCar, startDate, endDate) if err == nil { if rentalSystem.ProcessPayment(reservation) { fmt.Printf("Reservation successful. Reservation ID: %s\n", reservation.ReservationID) } else { fmt.Println("Payment failed. Reservation canceled.") rentalSystem.CancelReservation(reservation.ReservationID) } } else { fmt.Printf("Reservation failed: %v\n", err) } } else { fmt.Println("No available cars found for the given criteria.") } } ================================================ FILE: solutions/golang/carrentalsystem/credit_card_processor.go ================================================ package carrentalsystem type CreditCardPaymentProcessor struct{} func NewCreditCardPaymentProcessor() *CreditCardPaymentProcessor { return &CreditCardPaymentProcessor{} } func (p *CreditCardPaymentProcessor) ProcessPayment(amount float64) bool { // Process credit card payment return true } ================================================ FILE: solutions/golang/carrentalsystem/customer.go ================================================ package carrentalsystem type Customer struct { Name string ContactInfo string DriversLicenseNumber string } func NewCustomer(name, contactInfo, driversLicenseNumber string) *Customer { return &Customer{ Name: name, ContactInfo: contactInfo, DriversLicenseNumber: driversLicenseNumber, } } ================================================ FILE: solutions/golang/carrentalsystem/payment_processor.go ================================================ package carrentalsystem type PaymentProcessor interface { ProcessPayment(amount float64) bool } ================================================ FILE: solutions/golang/carrentalsystem/paypal_processor.go ================================================ package carrentalsystem type PayPalPaymentProcessor struct{} func NewPayPalPaymentProcessor() *PayPalPaymentProcessor { return &PayPalPaymentProcessor{} } func (p *PayPalPaymentProcessor) ProcessPayment(amount float64) bool { // Process PayPal payment return true } ================================================ FILE: solutions/golang/carrentalsystem/rental_system.go ================================================ package carrentalsystem import ( "crypto/rand" "encoding/hex" "fmt" "strings" "sync" "time" ) type RentalSystem struct { cars map[string]*Car reservations map[string]*Reservation processor PaymentProcessor mu sync.RWMutex } var ( instance *RentalSystem once sync.Once ) func GetRentalSystem() *RentalSystem { once.Do(func() { instance = &RentalSystem{ cars: make(map[string]*Car), reservations: make(map[string]*Reservation), processor: NewCreditCardPaymentProcessor(), } }) return instance } func (rs *RentalSystem) AddCar(car *Car) { rs.mu.Lock() defer rs.mu.Unlock() rs.cars[car.LicensePlate] = car } func (rs *RentalSystem) RemoveCar(licensePlate string) { rs.mu.Lock() defer rs.mu.Unlock() delete(rs.cars, licensePlate) } func (rs *RentalSystem) SearchCars(make, model string, startDate, endDate time.Time) []*Car { rs.mu.RLock() defer rs.mu.RUnlock() var availableCars []*Car for _, car := range rs.cars { if strings.EqualFold(car.Make, make) && strings.EqualFold(car.Model, model) && car.IsAvailable() && rs.isCarAvailable(car, startDate, endDate) { availableCars = append(availableCars, car) } } return availableCars } func (rs *RentalSystem) isCarAvailable(car *Car, startDate, endDate time.Time) bool { for _, reservation := range rs.reservations { if reservation.Car == car { if !startDate.After(reservation.EndDate) && !endDate.Before(reservation.StartDate) { return false } } } return true } func (rs *RentalSystem) MakeReservation(customer *Customer, car *Car, startDate, endDate time.Time) (*Reservation, error) { rs.mu.Lock() defer rs.mu.Unlock() if !rs.isCarAvailable(car, startDate, endDate) { return nil, fmt.Errorf("car is not available for the selected dates") } reservationID := rs.generateReservationID() reservation := NewReservation(reservationID, customer, car, startDate, endDate) rs.reservations[reservationID] = reservation car.SetAvailable(false) return reservation, nil } func (rs *RentalSystem) CancelReservation(reservationID string) { rs.mu.Lock() defer rs.mu.Unlock() if reservation, exists := rs.reservations[reservationID]; exists { reservation.Car.SetAvailable(true) delete(rs.reservations, reservationID) } } func (rs *RentalSystem) ProcessPayment(reservation *Reservation) bool { return rs.processor.ProcessPayment(reservation.TotalPrice) } func (rs *RentalSystem) generateReservationID() string { bytes := make([]byte, 4) rand.Read(bytes) return fmt.Sprintf("RES%s", hex.EncodeToString(bytes)) } ================================================ FILE: solutions/golang/carrentalsystem/reservation.go ================================================ package carrentalsystem import ( "time" ) type Reservation struct { ReservationID string Customer *Customer Car *Car StartDate time.Time EndDate time.Time TotalPrice float64 } func NewReservation(reservationID string, customer *Customer, car *Car, startDate, endDate time.Time) *Reservation { res := &Reservation{ ReservationID: reservationID, Customer: customer, Car: car, StartDate: startDate, EndDate: endDate, } res.TotalPrice = res.calculateTotalPrice() return res } func (r *Reservation) calculateTotalPrice() float64 { days := r.EndDate.Sub(r.StartDate).Hours() / 24 return r.Car.RentalPricePerDay * days } ================================================ FILE: solutions/golang/chessgame/README.md ================================================ # Designing a Chess Game ## Requirements 1. The chess game should follow the standard rules of chess. 2. The game should support two players, each controlling their own set of pieces. 3. The game board should be represented as an 8x8 grid, with alternating black and white squares. 4. Each player should have 16 pieces: 1 king, 1 queen, 2 rooks, 2 bishops, 2 knights, and 8 pawns. 5. The game should validate legal moves for each piece and prevent illegal moves. 6. The game should detect checkmate and stalemate conditions. 7. The game should handle player turns and allow players to make moves alternately. 8. The game should provide a user interface for players to interact with the game. ## Classes, Interfaces and Enumerations 1. The **Piece** class is an abstract base class representing a chess piece. It contains common attributes such as color, row, and column, and declares an abstract method canMove to be implemented by each specific piece class. 2. The **King**, **Queen**, **Rook**, **Bishop**, **Knight**, and **Pawn** classes extend the Piece class and implement their respective movement logic in the canMove method. 3. The **Board** class represents the chess board and manages the placement of pieces. It provides methods to get and set pieces on the board, check the validity of moves, and determine checkmate and stalemate conditions. 4. The **Player** class represents a player in the game and has a method to make a move on the board. 5. The Move class represents a move made by a player, containing the piece being moved and the destination coordinates. 6. The **Game** class orchestrates the overall game flow. It initializes the board, handles player turns, and determines the game result. 7. The **ChessGame** class is the entry point of the application and starts the game. ================================================ FILE: solutions/golang/chessgame/board.go ================================================ package chessgame type Board struct { pieces [][]Piece } func NewBoard() *Board { board := &Board{ pieces: make([][]Piece, 8), } for i := range board.pieces { board.pieces[i] = make([]Piece, 8) } board.initializeBoard() return board } func (b *Board) initializeBoard() { // Initialize white pieces b.pieces[0][0] = NewRook(White, 0, 0) b.pieces[0][1] = NewKnight(White, 0, 1) b.pieces[0][2] = NewBishop(White, 0, 2) b.pieces[0][3] = NewQueen(White, 0, 3) b.pieces[0][4] = NewKing(White, 0, 4) b.pieces[0][5] = NewBishop(White, 0, 5) b.pieces[0][6] = NewKnight(White, 0, 6) b.pieces[0][7] = NewRook(White, 0, 7) for i := 0; i < 8; i++ { b.pieces[1][i] = NewPawn(White, 1, i) } // Initialize black pieces b.pieces[7][0] = NewRook(Black, 7, 0) b.pieces[7][1] = NewKnight(Black, 7, 1) b.pieces[7][2] = NewBishop(Black, 7, 2) b.pieces[7][3] = NewQueen(Black, 7, 3) b.pieces[7][4] = NewKing(Black, 7, 4) b.pieces[7][5] = NewBishop(Black, 7, 5) b.pieces[7][6] = NewKnight(Black, 7, 6) b.pieces[7][7] = NewRook(Black, 7, 7) for i := 0; i < 8; i++ { b.pieces[6][i] = NewPawn(Black, 6, i) } } func (b *Board) GetPiece(row, col int) Piece { if row < 0 || row > 7 || col < 0 || col > 7 { return nil } return b.pieces[row][col] } func (b *Board) SetPiece(row, col int, piece Piece) { if row >= 0 && row < 8 && col >= 0 && col < 8 { b.pieces[row][col] = piece } } func (b *Board) IsValidMove(piece Piece, destRow, destCol int) bool { if piece == nil || destRow < 0 || destRow > 7 || destCol < 0 || destCol > 7 { return false } destPiece := b.GetPiece(destRow, destCol) return (destPiece == nil || destPiece.GetColor() != piece.GetColor()) && piece.CanMove(b, destRow, destCol) } func (b *Board) IsCheckmate(color Color) bool { // TODO: Implement checkmate logic return false } func (b *Board) IsStalemate(color Color) bool { // TODO: Implement stalemate logic return false } ================================================ FILE: solutions/golang/chessgame/chess_game.go ================================================ package chessgame import ( "bufio" "fmt" "os" "strconv" ) type ChessGame struct { board *Board players []*Player currentPlayer int } func NewChessGame() *ChessGame { return &ChessGame{ board: NewBoard(), players: []*Player{NewPlayer(White), NewPlayer(Black)}, currentPlayer: 0, } } func (g *ChessGame) Start() { reader := bufio.NewReader(os.Stdin) for !g.isGameOver() { player := g.players[g.currentPlayer] fmt.Printf("%s's turn.\n", player.color) move, err := g.getPlayerMove(player, reader) if err != nil { fmt.Printf("Error: %v\nTry again!\n", err) continue } err = player.MakeMove(g.board, move) if err != nil { fmt.Printf("Error: %v\nTry again!\n", err) continue } g.currentPlayer = (g.currentPlayer + 1) % 2 } g.displayResult() } func (g *ChessGame) isGameOver() bool { return g.board.IsCheckmate(White) || g.board.IsCheckmate(Black) || g.board.IsStalemate(White) || g.board.IsStalemate(Black) } func (g *ChessGame) getPlayerMove(player *Player, reader *bufio.Reader) (*Move, error) { fmt.Print("Enter source row: ") sourceRow, _ := strconv.Atoi(readLine(reader)) fmt.Print("Enter source column: ") sourceCol, _ := strconv.Atoi(readLine(reader)) fmt.Print("Enter destination row: ") destRow, _ := strconv.Atoi(readLine(reader)) fmt.Print("Enter destination column: ") destCol, _ := strconv.Atoi(readLine(reader)) piece := g.board.GetPiece(sourceRow, sourceCol) if piece == nil || piece.GetColor() != player.color { return nil, fmt.Errorf("invalid piece selection") } return NewMove(piece, destRow, destCol), nil } func (g *ChessGame) displayResult() { if g.board.IsCheckmate(White) { fmt.Println("Black wins by checkmate!") } else if g.board.IsCheckmate(Black) { fmt.Println("White wins by checkmate!") } else if g.board.IsStalemate(White) || g.board.IsStalemate(Black) { fmt.Println("The game ends in a stalemate!") } } func readLine(reader *bufio.Reader) string { text, _ := reader.ReadString('\n') return text[:len(text)-1] } ================================================ FILE: solutions/golang/chessgame/chess_game_demo.go ================================================ package chessgame func Run() { game := NewChessGame() game.Start() } ================================================ FILE: solutions/golang/chessgame/color.go ================================================ package chessgame type Color int const ( White Color = iota Black ) func (c Color) String() string { if c == White { return "White" } return "Black" } ================================================ FILE: solutions/golang/chessgame/errors.go ================================================ package chessgame type InvalidMoveError struct { message string } func NewInvalidMoveError(message string) *InvalidMoveError { return &InvalidMoveError{message: message} } func (e *InvalidMoveError) Error() string { return e.message } ================================================ FILE: solutions/golang/chessgame/move.go ================================================ package chessgame type Move struct { piece Piece destRow int destCol int } func NewMove(piece Piece, destRow, destCol int) *Move { return &Move{ piece: piece, destRow: destRow, destCol: destCol, } } ================================================ FILE: solutions/golang/chessgame/piece.go ================================================ package chessgame type Piece interface { CanMove(board *Board, destRow, destCol int) bool GetColor() Color GetRow() int GetCol() int SetPosition(row, col int) } type BasePiece struct { color Color row int col int } func (p *BasePiece) GetColor() Color { return p.color } func (p *BasePiece) GetRow() int { return p.row } func (p *BasePiece) GetCol() int { return p.col } func (p *BasePiece) SetPosition(row, col int) { p.row = row p.col = col } ================================================ FILE: solutions/golang/chessgame/pieces.go ================================================ package chessgame import "math" type Pawn struct { BasePiece } func NewPawn(color Color, row, col int) *Pawn { return &Pawn{BasePiece{color, row, col}} } func (p *Pawn) CanMove(board *Board, destRow, destCol int) bool { rowDiff := destRow - p.row colDiff := math.Abs(float64(destCol - p.col)) if p.color == White { return (rowDiff == 1 && colDiff == 0) || (p.row == 1 && rowDiff == 2 && colDiff == 0) || (rowDiff == 1 && colDiff == 1 && board.GetPiece(destRow, destCol) != nil) } return (rowDiff == -1 && colDiff == 0) || (p.row == 6 && rowDiff == -2 && colDiff == 0) || (rowDiff == -1 && colDiff == 1 && board.GetPiece(destRow, destCol) != nil) } type Rook struct { BasePiece } func NewRook(color Color, row, col int) *Rook { return &Rook{BasePiece{color, row, col}} } func (r *Rook) CanMove(board *Board, destRow, destCol int) bool { return r.row == destRow || r.col == destCol } type Knight struct { BasePiece } func NewKnight(color Color, row, col int) *Knight { return &Knight{BasePiece{color, row, col}} } func (k *Knight) CanMove(board *Board, destRow, destCol int) bool { rowDiff := math.Abs(float64(destRow - k.row)) colDiff := math.Abs(float64(destCol - k.col)) return (rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2) } type Bishop struct { BasePiece } func NewBishop(color Color, row, col int) *Bishop { return &Bishop{BasePiece{color, row, col}} } func (b *Bishop) CanMove(board *Board, destRow, destCol int) bool { rowDiff := math.Abs(float64(destRow - b.row)) colDiff := math.Abs(float64(destCol - b.col)) return rowDiff == colDiff } type Queen struct { BasePiece } func NewQueen(color Color, row, col int) *Queen { return &Queen{BasePiece{color, row, col}} } func (q *Queen) CanMove(board *Board, destRow, destCol int) bool { rowDiff := math.Abs(float64(destRow - q.row)) colDiff := math.Abs(float64(destCol - q.col)) return (rowDiff == colDiff) || (q.row == destRow || q.col == destCol) } type King struct { BasePiece } func NewKing(color Color, row, col int) *King { return &King{BasePiece{color, row, col}} } func (k *King) CanMove(board *Board, destRow, destCol int) bool { rowDiff := math.Abs(float64(destRow - k.row)) colDiff := math.Abs(float64(destCol - k.col)) return rowDiff <= 1 && colDiff <= 1 } ================================================ FILE: solutions/golang/chessgame/player.go ================================================ package chessgame type Player struct { color Color } func NewPlayer(color Color) *Player { return &Player{color: color} } func (p *Player) MakeMove(board *Board, move *Move) error { if !board.IsValidMove(move.piece, move.destRow, move.destCol) { return NewInvalidMoveError("Invalid move!") } sourceRow := move.piece.GetRow() sourceCol := move.piece.GetCol() board.SetPiece(sourceRow, sourceCol, nil) board.SetPiece(move.destRow, move.destCol, move.piece) move.piece.SetPosition(move.destRow, move.destCol) return nil } ================================================ FILE: solutions/golang/coffeevendingmachine/README.md ================================================ # Designing a Coffee Vending Machine ## Requirements 1. The coffee vending machine should support different types of coffee, such as espresso, cappuccino, and latte. 2. Each type of coffee should have a specific price and recipe (ingredients and their quantities). 3. The machine should have a menu to display the available coffee options and their prices. 4. Users should be able to select a coffee type and make a payment. 5. The machine should dispense the selected coffee and provide change if necessary. 6. The machine should track the inventory of ingredients and notify when they are running low. 7. The machine should handle multiple user requests concurrently and ensure thread safety. ## Classes, Interfaces and Enumerations 1. The **Coffee** class represents a coffee type with its name, price, and recipe (ingredients and their quantities). 2. The **Ingredient** class represents an ingredient used in making coffee, with its name and quantity. It provides a synchronized method to update the quantity. 3. The **Payment** class represents a payment made by a user, with the amount paid. 4. The **CoffeeMachine** class is the main class that manages the coffee vending machine. It follows the Singleton pattern to ensure a single instance of the machine. 5. The **CoffeeMachine** class initializes the coffee menu and ingredients in its constructor. It provides methods to display the menu, select a coffee, dispense coffee, and update ingredient quantities. 6. The hasEnoughIngredients method checks if there are sufficient ingredients to make a selected coffee, while the updateIngredients method updates the ingredient quantities after dispensing a coffee. 7. The **CoffeeVendingMachine** class is the entry point of the application and demonstrates the usage of the coffee vending machine. It creates an instance of the machine, displays the menu, and simulates concurrent user requests using an ExecutorService. ================================================ FILE: solutions/golang/coffeevendingmachine/coffee.go ================================================ package coffeevendingmachine type Coffee struct { name string price float64 recipe map[*Ingredient]int } func NewCoffee(name string, price float64, recipe map[*Ingredient]int) *Coffee { return &Coffee{ name: name, price: price, recipe: recipe, } } func (c *Coffee) GetName() string { return c.name } func (c *Coffee) GetPrice() float64 { return c.price } func (c *Coffee) GetRecipe() map[*Ingredient]int { return c.recipe } ================================================ FILE: solutions/golang/coffeevendingmachine/coffee_machine.go ================================================ package coffeevendingmachine import ( "fmt" "sync" ) type CoffeeMachine struct { coffeeMenu []*Coffee ingredients map[string]*Ingredient mu sync.Mutex } var ( instance *CoffeeMachine once sync.Once ) func GetCoffeeMachine() *CoffeeMachine { once.Do(func() { instance = &CoffeeMachine{ coffeeMenu: make([]*Coffee, 0), ingredients: make(map[string]*Ingredient), } instance.initializeIngredients() instance.initializeCoffeeMenu() }) return instance } func (cm *CoffeeMachine) initializeIngredients() { cm.ingredients["Coffee"] = NewIngredient("Coffee", 10) cm.ingredients["Water"] = NewIngredient("Water", 10) cm.ingredients["Milk"] = NewIngredient("Milk", 10) } func (cm *CoffeeMachine) initializeCoffeeMenu() { // Espresso Recipe espressoRecipe := make(map[*Ingredient]int) espressoRecipe[cm.ingredients["Coffee"]] = 1 espressoRecipe[cm.ingredients["Water"]] = 1 cm.coffeeMenu = append(cm.coffeeMenu, NewCoffee("Espresso", 2.5, espressoRecipe)) // Cappuccino Recipe cappuccinoRecipe := make(map[*Ingredient]int) cappuccinoRecipe[cm.ingredients["Coffee"]] = 1 cappuccinoRecipe[cm.ingredients["Water"]] = 1 cappuccinoRecipe[cm.ingredients["Milk"]] = 1 cm.coffeeMenu = append(cm.coffeeMenu, NewCoffee("Cappuccino", 3.5, cappuccinoRecipe)) // Latte Recipe latteRecipe := make(map[*Ingredient]int) latteRecipe[cm.ingredients["Coffee"]] = 1 latteRecipe[cm.ingredients["Water"]] = 1 latteRecipe[cm.ingredients["Milk"]] = 2 cm.coffeeMenu = append(cm.coffeeMenu, NewCoffee("Latte", 4.0, latteRecipe)) } func (cm *CoffeeMachine) DisplayMenu() { fmt.Println("Coffee Menu:") for _, coffee := range cm.coffeeMenu { fmt.Printf("%s - $%.2f\n", coffee.GetName(), coffee.GetPrice()) } } func (cm *CoffeeMachine) SelectCoffee(coffeeName string) *Coffee { cm.mu.Lock() defer cm.mu.Unlock() for _, coffee := range cm.coffeeMenu { if coffee.GetName() == coffeeName { return coffee } } return nil } func (cm *CoffeeMachine) DispenseCoffee(coffee *Coffee, payment *Payment) error { cm.mu.Lock() defer cm.mu.Unlock() if coffee == nil { return fmt.Errorf("invalid coffee selection") } if payment.amount < coffee.GetPrice() { return fmt.Errorf("insufficient payment for %s", coffee.GetName()) } if !cm.hasEnoughIngredients(coffee) { return fmt.Errorf("insufficient ingredients to make %s", coffee.GetName()) } cm.updateIngredients(coffee) fmt.Printf("Dispensing %s...\n", coffee.GetName()) change := payment.amount - coffee.GetPrice() if change > 0 { fmt.Printf("Please collect your change: $%.2f\n", change) } return nil } func (cm *CoffeeMachine) hasEnoughIngredients(coffee *Coffee) bool { for ingredient, requiredQuantity := range coffee.GetRecipe() { if ingredient.GetQuantity() < requiredQuantity { return false } } return true } func (cm *CoffeeMachine) updateIngredients(coffee *Coffee) { for ingredient, requiredQuantity := range coffee.GetRecipe() { ingredient.UpdateQuantity(-requiredQuantity) if ingredient.GetQuantity() < 3 { fmt.Printf("Low inventory alert: %s\n", ingredient.GetName()) } } } ================================================ FILE: solutions/golang/coffeevendingmachine/coffee_vending_machine_demo.go ================================================ package coffeevendingmachine import ( "fmt" ) func Run() { coffeeMachine := GetCoffeeMachine() // Display coffee menu coffeeMachine.DisplayMenu() // Simulate user requests coffeeTypes := []string{"Espresso", "Cappuccino", "Latte"} payments := []float64{3.0, 3.5, 4.0} for i, coffeeType := range coffeeTypes { selectedCoffee := coffeeMachine.SelectCoffee(coffeeType) payment := NewPayment(payments[i]) fmt.Printf("\nOrdering %s...\n", coffeeType) if err := coffeeMachine.DispenseCoffee(selectedCoffee, payment); err != nil { fmt.Printf("Error: %v\n", err) } } } ================================================ FILE: solutions/golang/coffeevendingmachine/ingredient.go ================================================ package coffeevendingmachine import "sync" type Ingredient struct { name string quantity int mu sync.Mutex } func NewIngredient(name string, quantity int) *Ingredient { return &Ingredient{ name: name, quantity: quantity, } } func (i *Ingredient) GetName() string { return i.name } func (i *Ingredient) GetQuantity() int { i.mu.Lock() defer i.mu.Unlock() return i.quantity } func (i *Ingredient) UpdateQuantity(amount int) { i.mu.Lock() defer i.mu.Unlock() i.quantity += amount } ================================================ FILE: solutions/golang/coffeevendingmachine/payment.go ================================================ package coffeevendingmachine type Payment struct { amount float64 } func NewPayment(amount float64) *Payment { return &Payment{amount: amount} } ================================================ FILE: solutions/golang/concertticketbookingsystem/README.md ================================================ # Designing a Concert Ticket Booking System ## Requirements 1. The concert ticket booking system should allow users to view available concerts and their seating arrangements. 2. Users should be able to search for concerts based on various criteria such as artist, venue, date, and time. 3. Users should be able to select seats and purchase tickets for a specific concert. 4. The system should handle concurrent booking requests to avoid double-booking of seats. 5. The system should ensure fair booking opportunities for all users. 6. The system should handle payment processing securely. 7. The system should generate booking confirmations and send them to users via email or SMS. 8. The system should provide a waiting list functionality for sold-out concerts. ## Classes, Interfaces and Enumerations 1. The **Concert** class represents a concert event, with properties such as ID, artist, venue, date and time, and a list of seats. 2. The **Seat** class represents a seat in a concert, with properties like ID, seat number, seat type, price, and status. It provides methods to book and release a seat. 3. The **SeatType** enum represents the different types of seats available, such as regular, premium, and VIP. 4. The **SeatStatus** enum represents the status of a seat, which can be available, booked, or reserved. 5. The **Booking** class represents a booking made by a user for a specific concert and seats. It contains properties such as ID, user, concert, seats, total price, and status. It provides methods to confirm and cancel a booking. 6. The **BookingStatus** enum represents the status of a booking, which can be pending, confirmed, or cancelled. 7. The **User** class represents a user of the concert ticket booking system, with properties like ID, name, and email. 8. The **ConcertTicketBookingSystem** class is the central component of the system. It follows the Singleton pattern to ensure a single instance of the system. It manages concerts, bookings, and provides methods to add concerts, search concerts, book tickets, and cancel bookings. 9. The **SeatNotAvailableException** is a custom exception used to handle cases where a seat is not available for booking. ================================================ FILE: solutions/golang/concertticketbookingsystem/booking.go ================================================ package concertbookingsystem type Booking struct { ID string User *User Concert *Concert Seats []*Seat TotalPrice float64 Status BookingStatus } func NewBooking(id string, user *User, concert *Concert, seats []*Seat) *Booking { totalPrice := calculateTotalPrice(seats) return &Booking{ ID: id, User: user, Concert: concert, Seats: seats, TotalPrice: totalPrice, Status: BookingStatusPending, } } func (b *Booking) ConfirmBooking() { if b.Status == BookingStatusPending { b.Status = BookingStatusConfirmed // TODO: Send booking confirmation to user } } func (b *Booking) CancelBooking() { if b.Status == BookingStatusConfirmed { b.Status = BookingStatusCancelled for _, seat := range b.Seats { seat.Release() } // TODO: Send cancellation notification to user } } func calculateTotalPrice(seats []*Seat) float64 { var total float64 for _, seat := range seats { total += seat.Price } return total } ================================================ FILE: solutions/golang/concertticketbookingsystem/concert.go ================================================ package concertbookingsystem import "time" type Concert struct { ID string Artist string Venue string DateTime time.Time Seats []*Seat } func NewConcert(id, artist, venue string, dateTime time.Time, seats []*Seat) *Concert { return &Concert{ ID: id, Artist: artist, Venue: venue, DateTime: dateTime, Seats: seats, } } ================================================ FILE: solutions/golang/concertticketbookingsystem/concert_booking_system.go ================================================ package concertbookingsystem import ( "fmt" "sync" "time" ) type ConcertTicketBookingSystem struct { concerts map[string]*Concert bookings map[string]*Booking mu sync.Mutex } var ( instance *ConcertTicketBookingSystem once sync.Once ) func GetBookingSystem() *ConcertTicketBookingSystem { once.Do(func() { instance = &ConcertTicketBookingSystem{ concerts: make(map[string]*Concert), bookings: make(map[string]*Booking), } }) return instance } func (bs *ConcertTicketBookingSystem) AddConcert(concert *Concert) { bs.mu.Lock() defer bs.mu.Unlock() bs.concerts[concert.ID] = concert } func (bs *ConcertTicketBookingSystem) GetConcert(concertID string) *Concert { bs.mu.Lock() defer bs.mu.Unlock() return bs.concerts[concertID] } func (bs *ConcertTicketBookingSystem) SearchConcerts(artist, venue string, dateTime time.Time) []*Concert { bs.mu.Lock() defer bs.mu.Unlock() var results []*Concert for _, concert := range bs.concerts { if concert.Artist == artist && concert.Venue == venue && concert.DateTime.Equal(dateTime) { results = append(results, concert) } } return results } func (bs *ConcertTicketBookingSystem) BookTickets(user *User, concert *Concert, seats []*Seat) (*Booking, error) { bs.mu.Lock() defer bs.mu.Unlock() // Check seat availability for _, seat := range seats { if seat.GetStatus() != StatusAvailable { return nil, NewSeatNotAvailableError(fmt.Sprintf("Seat %s is not available", seat.SeatNumber)) } } // Book seats for _, seat := range seats { if err := seat.Book(); err != nil { // Rollback previous bookings for _, s := range seats { if s == seat { break } s.Release() } return nil, err } } // Create booking bookingID := fmt.Sprintf("BKG-%d", time.Now().UnixNano()) booking := NewBooking(bookingID, user, concert, seats) // Process payment (mock) bs.processPayment(booking) // Confirm booking booking.ConfirmBooking() bs.bookings[bookingID] = booking fmt.Printf("Booking %s - %d seats booked\n", booking.ID, len(booking.Seats)) return booking, nil } func (bs *ConcertTicketBookingSystem) CancelBooking(bookingID string) { bs.mu.Lock() defer bs.mu.Unlock() if booking, exists := bs.bookings[bookingID]; exists { booking.CancelBooking() delete(bs.bookings, bookingID) fmt.Printf("Booking %s cancelled\n", bookingID) } } func (bs *ConcertTicketBookingSystem) processPayment(booking *Booking) { // Mock payment processing } ================================================ FILE: solutions/golang/concertticketbookingsystem/concert_booking_system_demo.go ================================================ package concertbookingsystem import ( "fmt" "time" ) func Run() { bookingSystem := GetBookingSystem() // Create concerts concert1Seats := GenerateSeats(100) concert1 := NewConcert("C001", "Artist 1", "Venue 1", time.Now().Add(30*24*time.Hour), concert1Seats) bookingSystem.AddConcert(concert1) concert2Seats := GenerateSeats(50) concert2 := NewConcert("C002", "Artist 2", "Venue 2", time.Now().Add(60*24*time.Hour), concert2Seats) bookingSystem.AddConcert(concert2) // Create users user1 := NewUser("U001", "John Doe", "john@example.com") user2 := NewUser("U002", "Jane Smith", "jane@example.com") // Search concerts searchResults := bookingSystem.SearchConcerts("Artist 1", "Venue 1", time.Now().Add(30*24*time.Hour)) fmt.Println("Search Results:") for _, concert := range searchResults { fmt.Printf("Concert: %s at %s\n", concert.Artist, concert.Venue) } // Book tickets selectedSeats1 := concert1.Seats[:3] // Select first 3 seats booking1, err := bookingSystem.BookTickets(user1, concert1, selectedSeats1) if err != nil { fmt.Printf("Booking error: %v\n", err) } selectedSeats2 := concert2.Seats[:2] // Select first 2 seats booking2, err := bookingSystem.BookTickets(user2, concert2, selectedSeats2) if err != nil { fmt.Printf("Booking error: %v\n", err) } if booking2 != nil { fmt.Printf("Booking Successful\n") } // Cancel booking if booking1 != nil { bookingSystem.CancelBooking(booking1.ID) } // Book tickets again selectedSeats3 := concert1.Seats[3:5] // Select next 2 seats booking3, err := bookingSystem.BookTickets(user2, concert1, selectedSeats3) if err != nil { fmt.Printf("Booking error: %v\n", err) } if booking3 != nil { fmt.Printf("Booking Successful\n") } } ================================================ FILE: solutions/golang/concertticketbookingsystem/errors.go ================================================ package concertbookingsystem type SeatNotAvailableError struct { message string } func NewSeatNotAvailableError(message string) *SeatNotAvailableError { return &SeatNotAvailableError{message: message} } func (e *SeatNotAvailableError) Error() string { return e.message } ================================================ FILE: solutions/golang/concertticketbookingsystem/seat.go ================================================ package concertbookingsystem import "sync" type Seat struct { ID string SeatNumber string Type SeatType Price float64 status SeatStatus mu sync.Mutex } func NewSeat(id, seatNumber string, seatType SeatType, price float64) *Seat { return &Seat{ ID: id, SeatNumber: seatNumber, Type: seatType, Price: price, status: StatusAvailable, } } func (s *Seat) Book() error { s.mu.Lock() defer s.mu.Unlock() if s.status != StatusAvailable { return NewSeatNotAvailableError("Seat is already booked or reserved") } s.status = StatusBooked return nil } func (s *Seat) Release() { s.mu.Lock() defer s.mu.Unlock() if s.status == StatusBooked { s.status = StatusAvailable } } func (s *Seat) GetStatus() SeatStatus { s.mu.Lock() defer s.mu.Unlock() return s.status } ================================================ FILE: solutions/golang/concertticketbookingsystem/types.go ================================================ package concertbookingsystem type SeatType int type SeatStatus int type BookingStatus int const ( SeatTypeRegular SeatType = iota SeatTypePremium SeatTypeVIP ) const ( StatusAvailable SeatStatus = iota StatusBooked StatusReserved ) const ( BookingStatusPending BookingStatus = iota BookingStatusConfirmed BookingStatusCancelled ) ================================================ FILE: solutions/golang/concertticketbookingsystem/user.go ================================================ package concertbookingsystem type User struct { ID string Name string Email string } func NewUser(id, name, email string) *User { return &User{ ID: id, Name: name, Email: email, } } ================================================ FILE: solutions/golang/concertticketbookingsystem/utils.go ================================================ package concertbookingsystem import "fmt" func GenerateSeats(numberOfSeats int) []*Seat { seats := make([]*Seat, 0, numberOfSeats) for i := 1; i <= numberOfSeats; i++ { seatNumber := fmt.Sprintf("S%d", i) var seatType SeatType var price float64 switch { case i <= 10: seatType = SeatTypeVIP price = 100.0 case i <= 30: seatType = SeatTypePremium price = 75.0 default: seatType = SeatTypeRegular price = 50.0 } seats = append(seats, NewSeat(seatNumber, seatNumber, seatType, price)) } return seats } ================================================ FILE: solutions/golang/courseregistrationsystem/README.md ================================================ # Designing a University Course Registration System ## Requirements 1. The course registration system should allow students to register for courses and view their registered courses. 2. Each course should have a course code, name, instructor, and maximum enrollment capacity. 3. Students should be able to search for courses based on course code or name. 4. The system should prevent students from registering for courses that have reached their maximum enrollment capacity. 5. The system should handle concurrent registration requests from multiple students. 6. The system should ensure data consistency and prevent race conditions. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Student** class represents a student in the course registration system, with properties such as ID, name, email, and a list of registered courses. 2. The **Course** class represents a course offered in the system, with properties such as code, name, instructor, maximum capacity, and the number of enrolled students. 3. The **Registration** class represents a registration record, associating a student with a course and capturing the registration timestamp. 4. The **CourseRegistrationSystem** class is the main class that manages the course registration system. It follows the Singleton pattern to ensure only one instance of the system exists. 5. The CourseRegistrationSystem class provides methods for adding courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. 6. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as courses and registrations. 7. The registerCourse method is synchronized to ensure thread safety when multiple students are registering for courses simultaneously. 8. The notifyObservers method is a placeholder for notifying observers (e.g., UI components) about updates to course enrollment. 9. The **CourseRegistrationDemo** class demonstrates the usage of the course registration system by creating courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. ================================================ FILE: solutions/golang/courseregistrationsystem/course.go ================================================ package courseregistrationsystem import "sync" type Course struct { Code string Name string Instructor string MaxCapacity int enrolledStudents int mu sync.Mutex } func NewCourse(code, name, instructor string, maxCapacity int) *Course { return &Course{ Code: code, Name: name, Instructor: instructor, MaxCapacity: maxCapacity, } } func (c *Course) GetEnrolledStudents() int { c.mu.Lock() defer c.mu.Unlock() return c.enrolledStudents } func (c *Course) IncrementEnrolled() { c.mu.Lock() defer c.mu.Unlock() c.enrolledStudents++ } ================================================ FILE: solutions/golang/courseregistrationsystem/course_registration_system.go ================================================ package courseregistrationsystem import ( "fmt" "strings" "sync" ) type CourseRegistrationSystem struct { courses map[string]*Course students map[int]*Student registrations []*Registration mu sync.RWMutex } var ( instance *CourseRegistrationSystem once sync.Once ) func GetRegistrationSystem() *CourseRegistrationSystem { once.Do(func() { instance = &CourseRegistrationSystem{ courses: make(map[string]*Course), students: make(map[int]*Student), registrations: make([]*Registration, 0), } }) return instance } func (rs *CourseRegistrationSystem) AddCourse(course *Course) { rs.mu.Lock() defer rs.mu.Unlock() rs.courses[course.Code] = course } func (rs *CourseRegistrationSystem) AddStudent(student *Student) { rs.mu.Lock() defer rs.mu.Unlock() rs.students[student.ID] = student } func (rs *CourseRegistrationSystem) SearchCourses(query string) []*Course { rs.mu.RLock() defer rs.mu.RUnlock() var result []*Course query = strings.ToLower(query) for _, course := range rs.courses { if strings.Contains(strings.ToLower(course.Code), query) || strings.Contains(strings.ToLower(course.Name), query) { result = append(result, course) } } return result } func (rs *CourseRegistrationSystem) RegisterCourse(student *Student, course *Course) error { rs.mu.Lock() defer rs.mu.Unlock() // Check if course exists if _, exists := rs.courses[course.Code]; !exists { return fmt.Errorf("course %s does not exist", course.Code) } // Check if student exists if _, exists := rs.students[student.ID]; !exists { return fmt.Errorf("student with ID %d does not exist", student.ID) } // Check capacity if course.GetEnrolledStudents() >= course.MaxCapacity { return fmt.Errorf("course %s is full", course.Code) } // Check if student is already registered for _, c := range student.RegisteredCourses { if c.Code == course.Code { return fmt.Errorf("student is already registered for course %s", course.Code) } } // Create registration registration := NewRegistration(student, course) rs.registrations = append(rs.registrations, registration) // Update course and student course.IncrementEnrolled() student.AddCourse(course) rs.notifyObservers(course) return nil } func (rs *CourseRegistrationSystem) GetRegisteredCourses(student *Student) []*Course { rs.mu.RLock() defer rs.mu.RUnlock() if _, exists := rs.students[student.ID]; !exists { return nil } return student.RegisteredCourses } func (rs *CourseRegistrationSystem) notifyObservers(course *Course) { // TODO: Implement observer pattern for notifications fmt.Printf("Course %s updated: %d/%d students enrolled\n", course.Code, course.GetEnrolledStudents(), course.MaxCapacity) } ================================================ FILE: solutions/golang/courseregistrationsystem/course_registration_system_demo.go ================================================ package courseregistrationsystem import ( "fmt" ) func Run() { registrationSystem := GetRegistrationSystem() // Create courses course1 := NewCourse("CS101", "Introduction to Programming", "John Doe", 50) course2 := NewCourse("CS201", "Data Structures and Algorithms", "Jane Smith", 30) registrationSystem.AddCourse(course1) registrationSystem.AddCourse(course2) // Create students student1 := NewStudent(1, "Alice", "alice@example.com") student2 := NewStudent(2, "Bob", "bob@example.com") registrationSystem.AddStudent(student1) registrationSystem.AddStudent(student2) // Search for courses searchResults := registrationSystem.SearchCourses("CS") fmt.Println("Search Results:") for _, course := range searchResults { fmt.Printf("%s - %s\n", course.Code, course.Name) } // Register courses for students fmt.Println("\nRegistration Results:") err := registrationSystem.RegisterCourse(student1, course1) fmt.Printf("Student 1 - Course 1: %v\n", err == nil) err = registrationSystem.RegisterCourse(student2, course1) fmt.Printf("Student 2 - Course 1: %v\n", err == nil) err = registrationSystem.RegisterCourse(student1, course2) fmt.Printf("Student 1 - Course 2: %v\n", err == nil) // Get registered courses for a student registeredCourses := registrationSystem.GetRegisteredCourses(student1) fmt.Println("\nRegistered Courses for Student 1:") for _, course := range registeredCourses { fmt.Printf("%s - %s\n", course.Code, course.Name) } } ================================================ FILE: solutions/golang/courseregistrationsystem/registration.go ================================================ package courseregistrationsystem import "time" type Registration struct { Student *Student Course *Course RegistrationTime time.Time } func NewRegistration(student *Student, course *Course) *Registration { return &Registration{ Student: student, Course: course, RegistrationTime: time.Now(), } } ================================================ FILE: solutions/golang/courseregistrationsystem/student.go ================================================ package courseregistrationsystem import "sync" type Student struct { ID int Name string Email string RegisteredCourses []*Course mu sync.Mutex } func NewStudent(id int, name, email string) *Student { return &Student{ ID: id, Name: name, Email: email, RegisteredCourses: make([]*Course, 0), } } func (s *Student) AddCourse(course *Course) { s.mu.Lock() defer s.mu.Unlock() s.RegisteredCourses = append(s.RegisteredCourses, course) } ================================================ FILE: solutions/golang/cricinfo/README.md ================================================ # Designing a Cricket Information System like CricInfo ## Requirements 1. The Cricinfo system should provide information about cricket matches, teams, players, and live scores. 2. Users should be able to view the schedule of upcoming matches and the results of completed matches. 3. The system should allow users to search for specific matches, teams, or players. 4. Users should be able to view detailed information about a particular match, including the scorecard, commentary, and statistics. 5. The system should support real-time updates of live scores and match information. 6. The system should handle concurrent access to match data and ensure data consistency. 7. The system should be scalable and able to handle a large volume of user requests. 8. The system should be extensible to accommodate new features and enhancements in the future. ## Classes, Interfaces and Enumerations 1. The **Match** class represents a cricket match, with properties such as ID, title, venue, start time, teams, status, and scorecard. 2. The **Team** class represents a cricket team, with properties like ID, name, and a list of players. 3. The **Player** class represents a cricket player, with properties such as ID, name, and role. 4. The **Scorecard** class represents the scorecard of a match, containing team scores and a list of innings. 5. The **Innings** class represents an innings in a match, with properties like ID, batting team, bowling team, and a list of overs. 6. The **Over** class represents an over in an innings, containing a list of balls. 7. The **Ball** class represents a ball bowled in an over, with properties such as ball number, bowler, batsman, and result. 8. The **MatchStatus** enum represents the different statuses of a match, such as scheduled, in progress, completed, or abandoned. 9. The **MatchService** class manages the matches in the system, providing methods to add, retrieve, and update match information. It follows the Singleton pattern to ensure a single instance of the service. 10. The **ScorecardService** class manages the scorecards of matches, allowing the creation, retrieval, and update of scorecards and their associated data, such as innings and scores. It also follows the Singleton pattern. 11. The **CricinfoSystem** class serves as the main entry point of the system, integrating the match and scorecard services and providing high-level methods for interacting with the system. ================================================ FILE: solutions/golang/cricinfo/ball.go ================================================ package cricinfo type Ball struct { BallNumber int Bowler string Batsman string Result string } func NewBall(ballNumber int, bowler, batsman, result string) *Ball { return &Ball{ BallNumber: ballNumber, Bowler: bowler, Batsman: batsman, Result: result, } } ================================================ FILE: solutions/golang/cricinfo/cricinfo.go ================================================ package cricinfo import ( "fmt" "time" ) func Run() { // Create teams team1Players := []*Player{ NewPlayer("P101", "Player 1", "Batsman"), NewPlayer("P102", "Player 2", "Bowler"), NewPlayer("P103", "Player 3", "All-rounder"), } team2Players := []*Player{ NewPlayer("P201", "Player 4", "Batsman"), NewPlayer("P202", "Player 5", "Bowler"), NewPlayer("P203", "Player 6", "All-rounder"), } team1 := NewTeam("T1", "Team 1", team1Players) team2 := NewTeam("T2", "Team 2", team2Players) teams := []*Team{team1, team2} // Create match match := NewMatch("M001", "Match 1", "Venue 1", time.Now(), teams) // Create Cricinfo system cricinfoSystem := NewCricinfoSystem() // Add match cricinfoSystem.AddMatch(match) // Create scorecard scorecardID := cricinfoSystem.CreateScorecard(match) // Update scores cricinfoSystem.UpdateScore(scorecardID, "T1", 100) cricinfoSystem.UpdateScore(scorecardID, "T2", 75) // Create innings innings1 := NewInnings("I1", "T1", "T2") innings2 := NewInnings("I2", "T2", "T1") // Add overs over1 := NewOver(1) over1.AddBall(NewBall(1, "P202", "P101", "4")) over1.AddBall(NewBall(2, "P202", "P101", "6")) innings1.AddOver(over1) over2 := NewOver(2) over2.AddBall(NewBall(1, "P102", "P201", "1")) over2.AddBall(NewBall(2, "P102", "P201", "0")) innings1.AddOver(over2) // Add innings cricinfoSystem.AddInnings(scorecardID, innings1) cricinfoSystem.AddInnings(scorecardID, innings2) // Display scorecard scorecard := cricinfoSystem.GetScorecard(scorecardID) displayScorecard(scorecard) } func displayScorecard(scorecard *Scorecard) { fmt.Printf("Scorecard ID: %s\n", scorecard.ID) fmt.Printf("Match: %s\n", scorecard.Match.Title) fmt.Println("Team Scores:") for teamID, score := range scorecard.TeamScores { fmt.Printf("%s: %d\n", teamID, score) } fmt.Println("\nInnings:") for _, innings := range scorecard.Innings { fmt.Printf("Innings ID: %s\n", innings.ID) fmt.Printf("Batting Team: %s\n", innings.BattingTeamID) fmt.Printf("Bowling Team: %s\n", innings.BowlingTeamID) fmt.Println("Overs:") for _, over := range innings.Overs { fmt.Printf("Over %d\n", over.OverNumber) for _, ball := range over.Balls { fmt.Printf("Ball %d: %s to %s - %s\n", ball.BallNumber, ball.Bowler, ball.Batsman, ball.Result) } } fmt.Println() } } ================================================ FILE: solutions/golang/cricinfo/cricinfo_system.go ================================================ package cricinfo type CricinfoSystem struct { matchService *MatchService scorecardService *ScorecardService } func NewCricinfoSystem() *CricinfoSystem { return &CricinfoSystem{ matchService: GetMatchService(), scorecardService: GetScorecardService(), } } func (cs *CricinfoSystem) AddMatch(match *Match) { cs.matchService.AddMatch(match) } func (cs *CricinfoSystem) GetMatch(matchID string) *Match { return cs.matchService.GetMatch(matchID) } func (cs *CricinfoSystem) GetAllMatches() []*Match { return cs.matchService.GetAllMatches() } func (cs *CricinfoSystem) UpdateMatchStatus(matchID string, status MatchStatus) { cs.matchService.UpdateMatchStatus(matchID, status) } func (cs *CricinfoSystem) CreateScorecard(match *Match) string { return cs.scorecardService.CreateScorecard(match) } func (cs *CricinfoSystem) GetScorecard(scorecardID string) *Scorecard { return cs.scorecardService.GetScorecard(scorecardID) } func (cs *CricinfoSystem) UpdateScore(scorecardID string, teamID string, score int) { cs.scorecardService.UpdateScore(scorecardID, teamID, score) } func (cs *CricinfoSystem) AddInnings(scorecardID string, innings *Innings) { cs.scorecardService.AddInnings(scorecardID, innings) } ================================================ FILE: solutions/golang/cricinfo/innings.go ================================================ package cricinfo type Innings struct { ID string BattingTeamID string BowlingTeamID string Overs []*Over } func NewInnings(id, battingTeamID, bowlingTeamID string) *Innings { return &Innings{ ID: id, BattingTeamID: battingTeamID, BowlingTeamID: bowlingTeamID, Overs: make([]*Over, 0), } } func (i *Innings) AddOver(over *Over) { i.Overs = append(i.Overs, over) } ================================================ FILE: solutions/golang/cricinfo/match.go ================================================ package cricinfo import "time" type Match struct { ID string Title string Venue string StartTime time.Time Teams []*Team Status MatchStatus Scorecard *Scorecard } func NewMatch(id, title, venue string, startTime time.Time, teams []*Team) *Match { return &Match{ ID: id, Title: title, Venue: venue, StartTime: startTime, Teams: teams, Status: MatchStatusScheduled, } } ================================================ FILE: solutions/golang/cricinfo/match_service.go ================================================ package cricinfo import ( "sync" ) type MatchService struct { matches map[string]*Match mu sync.RWMutex } var ( matchServiceInstance *MatchService matchServiceOnce sync.Once ) func GetMatchService() *MatchService { matchServiceOnce.Do(func() { matchServiceInstance = &MatchService{ matches: make(map[string]*Match), } }) return matchServiceInstance } func (ms *MatchService) AddMatch(match *Match) { ms.mu.Lock() defer ms.mu.Unlock() ms.matches[match.ID] = match } func (ms *MatchService) GetMatch(matchID string) *Match { ms.mu.RLock() defer ms.mu.RUnlock() return ms.matches[matchID] } func (ms *MatchService) GetAllMatches() []*Match { ms.mu.RLock() defer ms.mu.RUnlock() matches := make([]*Match, 0, len(ms.matches)) for _, match := range ms.matches { matches = append(matches, match) } return matches } func (ms *MatchService) UpdateMatchStatus(matchID string, status MatchStatus) { ms.mu.Lock() defer ms.mu.Unlock() if match, exists := ms.matches[matchID]; exists { match.Status = status } } ================================================ FILE: solutions/golang/cricinfo/over.go ================================================ package cricinfo type Over struct { OverNumber int Balls []*Ball } func NewOver(overNumber int) *Over { return &Over{ OverNumber: overNumber, Balls: make([]*Ball, 0), } } func (o *Over) AddBall(ball *Ball) { o.Balls = append(o.Balls, ball) } ================================================ FILE: solutions/golang/cricinfo/player.go ================================================ package cricinfo type Player struct { ID string Name string Role string } func NewPlayer(id, name, role string) *Player { return &Player{ ID: id, Name: name, Role: role, } } ================================================ FILE: solutions/golang/cricinfo/scorecard.go ================================================ package cricinfo import "sync" type Scorecard struct { ID string Match *Match TeamScores map[string]int Innings []*Innings mu sync.RWMutex } func NewScorecard(id string, match *Match) *Scorecard { return &Scorecard{ ID: id, Match: match, TeamScores: make(map[string]int), Innings: make([]*Innings, 0), } } func (s *Scorecard) UpdateScore(teamID string, score int) { s.mu.Lock() defer s.mu.Unlock() s.TeamScores[teamID] = score } func (s *Scorecard) AddInnings(innings *Innings) { s.mu.Lock() defer s.mu.Unlock() s.Innings = append(s.Innings, innings) } ================================================ FILE: solutions/golang/cricinfo/scorecard_service.go ================================================ package cricinfo import ( "fmt" "sync" "sync/atomic" ) type ScorecardService struct { scorecards map[string]*Scorecard scorecardCounter int64 mu sync.RWMutex } var ( scorecardServiceInstance *ScorecardService scorecardServiceOnce sync.Once ) func GetScorecardService() *ScorecardService { scorecardServiceOnce.Do(func() { scorecardServiceInstance = &ScorecardService{ scorecards: make(map[string]*Scorecard), } }) return scorecardServiceInstance } func (ss *ScorecardService) CreateScorecard(match *Match) string { ss.mu.Lock() defer ss.mu.Unlock() scorecardID := ss.generateScorecardID(match.ID) scorecard := NewScorecard(scorecardID, match) ss.scorecards[scorecardID] = scorecard return scorecardID } func (ss *ScorecardService) GetScorecard(scorecardID string) *Scorecard { ss.mu.RLock() defer ss.mu.RUnlock() return ss.scorecards[scorecardID] } func (ss *ScorecardService) UpdateScore(scorecardID string, teamID string, score int) { ss.mu.RLock() scorecard := ss.scorecards[scorecardID] ss.mu.RUnlock() if scorecard != nil { scorecard.UpdateScore(teamID, score) } } func (ss *ScorecardService) AddInnings(scorecardID string, innings *Innings) { ss.mu.RLock() scorecard := ss.scorecards[scorecardID] ss.mu.RUnlock() if scorecard != nil { scorecard.AddInnings(innings) } } func (ss *ScorecardService) generateScorecardID(matchID string) string { counter := atomic.AddInt64(&ss.scorecardCounter, 1) return fmt.Sprintf("SC-%s-%04d", matchID, counter) } ================================================ FILE: solutions/golang/cricinfo/team.go ================================================ package cricinfo type Team struct { ID string Name string Players []*Player } func NewTeam(id, name string, players []*Player) *Team { return &Team{ ID: id, Name: name, Players: players, } } ================================================ FILE: solutions/golang/cricinfo/types.go ================================================ package cricinfo type MatchStatus int const ( MatchStatusScheduled MatchStatus = iota MatchStatusInProgress MatchStatusCompleted MatchStatusAbandoned ) func (s MatchStatus) String() string { return [...]string{"SCHEDULED", "IN_PROGRESS", "COMPLETED", "ABANDONED"}[s] } ================================================ FILE: solutions/golang/digitalwalletservice/README.md ================================================ # Designing a Digital Wallet System ## Requirements 1. The digital wallet should allow users to create an account and manage their personal information. 2. Users should be able to add and remove payment methods, such as credit cards or bank accounts. 3. The digital wallet should support fund transfers between users and to external accounts. 4. The system should handle transaction history and provide a statement of transactions. 5. The digital wallet should support multiple currencies and perform currency conversions. 6. The system should ensure the security of user information and transactions. 7. The digital wallet should handle concurrent transactions and ensure data consistency. 8. The system should be scalable to handle a large number of users and transactions. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the digital wallet, with properties such as ID, name, email, password, and a list of accounts. 2. The **Account** class represents a user's account within the digital wallet, with properties like ID, user, account number, currency, balance, and a list of transactions. It provides methods to deposit and withdraw funds. 3. The **Transaction** class represents a financial transaction between two accounts, containing properties such as ID, source account, destination account, amount, currency, and timestamp. 4. The **PaymentMethod** class is an abstract base class for different payment methods, such as credit cards and bank accounts. It defines the common properties and methods for processing payments. 5. The **CreditCard** and **BankAccount** classes are concrete implementations of the PaymentMethod class, representing specific payment methods. 6. The **Currency** enum represents different currencies supported by the digital wallet. 7. The **CurrencyConverter** class provides a static method to convert amounts between different currencies based on predefined exchange rates. 8. The **DigitalWallet** class is the central component of the digital wallet system. It follows the Singleton pattern to ensure only one instance of the digital wallet exists. It provides methods to create users, accounts, add payment methods, transfer funds, and retrieve transaction history. It handles concurrent access to shared resources using synchronization. 9. The **DigitalWalletDemo** class demonstrates the usage of the digital wallet system by creating users, accounts, adding payment methods, depositing funds, transferring funds, and retrieving transaction history. ================================================ FILE: solutions/golang/digitalwalletservice/account.go ================================================ package digitalwallet import ( "math/big" "sync" ) type Account struct { ID string User *User AccountNumber string Currency Currency balance *big.Float transactions []*Transaction mu sync.RWMutex } func NewAccount(id string, user *User, accountNumber string, currency Currency) *Account { return &Account{ ID: id, User: user, AccountNumber: accountNumber, Currency: currency, balance: big.NewFloat(0), transactions: make([]*Transaction, 0), } } func (a *Account) Deposit(amount *big.Float) { a.mu.Lock() defer a.mu.Unlock() a.balance.Add(a.balance, amount) } func (a *Account) Withdraw(amount *big.Float) error { a.mu.Lock() defer a.mu.Unlock() if a.balance.Cmp(amount) >= 0 { a.balance.Sub(a.balance, amount) return nil } return NewInsufficientFundsError("Insufficient funds in the account") } func (a *Account) AddTransaction(transaction *Transaction) { a.mu.Lock() defer a.mu.Unlock() a.transactions = append(a.transactions, transaction) } func (a *Account) GetBalance() *big.Float { a.mu.RLock() defer a.mu.RUnlock() return new(big.Float).Copy(a.balance) } func (a *Account) GetTransactions() []*Transaction { a.mu.RLock() defer a.mu.RUnlock() return append([]*Transaction{}, a.transactions...) } ================================================ FILE: solutions/golang/digitalwalletservice/bank_account.go ================================================ package digitalwallet import "math/big" type BankAccount struct { BasePaymentMethod AccountNumber string RoutingNumber string } func NewBankAccount(id string, user *User, accountNumber, routingNumber string) *BankAccount { return &BankAccount{ BasePaymentMethod: BasePaymentMethod{ID: id, User: user}, AccountNumber: accountNumber, RoutingNumber: routingNumber, } } func (b *BankAccount) ProcessPayment(amount *big.Float, currency Currency) bool { // Process bank account payment return true } ================================================ FILE: solutions/golang/digitalwalletservice/credit_card.go ================================================ package digitalwallet import "math/big" type CreditCard struct { BasePaymentMethod CardNumber string ExpirationDate string CVV string } func NewCreditCard(id string, user *User, cardNumber, expirationDate, cvv string) *CreditCard { return &CreditCard{ BasePaymentMethod: BasePaymentMethod{ID: id, User: user}, CardNumber: cardNumber, ExpirationDate: expirationDate, CVV: cvv, } } func (c *CreditCard) ProcessPayment(amount *big.Float, currency Currency) bool { // Process credit card payment return true } ================================================ FILE: solutions/golang/digitalwalletservice/currency_converter.go ================================================ package digitalwallet import ( "math/big" "sync" ) type CurrencyConverter struct { exchangeRates map[Currency]*big.Float mu sync.RWMutex } var ( currencyConverter *CurrencyConverter converterOnce sync.Once ) func GetCurrencyConverter() *CurrencyConverter { converterOnce.Do(func() { currencyConverter = &CurrencyConverter{ exchangeRates: make(map[Currency]*big.Float), } currencyConverter.initializeRates() }) return currencyConverter } func (cc *CurrencyConverter) initializeRates() { cc.mu.Lock() defer cc.mu.Unlock() one := big.NewFloat(1) cc.exchangeRates[USD] = one cc.exchangeRates[EUR] = big.NewFloat(0.85) cc.exchangeRates[GBP] = big.NewFloat(0.72) cc.exchangeRates[JPY] = big.NewFloat(110.00) } func (cc *CurrencyConverter) Convert(amount *big.Float, sourceCurrency, targetCurrency Currency) *big.Float { cc.mu.RLock() defer cc.mu.RUnlock() sourceRate := cc.exchangeRates[sourceCurrency] targetRate := cc.exchangeRates[targetCurrency] result := new(big.Float).Mul(amount, sourceRate) return new(big.Float).Quo(result, targetRate) } ================================================ FILE: solutions/golang/digitalwalletservice/digital_wallet.go ================================================ package digitalwallet import ( "fmt" "math/big" "sync" "time" ) type DigitalWallet struct { users map[string]*User accounts map[string]*Account paymentMethods map[string]PaymentMethod mu sync.RWMutex } var ( instance *DigitalWallet once sync.Once ) func GetDigitalWallet() *DigitalWallet { once.Do(func() { instance = &DigitalWallet{ users: make(map[string]*User), accounts: make(map[string]*Account), paymentMethods: make(map[string]PaymentMethod), } }) return instance } func (dw *DigitalWallet) CreateUser(user *User) { dw.mu.Lock() defer dw.mu.Unlock() dw.users[user.ID] = user } func (dw *DigitalWallet) CreateAccount(account *Account) { dw.mu.Lock() defer dw.mu.Unlock() dw.accounts[account.ID] = account account.User.AddAccount(account) } func (dw *DigitalWallet) AddPaymentMethod(method PaymentMethod) { dw.mu.Lock() defer dw.mu.Unlock() dw.paymentMethods[method.GetID()] = method } func (dw *DigitalWallet) TransferFunds(sourceAccount, destinationAccount *Account, amount *big.Float, currency Currency) error { dw.mu.Lock() defer dw.mu.Unlock() converter := GetCurrencyConverter() // Convert amount to source account currency sourceAmount := amount if sourceAccount.Currency != currency { sourceAmount = converter.Convert(amount, currency, sourceAccount.Currency) } // Withdraw from source account if err := sourceAccount.Withdraw(sourceAmount); err != nil { return err } // Convert amount to destination account currency destAmount := amount if destinationAccount.Currency != currency { destAmount = converter.Convert(amount, currency, destinationAccount.Currency) } // Deposit to destination account destinationAccount.Deposit(destAmount) // Create and record transaction transactionID := fmt.Sprintf("TXN%d", time.Now().UnixNano()) transaction := NewTransaction(transactionID, sourceAccount, destinationAccount, amount, currency) sourceAccount.AddTransaction(transaction) destinationAccount.AddTransaction(transaction) return nil } func (dw *DigitalWallet) GetTransactionHistory(account *Account) []*Transaction { return account.GetTransactions() } ================================================ FILE: solutions/golang/digitalwalletservice/digital_wallet_demo.go ================================================ package digitalwallet import ( "fmt" "math/big" ) func Run() { digitalWallet := GetDigitalWallet() // Create users user1 := NewUser("U001", "John Doe", "john@example.com", "password123") user2 := NewUser("U002", "Jane Smith", "jane@example.com", "password456") digitalWallet.CreateUser(user1) digitalWallet.CreateUser(user2) // Create accounts account1 := NewAccount("A001", user1, "1234567890", USD) account2 := NewAccount("A002", user2, "9876543210", EUR) digitalWallet.CreateAccount(account1) digitalWallet.CreateAccount(account2) // Add payment methods creditCard := NewCreditCard("PM001", user1, "1234567890123456", "12/25", "123") bankAccount := NewBankAccount("PM002", user2, "9876543210", "987654321") digitalWallet.AddPaymentMethod(creditCard) digitalWallet.AddPaymentMethod(bankAccount) // Deposit funds account1.Deposit(big.NewFloat(1000.00)) account2.Deposit(big.NewFloat(500.00)) // Transfer funds amount := big.NewFloat(100.00) if err := digitalWallet.TransferFunds(account1, account2, amount, USD); err != nil { fmt.Printf("Transfer failed: %v\n", err) } // Print transaction history fmt.Println("Transaction History for Account 1:") for _, transaction := range digitalWallet.GetTransactionHistory(account1) { fmt.Printf("Transaction ID: %s\n", transaction.ID) fmt.Printf("Amount: %v %s\n", transaction.Amount, transaction.Currency) fmt.Printf("Timestamp: %v\n\n", transaction.Timestamp) } fmt.Println("Transaction History for Account 2:") for _, transaction := range digitalWallet.GetTransactionHistory(account2) { fmt.Printf("Transaction ID: %s\n", transaction.ID) fmt.Printf("Amount: %v %s\n", transaction.Amount, transaction.Currency) fmt.Printf("Timestamp: %v\n\n", transaction.Timestamp) } } ================================================ FILE: solutions/golang/digitalwalletservice/errors.go ================================================ package digitalwallet type InsufficientFundsError struct { message string } func NewInsufficientFundsError(message string) *InsufficientFundsError { return &InsufficientFundsError{message: message} } func (e *InsufficientFundsError) Error() string { return e.message } ================================================ FILE: solutions/golang/digitalwalletservice/payment_method.go ================================================ package digitalwallet import "math/big" type PaymentMethod interface { ProcessPayment(amount *big.Float, currency Currency) bool GetID() string GetUser() *User } type BasePaymentMethod struct { ID string User *User } func (b *BasePaymentMethod) GetID() string { return b.ID } func (b *BasePaymentMethod) GetUser() *User { return b.User } ================================================ FILE: solutions/golang/digitalwalletservice/transaction.go ================================================ package digitalwallet import ( "math/big" "time" ) type Transaction struct { ID string SourceAccount *Account DestinationAccount *Account Amount *big.Float Currency Currency Timestamp time.Time } func NewTransaction(id string, sourceAccount, destinationAccount *Account, amount *big.Float, currency Currency) *Transaction { return &Transaction{ ID: id, SourceAccount: sourceAccount, DestinationAccount: destinationAccount, Amount: amount, Currency: currency, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/digitalwalletservice/types.go ================================================ package digitalwallet type Currency string const ( USD Currency = "USD" EUR Currency = "EUR" GBP Currency = "GBP" JPY Currency = "JPY" ) ================================================ FILE: solutions/golang/digitalwalletservice/user.go ================================================ package digitalwallet import "sync" type User struct { ID string Name string Email string Password string accounts []*Account mu sync.RWMutex } func NewUser(id, name, email, password string) *User { return &User{ ID: id, Name: name, Email: email, Password: password, accounts: make([]*Account, 0), } } func (u *User) AddAccount(account *Account) { u.mu.Lock() defer u.mu.Unlock() u.accounts = append(u.accounts, account) } func (u *User) RemoveAccount(account *Account) { u.mu.Lock() defer u.mu.Unlock() for i, acc := range u.accounts { if acc == account { u.accounts = append(u.accounts[:i], u.accounts[i+1:]...) break } } } ================================================ FILE: solutions/golang/elevatorsystem/README.md ================================================ # Designing an Elevator System ## Requirements 1. The elevator system should consist of multiple elevators serving multiple floors. 2. Each elevator should have a capacity limit and should not exceed it. 3. Users should be able to request an elevator from any floor and select a destination floor. 4. The elevator system should efficiently handle user requests and optimize the movement of elevators to minimize waiting time. 5. The system should prioritize requests based on the direction of travel and the proximity of the elevators to the requested floor. 6. The elevators should be able to handle multiple requests concurrently and process them in an optimal order. 7. The system should ensure thread safety and prevent race conditions when multiple threads interact with the elevators. ## Classes, Interfaces and Enumerations 1. The **Direction** enum represents the possible directions of elevator movement (UP or DOWN). 2. The **Request** class represents a user request for an elevator, containing the source floor and destination floor. 3. The **Elevator** class represents an individual elevator in the system. It has a capacity limit and maintains a list of 4. requests. The elevator processes requests concurrently and moves between floors based on the requests. 4. The **ElevatorController** class manages multiple elevators and handles user requests. It finds the optimal elevator to serve a request based on the proximity of the elevators to the requested floor. 5. The **ElevatorSystem** class is the entry point of the application and demonstrates the usage of the elevator system. ================================================ FILE: solutions/golang/elevatorsystem/direction.go ================================================ package elevatorsystem type Direction int const ( DirectionUp Direction = iota DirectionDown ) func (d Direction) String() string { return [...]string{"UP", "DOWN"}[d] } ================================================ FILE: solutions/golang/elevatorsystem/elevator.go ================================================ package elevatorsystem import ( "fmt" "sync" "time" ) type Elevator struct { id int capacity int currentFloor int currentDirection Direction requests chan *Request stopChan chan struct{} mu sync.RWMutex } func NewElevator(id, capacity int) *Elevator { return &Elevator{ id: id, capacity: capacity, currentFloor: 1, currentDirection: DirectionUp, requests: make(chan *Request, capacity), stopChan: make(chan struct{}), } } func (e *Elevator) AddRequest(request *Request) bool { select { case e.requests <- request: fmt.Printf("Elevator %d added request: Floor %d to %d\n", e.id, request.SourceFloor, request.DestinationFloor) return true default: return false } } func (e *Elevator) getCurrentFloor() int { e.mu.RLock() defer e.mu.RUnlock() return e.currentFloor } func (e *Elevator) setCurrentFloor(floor int) { e.mu.Lock() defer e.mu.Unlock() e.currentFloor = floor } func (e *Elevator) Run() { go func() { for { select { case request := <-e.requests: e.processRequest(request) case <-e.stopChan: return } } }() } func (e *Elevator) Stop() { close(e.stopChan) } func (e *Elevator) processRequest(request *Request) { startFloor := e.getCurrentFloor() endFloor := request.DestinationFloor if startFloor < endFloor { e.currentDirection = DirectionUp for i := startFloor; i <= endFloor; i++ { e.setCurrentFloor(i) fmt.Printf("Elevator %d reached floor %d\n", e.id, i) time.Sleep(time.Second) // Simulating elevator movement } } else if startFloor > endFloor { e.currentDirection = DirectionDown for i := startFloor; i >= endFloor; i-- { e.setCurrentFloor(i) fmt.Printf("Elevator %d reached floor %d\n", e.id, i) time.Sleep(time.Second) // Simulating elevator movement } } } ================================================ FILE: solutions/golang/elevatorsystem/elevator_controller.go ================================================ package elevatorsystem import ( "math" "sync" ) type ElevatorController struct { elevators []*Elevator mu sync.RWMutex } func NewElevatorController(numElevators, capacity int) *ElevatorController { controller := &ElevatorController{ elevators: make([]*Elevator, numElevators), } for i := 0; i < numElevators; i++ { elevator := NewElevator(i+1, capacity) controller.elevators[i] = elevator elevator.Run() } return controller } func (ec *ElevatorController) RequestElevator(sourceFloor, destinationFloor int) { elevator := ec.findOptimalElevator(sourceFloor, destinationFloor) request := NewRequest(sourceFloor, destinationFloor) elevator.AddRequest(request) } func (ec *ElevatorController) findOptimalElevator(sourceFloor, destinationFloor int) *Elevator { ec.mu.RLock() defer ec.mu.RUnlock() var optimalElevator *Elevator minDistance := math.MaxInt32 for _, elevator := range ec.elevators { distance := int(math.Abs(float64(sourceFloor - elevator.getCurrentFloor()))) if distance < minDistance { minDistance = distance optimalElevator = elevator } } return optimalElevator } func (ec *ElevatorController) Stop() { ec.mu.Lock() defer ec.mu.Unlock() for _, elevator := range ec.elevators { elevator.Stop() } } ================================================ FILE: solutions/golang/elevatorsystem/elevator_controller_demo.go ================================================ package elevatorsystem import ( "time" ) func Run() { controller := NewElevatorController(3, 5) defer controller.Stop() // Simulate elevator requests controller.RequestElevator(5, 10) controller.RequestElevator(3, 7) controller.RequestElevator(8, 2) controller.RequestElevator(1, 9) // Wait for elevators to process requests time.Sleep(30 * time.Second) } ================================================ FILE: solutions/golang/elevatorsystem/request.go ================================================ package elevatorsystem type Request struct { SourceFloor int DestinationFloor int } func NewRequest(sourceFloor, destinationFloor int) *Request { return &Request{ SourceFloor: sourceFloor, DestinationFloor: destinationFloor, } } ================================================ FILE: solutions/golang/fooddeliveryservice/README.md ================================================ # Designing an Online Food Delivery Service Like Swiggy ## Requirements 1. The food delivery service should allow customers to browse restaurants, view menus, and place orders. 2. Restaurants should be able to manage their menus, prices, and availability. 3. Delivery agents should be able to accept and fulfill orders. 4. The system should handle order tracking and status updates. 5. The system should support multiple payment methods. 6. The system should handle concurrent orders and ensure data consistency. 7. The system should be scalable and handle a high volume of orders. 8. The system should provide real-time notifications to customers, restaurants, and delivery agents. ## Classes, Interfaces and Enumerations 1. The **Customer** class represents a customer who can place orders. It contains customer details such as ID, name, email, and phone number. 2. The **Restaurant** class represents a restaurant that offers menu items. It contains restaurant details such as ID, name, address, and a list of menu items. It provides methods to add and remove menu items. 3. The **MenuItem** class represents an item on a restaurant's menu. It contains details such as ID, name, description, price, and availability status. 4. The **Order** class represents an order placed by a customer. It contains order details such as ID, customer, restaurant, list of order items, status, and assigned delivery agent. It provides methods to add and remove order items, update order status, and assign a delivery agent. 5. The **OrderItem** class represents an item within an order. It contains the selected menu item and the quantity ordered. 6. The **OrderStatus** enum represents the different statuses an order can have, such as PENDING, CONFIRMED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, and CANCELLED. 7. The **DeliveryAgent** class represents a delivery agent who fulfills orders. It contains details such as ID, name, phone number, and availability status. 8. The **FoodDeliveryService** class is the main class that manages the food delivery service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register customers, restaurants, and delivery agents, retrieve available restaurants and menus, place orders, update order status, cancel orders, and assign delivery agents to orders. It also handles notifications to customers, restaurants, and delivery agents. ================================================ FILE: solutions/golang/fooddeliveryservice/customer.go ================================================ package fooddeliveryservice type Customer struct { ID string Name string Email string Phone string } func NewCustomer(id, name, email, phone string) *Customer { return &Customer{ ID: id, Name: name, Email: email, Phone: phone, } } ================================================ FILE: solutions/golang/fooddeliveryservice/delivery_agent.go ================================================ package fooddeliveryservice import "sync" type DeliveryAgent struct { ID string Name string Phone string available bool mu sync.RWMutex } func NewDeliveryAgent(id, name, phone string) *DeliveryAgent { return &DeliveryAgent{ ID: id, Name: name, Phone: phone, available: true, } } func (d *DeliveryAgent) SetAvailable(available bool) { d.mu.Lock() defer d.mu.Unlock() d.available = available } func (d *DeliveryAgent) IsAvailable() bool { d.mu.RLock() defer d.mu.RUnlock() return d.available } ================================================ FILE: solutions/golang/fooddeliveryservice/food_delivery_service.go ================================================ package fooddeliveryservice import ( "fmt" "sync" "time" ) type FoodDeliveryService struct { customers map[string]*Customer restaurants map[string]*Restaurant orders map[string]*Order deliveryAgents map[string]*DeliveryAgent mu sync.RWMutex } var ( instance *FoodDeliveryService once sync.Once ) func GetFoodDeliveryService() *FoodDeliveryService { once.Do(func() { instance = &FoodDeliveryService{ customers: make(map[string]*Customer), restaurants: make(map[string]*Restaurant), orders: make(map[string]*Order), deliveryAgents: make(map[string]*DeliveryAgent), } }) return instance } func (s *FoodDeliveryService) RegisterCustomer(customer *Customer) { s.mu.Lock() defer s.mu.Unlock() s.customers[customer.ID] = customer } func (s *FoodDeliveryService) RegisterRestaurant(restaurant *Restaurant) { s.mu.Lock() defer s.mu.Unlock() s.restaurants[restaurant.ID] = restaurant } func (s *FoodDeliveryService) RegisterDeliveryAgent(agent *DeliveryAgent) { s.mu.Lock() defer s.mu.Unlock() s.deliveryAgents[agent.ID] = agent } func (s *FoodDeliveryService) GetAvailableRestaurants() []*Restaurant { s.mu.RLock() defer s.mu.RUnlock() restaurants := make([]*Restaurant, 0, len(s.restaurants)) for _, restaurant := range s.restaurants { restaurants = append(restaurants, restaurant) } return restaurants } func (s *FoodDeliveryService) GetRestaurantMenu(restaurantID string) []*MenuItem { s.mu.RLock() restaurant := s.restaurants[restaurantID] s.mu.RUnlock() if restaurant != nil { return restaurant.GetMenu() } return nil } func (s *FoodDeliveryService) PlaceOrder(customerID, restaurantID string, items []*OrderItem) (*Order, error) { s.mu.Lock() defer s.mu.Unlock() customer := s.customers[customerID] restaurant := s.restaurants[restaurantID] if customer == nil { return nil, fmt.Errorf("customer not found") } if restaurant == nil { return nil, fmt.Errorf("restaurant not found") } orderID := fmt.Sprintf("ORD%d", time.Now().UnixNano()) order := NewOrder(orderID, customer, restaurant) for _, item := range items { order.AddItem(item) } s.orders[order.ID] = order s.notifyRestaurant(order) fmt.Printf("Order placed: %s\n", order.ID) return order, nil } func (s *FoodDeliveryService) UpdateOrderStatus(orderID string, status OrderStatus) error { s.mu.Lock() defer s.mu.Unlock() order := s.orders[orderID] if order == nil { return fmt.Errorf("order not found") } order.SetStatus(status) s.notifyCustomer(order) if status == OrderStatusConfirmed { s.assignDeliveryAgent(order) } return nil } func (s *FoodDeliveryService) CancelOrder(orderID string) error { s.mu.Lock() defer s.mu.Unlock() order := s.orders[orderID] if order == nil { return fmt.Errorf("order not found") } if order.GetStatus() != OrderStatusPending { return fmt.Errorf("cannot cancel order in current status") } order.SetStatus(OrderStatusCancelled) s.notifyCustomer(order) s.notifyRestaurant(order) fmt.Printf("Order cancelled: %s\n", order.ID) return nil } func (s *FoodDeliveryService) notifyCustomer(order *Order) { // TODO: Implement customer notification fmt.Printf("Notifying customer about order %s status: %s\n", order.ID, order.GetStatus()) } func (s *FoodDeliveryService) notifyRestaurant(order *Order) { // TODO: Implement restaurant notification fmt.Printf("Notifying restaurant about order %s\n", order.ID) } func (s *FoodDeliveryService) notifyDeliveryAgent(order *Order) { // TODO: Implement delivery agent notification fmt.Printf("Notifying delivery agent about order %s\n", order.ID) } func (s *FoodDeliveryService) assignDeliveryAgent(order *Order) { for _, agent := range s.deliveryAgents { if agent.IsAvailable() { agent.SetAvailable(false) order.AssignDeliveryAgent(agent) s.notifyDeliveryAgent(order) break } } } ================================================ FILE: solutions/golang/fooddeliveryservice/food_delivery_service_demo.go ================================================ package fooddeliveryservice import ( "fmt" ) func Run() { service := GetFoodDeliveryService() // Register customers customer1 := NewCustomer("C001", "John Doe", "john@example.com", "1234567890") customer2 := NewCustomer("C002", "Jane Smith", "jane@example.com", "9876543210") service.RegisterCustomer(customer1) service.RegisterCustomer(customer2) // Create restaurant menus restaurant1Menu := []*MenuItem{ NewMenuItem("M001", "Burger", "Delicious burger", 9.99), NewMenuItem("M002", "Pizza", "Cheesy pizza", 12.99), } restaurant2Menu := []*MenuItem{ NewMenuItem("M003", "Sushi", "Fresh sushi", 15.99), NewMenuItem("M004", "Ramen", "Delicious ramen", 10.99), } // Register restaurants restaurant1 := NewRestaurant("R001", "Restaurant 1", "Address 1", restaurant1Menu) restaurant2 := NewRestaurant("R002", "Restaurant 2", "Address 2", restaurant2Menu) service.RegisterRestaurant(restaurant1) service.RegisterRestaurant(restaurant2) // Register delivery agents agent1 := NewDeliveryAgent("D001", "Agent 1", "9999999999") agent2 := NewDeliveryAgent("D002", "Agent 2", "8888888888") service.RegisterDeliveryAgent(agent1) service.RegisterDeliveryAgent(agent2) // Place orders orderItems := []*OrderItem{ NewOrderItem(restaurant1Menu[0], 2), NewOrderItem(restaurant1Menu[1], 1), } order1, err := service.PlaceOrder(customer1.ID, restaurant1.ID, orderItems) if err != nil { fmt.Printf("Error placing order: %v\n", err) return } // Update order status err = service.UpdateOrderStatus(order1.ID, OrderStatusConfirmed) if err != nil { fmt.Printf("Error updating order status: %v\n", err) return } fmt.Printf("Order status updated: %s\n", order1.GetStatus()) // Place and cancel another order order2Items := []*OrderItem{ NewOrderItem(restaurant2Menu[0], 1), } order2, err := service.PlaceOrder(customer2.ID, restaurant2.ID, order2Items) if err != nil { fmt.Printf("Error placing order: %v\n", err) return } err = service.CancelOrder(order2.ID) if err != nil { fmt.Printf("Error cancelling order: %v\n", err) } } ================================================ FILE: solutions/golang/fooddeliveryservice/menu_item.go ================================================ package fooddeliveryservice import "sync" type MenuItem struct { ID string Name string Description string Price float64 available bool mu sync.RWMutex } func NewMenuItem(id, name, description string, price float64) *MenuItem { return &MenuItem{ ID: id, Name: name, Description: description, Price: price, available: true, } } func (m *MenuItem) SetAvailable(available bool) { m.mu.Lock() defer m.mu.Unlock() m.available = available } func (m *MenuItem) IsAvailable() bool { m.mu.RLock() defer m.mu.RUnlock() return m.available } ================================================ FILE: solutions/golang/fooddeliveryservice/order.go ================================================ package fooddeliveryservice import "sync" type OrderItem struct { MenuItem *MenuItem Quantity int } func NewOrderItem(menuItem *MenuItem, quantity int) *OrderItem { return &OrderItem{ MenuItem: menuItem, Quantity: quantity, } } type Order struct { ID string Customer *Customer Restaurant *Restaurant Items []*OrderItem Status OrderStatus DeliveryAgent *DeliveryAgent mu sync.RWMutex } func NewOrder(id string, customer *Customer, restaurant *Restaurant) *Order { return &Order{ ID: id, Customer: customer, Restaurant: restaurant, Items: make([]*OrderItem, 0), Status: OrderStatusPending, } } func (o *Order) AddItem(item *OrderItem) { o.mu.Lock() defer o.mu.Unlock() o.Items = append(o.Items, item) } func (o *Order) RemoveItem(item *OrderItem) { o.mu.Lock() defer o.mu.Unlock() for i, orderItem := range o.Items { if orderItem == item { o.Items = append(o.Items[:i], o.Items[i+1:]...) break } } } func (o *Order) SetStatus(status OrderStatus) { o.mu.Lock() defer o.mu.Unlock() o.Status = status } func (o *Order) GetStatus() OrderStatus { o.mu.RLock() defer o.mu.RUnlock() return o.Status } func (o *Order) AssignDeliveryAgent(agent *DeliveryAgent) { o.mu.Lock() defer o.mu.Unlock() o.DeliveryAgent = agent } ================================================ FILE: solutions/golang/fooddeliveryservice/restaurant.go ================================================ package fooddeliveryservice import "sync" type Restaurant struct { ID string Name string Address string Menu []*MenuItem mu sync.RWMutex } func NewRestaurant(id, name, address string, menu []*MenuItem) *Restaurant { return &Restaurant{ ID: id, Name: name, Address: address, Menu: menu, } } func (r *Restaurant) AddMenuItem(item *MenuItem) { r.mu.Lock() defer r.mu.Unlock() r.Menu = append(r.Menu, item) } func (r *Restaurant) RemoveMenuItem(item *MenuItem) { r.mu.Lock() defer r.mu.Unlock() for i, menuItem := range r.Menu { if menuItem == item { r.Menu = append(r.Menu[:i], r.Menu[i+1:]...) break } } } func (r *Restaurant) GetMenu() []*MenuItem { r.mu.RLock() defer r.mu.RUnlock() menuCopy := make([]*MenuItem, len(r.Menu)) copy(menuCopy, r.Menu) return menuCopy } ================================================ FILE: solutions/golang/fooddeliveryservice/types.go ================================================ package fooddeliveryservice type OrderStatus int const ( OrderStatusPending OrderStatus = iota OrderStatusConfirmed OrderStatusPreparing OrderStatusOutForDelivery OrderStatusDelivered OrderStatusCancelled ) func (s OrderStatus) String() string { return [...]string{ "PENDING", "CONFIRMED", "PREPARING", "OUT_FOR_DELIVERY", "DELIVERED", "CANCELLED", }[s] } ================================================ FILE: solutions/golang/go.mod ================================================ module github.com/ashishps1/awesome-low-level-design/solutions/golang go 1.23.2 ================================================ FILE: solutions/golang/hotelmanagementsystem/README.md ================================================ # Designing a Hotel Management System ## Requirements 1. The hotel management system should allow guests to book rooms, check-in, and check-out. 2. The system should manage different types of rooms, such as single, double, deluxe, and suite. 3. The system should handle room availability and reservation status. 4. The system should allow the hotel staff to manage guest information, room assignments, and billing. 5. The system should support multiple payment methods, such as cash, credit card, and online payment. 6. The system should handle concurrent bookings and ensure data consistency. 7. The system should provide reporting and analytics features for hotel management. 8. The system should be scalable and handle a large number of rooms and guests. ## Classes, Interfaces and Enumerations 1. The **Guest** class represents a guest of the hotel, with properties such as ID, name, email, and phone number. 2. The **Room** class represents a room in the hotel, with properties like ID, room type, price, and status. It provides methods to book, check-in, and check-out a room. 3. The **RoomType** enum represents the different types of rooms available in the hotel. 4. The **RoomStatus** enum represents the status of a room, which can be available, booked, or occupied. 5. The **Reservation** class represents a reservation made by a guest for a specific room and date range. It contains properties such as ID, guest, room, check-in date, check-out date, and status. It provides a method to cancel a reservation. 6. The **ReservationStatus** enum represents the status of a reservation, which can be confirmed or cancelled. 7. The **Payment** interface defines the contract for processing payments. It is implemented by concrete payment classes like CashPayment and CreditCardPayment. 8. The **HotelManagementSystem** class is the central component of the hotel management system. It follows the Singleton pattern to ensure only one instance of the system exists. It provides methods to add guests and rooms, book rooms, cancel reservations, check-in, check-out, and process payments. It also handles concurrent access to shared resources using synchronization. 9. The **HotelManagementSystemDemo** class demonstrates the usage of the hotel management system by creating guests, rooms, booking a room, checking in, checking out, and cancelling a reservation. ================================================ FILE: solutions/golang/hotelmanagementsystem/guest.go ================================================ package hotelmanagement type Guest struct { ID string Name string Email string PhoneNumber string } func NewGuest(id, name, email, phoneNumber string) *Guest { return &Guest{ ID: id, Name: name, Email: email, PhoneNumber: phoneNumber, } } ================================================ FILE: solutions/golang/hotelmanagementsystem/hotel_management.go ================================================ package hotelmanagement import ( "fmt" "sync" "time" ) type HotelManagementSystem struct { guests map[string]*Guest rooms map[string]*Room reservations map[string]*Reservation mu sync.RWMutex } var ( instance *HotelManagementSystem once sync.Once ) func GetHotelManagementSystem() *HotelManagementSystem { once.Do(func() { instance = &HotelManagementSystem{ guests: make(map[string]*Guest), rooms: make(map[string]*Room), reservations: make(map[string]*Reservation), } }) return instance } func (h *HotelManagementSystem) AddGuest(guest *Guest) { h.mu.Lock() defer h.mu.Unlock() h.guests[guest.ID] = guest } func (h *HotelManagementSystem) GetGuest(guestID string) *Guest { h.mu.RLock() defer h.mu.RUnlock() return h.guests[guestID] } func (h *HotelManagementSystem) AddRoom(room *Room) { h.mu.Lock() defer h.mu.Unlock() h.rooms[room.ID] = room } func (h *HotelManagementSystem) GetRoom(roomID string) *Room { h.mu.RLock() defer h.mu.RUnlock() return h.rooms[roomID] } func (h *HotelManagementSystem) BookRoom(guest *Guest, room *Room, checkInDate, checkOutDate time.Time) (*Reservation, error) { h.mu.Lock() defer h.mu.Unlock() if room.GetStatus() != RoomStatusAvailable { return nil, fmt.Errorf("room is not available") } if err := room.Book(); err != nil { return nil, err } reservationID := fmt.Sprintf("RES%d", time.Now().UnixNano()) reservation := NewReservation(reservationID, guest, room, checkInDate, checkOutDate) h.reservations[reservationID] = reservation return reservation, nil } func (h *HotelManagementSystem) CancelReservation(reservationID string) error { h.mu.Lock() defer h.mu.Unlock() reservation, exists := h.reservations[reservationID] if !exists { return fmt.Errorf("reservation not found") } if err := reservation.Cancel(); err != nil { return err } delete(h.reservations, reservationID) return nil } func (h *HotelManagementSystem) CheckIn(reservationID string) error { h.mu.Lock() defer h.mu.Unlock() reservation, exists := h.reservations[reservationID] if !exists { return fmt.Errorf("reservation not found") } if reservation.Status != ReservationStatusConfirmed { return fmt.Errorf("invalid reservation status") } return reservation.Room.CheckIn() } func (h *HotelManagementSystem) CheckOut(reservationID string, payment Payment) error { h.mu.Lock() defer h.mu.Unlock() reservation, exists := h.reservations[reservationID] if !exists { return fmt.Errorf("reservation not found") } if reservation.Status != ReservationStatusConfirmed { return fmt.Errorf("invalid reservation status") } days := reservation.CheckOutDate.Sub(reservation.CheckInDate).Hours() / 24 amount := reservation.Room.Price * days if !payment.ProcessPayment(amount) { return fmt.Errorf("payment failed") } if err := reservation.Room.CheckOut(); err != nil { return err } delete(h.reservations, reservationID) return nil } ================================================ FILE: solutions/golang/hotelmanagementsystem/hotel_management_demo.go ================================================ package hotelmanagement import ( "fmt" "time" ) func Run() { hotelSystem := GetHotelManagementSystem() // Create guests guest1 := NewGuest("G001", "John Doe", "john@example.com", "1234567890") guest2 := NewGuest("G002", "Jane Smith", "jane@example.com", "9876543210") hotelSystem.AddGuest(guest1) hotelSystem.AddGuest(guest2) // Create rooms room1 := NewRoom("R001", RoomTypeSingle, 100.0) room2 := NewRoom("R002", RoomTypeDouble, 200.0) hotelSystem.AddRoom(room1) hotelSystem.AddRoom(room2) // Book a room checkInDate := time.Now() checkOutDate := checkInDate.AddDate(0, 0, 3) reservation1, err := hotelSystem.BookRoom(guest1, room1, checkInDate, checkOutDate) if err != nil { fmt.Printf("Failed to book room: %v\n", err) return } fmt.Printf("Reservation created: %s\n", reservation1.ID) // Check-in if err := hotelSystem.CheckIn(reservation1.ID); err != nil { fmt.Printf("Failed to check in: %v\n", err) return } fmt.Printf("Checked in: %s\n", reservation1.ID) // Check-out and process payment payment := NewCreditCardPayment() if err := hotelSystem.CheckOut(reservation1.ID, payment); err != nil { fmt.Printf("Failed to check out: %v\n", err) return } fmt.Printf("Checked out: %s\n", reservation1.ID) // Cancel a reservation if err := hotelSystem.CancelReservation(reservation1.ID); err != nil { fmt.Printf("Failed to cancel reservation: %v\n", err) return } fmt.Printf("Reservation cancelled: %s\n", reservation1.ID) } ================================================ FILE: solutions/golang/hotelmanagementsystem/payment.go ================================================ package hotelmanagement type Payment interface { ProcessPayment(amount float64) bool } type CreditCardPayment struct{} func NewCreditCardPayment() *CreditCardPayment { return &CreditCardPayment{} } func (p *CreditCardPayment) ProcessPayment(amount float64) bool { // Process credit card payment return true } type CashPayment struct{} func NewCashPayment() *CashPayment { return &CashPayment{} } func (p *CashPayment) ProcessPayment(amount float64) bool { // Process cash payment return true } ================================================ FILE: solutions/golang/hotelmanagementsystem/reservation.go ================================================ package hotelmanagement import ( "fmt" "sync" "time" ) type Reservation struct { ID string Guest *Guest Room *Room CheckInDate time.Time CheckOutDate time.Time Status ReservationStatus mu sync.RWMutex } func NewReservation(id string, guest *Guest, room *Room, checkInDate, checkOutDate time.Time) *Reservation { return &Reservation{ ID: id, Guest: guest, Room: room, CheckInDate: checkInDate, CheckOutDate: checkOutDate, Status: ReservationStatusConfirmed, } } func (r *Reservation) Cancel() error { r.mu.Lock() defer r.mu.Unlock() if r.Status != ReservationStatusConfirmed { return fmt.Errorf("reservation is not confirmed") } r.Status = ReservationStatusCancelled return r.Room.CheckOut() } ================================================ FILE: solutions/golang/hotelmanagementsystem/room.go ================================================ package hotelmanagement import ( "fmt" "sync" ) type Room struct { ID string Type RoomType Price float64 status RoomStatus mu sync.RWMutex } func NewRoom(id string, roomType RoomType, price float64) *Room { return &Room{ ID: id, Type: roomType, Price: price, status: RoomStatusAvailable, } } func (r *Room) Book() error { r.mu.Lock() defer r.mu.Unlock() if r.status != RoomStatusAvailable { return fmt.Errorf("room is not available for booking") } r.status = RoomStatusBooked return nil } func (r *Room) CheckIn() error { r.mu.Lock() defer r.mu.Unlock() if r.status != RoomStatusBooked { return fmt.Errorf("room is not booked") } r.status = RoomStatusOccupied return nil } func (r *Room) CheckOut() error { r.mu.Lock() defer r.mu.Unlock() if r.status != RoomStatusOccupied { return fmt.Errorf("room is not occupied") } r.status = RoomStatusAvailable return nil } func (r *Room) GetStatus() RoomStatus { r.mu.RLock() defer r.mu.RUnlock() return r.status } ================================================ FILE: solutions/golang/hotelmanagementsystem/types.go ================================================ package hotelmanagement type RoomType int type RoomStatus int type ReservationStatus int const ( RoomTypeSingle RoomType = iota RoomTypeDouble RoomTypeDeluxe RoomTypeSuite ) const ( RoomStatusAvailable RoomStatus = iota RoomStatusBooked RoomStatusOccupied ) const ( ReservationStatusConfirmed ReservationStatus = iota ReservationStatusCancelled ) ================================================ FILE: solutions/golang/librarymanagementsystem/README.md ================================================ # Designing a Library Management System ## Requirements 1. The library management system should allow librarians to manage books, members, and borrowing activities. 2. The system should support adding, updating, and removing books from the library catalog. 3. Each book should have details such as title, author, ISBN, publication year, and availability status. 4. The system should allow members to borrow and return books. 5. Each member should have details such as name, member ID, contact information, and borrowing history. 6. The system should enforce borrowing rules, such as a maximum number of books that can be borrowed at a time and loan duration. 7. The system should handle concurrent access to the library catalog and member records. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Book** class represents a book in the library catalog, with properties such as ISBN, title, author, publication year, and availability status. 2. The **Member** class represents a library member, with properties like member ID, name, contact information, and a list of borrowed books. 3. The **LibraryManager** class is the core of the library management system and follows the Singleton pattern to ensure a single instance of the library manager. 4. The LibraryManager class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to the library catalog and member records. 5. The LibraryManager class provides methods for adding and removing books, registering and unregistering members, borrowing and returning books, and searching for books based on keywords. 6. The **LibraryManagementSystemDemo** class serves as the entry point of the application and demonstrates the usage of the library management system. ================================================ FILE: solutions/golang/librarymanagementsystem/book.go ================================================ package librarymanagementsystem import "sync" type Book struct { ISBN string Title string Author string PublicationYear int available bool mu sync.RWMutex } func NewBook(isbn, title, author string, publicationYear int) *Book { return &Book{ ISBN: isbn, Title: title, Author: author, PublicationYear: publicationYear, available: true, } } func (b *Book) IsAvailable() bool { b.mu.RLock() defer b.mu.RUnlock() return b.available } func (b *Book) SetAvailable(available bool) { b.mu.Lock() defer b.mu.Unlock() b.available = available } ================================================ FILE: solutions/golang/librarymanagementsystem/library_management_system_demo.go ================================================ package librarymanagementsystem import ( "fmt" ) func Run() { libraryManager := GetLibraryManager() // Add books to the catalog book1 := NewBook("ISBN1", "Book 1", "Author 1", 2020) book2 := NewBook("ISBN2", "Book 2", "Author 2", 2019) book3 := NewBook("ISBN3", "Book 3", "Author 3", 2021) libraryManager.AddBook(book1) libraryManager.AddBook(book2) libraryManager.AddBook(book3) // Register members member1 := NewMember("M1", "John Doe", "john@example.com") member2 := NewMember("M2", "Jane Smith", "jane@example.com") libraryManager.RegisterMember(member1) libraryManager.RegisterMember(member2) // Borrow books if err := libraryManager.BorrowBook("M1", "ISBN1"); err != nil { fmt.Printf("Error borrowing book: %v\n", err) } if err := libraryManager.BorrowBook("M2", "ISBN2"); err != nil { fmt.Printf("Error borrowing book: %v\n", err) } // Return books if err := libraryManager.ReturnBook("M1", "ISBN1"); err != nil { fmt.Printf("Error returning book: %v\n", err) } // Search books searchResults := libraryManager.SearchBooks("Book") fmt.Println("\nSearch Results:") for _, book := range searchResults { fmt.Printf("%s by %s\n", book.Title, book.Author) } } ================================================ FILE: solutions/golang/librarymanagementsystem/library_manager.go ================================================ package librarymanagementsystem import ( "fmt" "strings" "sync" ) const ( maxBooksPerMember = 5 loanDurationDays = 14 ) type LibraryManager struct { catalog map[string]*Book members map[string]*Member mu sync.RWMutex } var ( instance *LibraryManager once sync.Once ) func GetLibraryManager() *LibraryManager { once.Do(func() { instance = &LibraryManager{ catalog: make(map[string]*Book), members: make(map[string]*Member), } }) return instance } func (lm *LibraryManager) AddBook(book *Book) { lm.mu.Lock() defer lm.mu.Unlock() lm.catalog[book.ISBN] = book } func (lm *LibraryManager) RemoveBook(isbn string) { lm.mu.Lock() defer lm.mu.Unlock() delete(lm.catalog, isbn) } func (lm *LibraryManager) GetBook(isbn string) *Book { lm.mu.RLock() defer lm.mu.RUnlock() return lm.catalog[isbn] } func (lm *LibraryManager) RegisterMember(member *Member) { lm.mu.Lock() defer lm.mu.Unlock() lm.members[member.MemberID] = member } func (lm *LibraryManager) UnregisterMember(memberID string) { lm.mu.Lock() defer lm.mu.Unlock() delete(lm.members, memberID) } func (lm *LibraryManager) GetMember(memberID string) *Member { lm.mu.RLock() defer lm.mu.RUnlock() return lm.members[memberID] } func (lm *LibraryManager) BorrowBook(memberID, isbn string) error { lm.mu.Lock() defer lm.mu.Unlock() member := lm.members[memberID] book := lm.catalog[isbn] if member == nil || book == nil { return fmt.Errorf("book or member not found") } if !book.IsAvailable() { return fmt.Errorf("book is not available") } if len(member.GetBorrowedBooks()) >= maxBooksPerMember { return fmt.Errorf("member %s has reached the maximum number of borrowed books", member.Name) } member.BorrowBook(book) book.SetAvailable(false) fmt.Printf("Book borrowed: %s by %s\n", book.Title, member.Name) return nil } func (lm *LibraryManager) ReturnBook(memberID, isbn string) error { lm.mu.Lock() defer lm.mu.Unlock() member := lm.members[memberID] book := lm.catalog[isbn] if member == nil || book == nil { return fmt.Errorf("book or member not found") } member.ReturnBook(book) book.SetAvailable(true) fmt.Printf("Book returned: %s by %s\n", book.Title, member.Name) return nil } func (lm *LibraryManager) SearchBooks(keyword string) []*Book { lm.mu.RLock() defer lm.mu.RUnlock() keyword = strings.ToLower(keyword) matchingBooks := make([]*Book, 0) for _, book := range lm.catalog { if strings.Contains(strings.ToLower(book.Title), keyword) || strings.Contains(strings.ToLower(book.Author), keyword) { matchingBooks = append(matchingBooks, book) } } return matchingBooks } ================================================ FILE: solutions/golang/librarymanagementsystem/member.go ================================================ package librarymanagementsystem import "sync" type Member struct { MemberID string Name string ContactInfo string borrowedBooks map[string]*Book // Using map for O(1) lookups mu sync.RWMutex } func NewMember(memberID, name, contactInfo string) *Member { return &Member{ MemberID: memberID, Name: name, ContactInfo: contactInfo, borrowedBooks: make(map[string]*Book), } } func (m *Member) BorrowBook(book *Book) { m.mu.Lock() defer m.mu.Unlock() m.borrowedBooks[book.ISBN] = book } func (m *Member) ReturnBook(book *Book) { m.mu.Lock() defer m.mu.Unlock() delete(m.borrowedBooks, book.ISBN) } func (m *Member) GetBorrowedBooks() []*Book { m.mu.RLock() defer m.mu.RUnlock() books := make([]*Book, 0, len(m.borrowedBooks)) for _, book := range m.borrowedBooks { books = append(books, book) } return books } ================================================ FILE: solutions/golang/linkedin/README.md ================================================ # Designing a Professional Networking Platform like LinkedIn ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their professional information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their professional information, such as profile picture, headline, summary, experience, education, and skills. - Users should be able to update their profile information. #### Connections: - Users should be able to send connection requests to other users. - Users should be able to accept or decline connection requests. - Users should be able to view their list of connections. #### Messaging: - Users should be able to send messages to their connections. - Users should be able to view their inbox and sent messages. #### Job Postings: - Employers should be able to post job listings with details such as title, description, requirements, and location. - Users should be able to view and apply for job postings. #### Search Functionality: - Users should be able to search for other users, companies, and job postings based on relevant criteria. - Search results should be ranked based on relevance and user preferences. #### Notifications: - Users should receive notifications for events such as connection requests, messages, and job postings. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the LinkedIn system, containing properties such as ID, name, email, password, profile, connections, inbox, and sent messages. 2. The **Profile** class represents a user's profile, containing properties such as profile picture, headline, summary, experiences, educations, and skills. 3. The **Experience**, **Education**, and **Skill** classes represent different components of a user's profile. 4. The **Connection** class represents a connection between two users, containing the user and the connection date. 5. The **Message** class represents a message sent between users, containing properties such as ID, sender, receiver, content, and timestamp. 6. The **JobPosting** class represents a job listing posted by an employer, containing properties such as ID, title, description, requirements, location, and post date. 7. The **Notification** class represents a notification generated for a user, containing properties such as ID, user, notification type, content, and timestamp. 8. The **NotificationType** enum defines the different types of notifications, such as connection request, message, and job posting. 9. The **LinkedInService** class is the main class that manages the LinkedIn system. It follows the Singleton pattern to ensure only one instance of the service exists. 10. The **LinkedInService** class provides methods for user registration, login, profile updates, connection requests, job postings, user and job search, messaging, and notifications. 11. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 12. The **LinkedInDemo** class demonstrates the usage of the LinkedIn system by registering users, logging in, updating profiles, sending connection requests, posting job listings, searching for users and jobs, sending messages, and retrieving notifications. ================================================ FILE: solutions/golang/linkedin/connection.go ================================================ package linkedin import "time" type Connection struct { User *User ConnectionDate time.Time } func NewConnection(user *User) *Connection { return &Connection{ User: user, ConnectionDate: time.Now(), } } ================================================ FILE: solutions/golang/linkedin/education.go ================================================ package linkedin type Education struct { School string Degree string FieldOfStudy string StartDate string EndDate string } ================================================ FILE: solutions/golang/linkedin/experience.go ================================================ package linkedin type Experience struct { Title string Company string StartDate string EndDate string Description string } ================================================ FILE: solutions/golang/linkedin/job_posting.go ================================================ package linkedin import "time" type JobPosting struct { ID string Title string Description string Requirements []string Location string PostDate time.Time } func NewJobPosting(id, title, description string, requirements []string, location string) *JobPosting { return &JobPosting{ ID: id, Title: title, Description: description, Requirements: requirements, Location: location, PostDate: time.Now(), } } ================================================ FILE: solutions/golang/linkedin/linkedin_service.go ================================================ package linkedin import ( "fmt" "strings" "sync" "time" ) type LinkedInService struct { users map[string]*User jobPostings map[string]*JobPosting notifications map[string][]*Notification mu sync.RWMutex } var ( instance *LinkedInService once sync.Once ) func GetLinkedInService() *LinkedInService { once.Do(func() { instance = &LinkedInService{ users: make(map[string]*User), jobPostings: make(map[string]*JobPosting), notifications: make(map[string][]*Notification), } }) return instance } func (s *LinkedInService) RegisterUser(user *User) { s.mu.Lock() defer s.mu.Unlock() s.users[user.ID] = user } func (s *LinkedInService) LoginUser(email, password string) (*User, error) { s.mu.RLock() defer s.mu.RUnlock() for _, user := range s.users { if user.Email == email && user.Password == password { return user, nil } } return nil, fmt.Errorf("invalid email or password") } func (s *LinkedInService) UpdateUserProfile(user *User) { s.mu.Lock() defer s.mu.Unlock() s.users[user.ID] = user } func (s *LinkedInService) SendConnectionRequest(sender, receiver *User) { connection := NewConnection(sender) receiver.AddConnection(connection) notification := NewNotification( fmt.Sprintf("NOTIF-%d", time.Now().UnixNano()), receiver, NotificationTypeConnectionRequest, fmt.Sprintf("New connection request from %s", sender.Name), ) s.addNotification(receiver.ID, notification) } func (s *LinkedInService) AcceptConnectionRequest(user, connectionUser *User) { user.AddConnection(NewConnection(connectionUser)) } func (s *LinkedInService) SearchUsers(keyword string) []*User { s.mu.RLock() defer s.mu.RUnlock() var results []*User keyword = strings.ToLower(keyword) for _, user := range s.users { if strings.Contains(strings.ToLower(user.Name), keyword) { results = append(results, user) } } return results } func (s *LinkedInService) PostJobListing(jobPosting *JobPosting) { s.mu.Lock() s.jobPostings[jobPosting.ID] = jobPosting s.mu.Unlock() // Notify all users about new job posting for _, user := range s.users { notification := NewNotification( fmt.Sprintf("NOTIF-%d", time.Now().UnixNano()), user, NotificationTypeJobPosting, fmt.Sprintf("New job posting: %s", jobPosting.Title), ) s.addNotification(user.ID, notification) } } func (s *LinkedInService) SearchJobPostings(keyword string) []*JobPosting { s.mu.RLock() defer s.mu.RUnlock() var results []*JobPosting keyword = strings.ToLower(keyword) for _, posting := range s.jobPostings { if strings.Contains(strings.ToLower(posting.Title), keyword) || strings.Contains(strings.ToLower(posting.Description), keyword) { results = append(results, posting) } } return results } func (s *LinkedInService) SendMessage(sender, receiver *User, content string) { message := NewMessage( fmt.Sprintf("MSG-%d", time.Now().UnixNano()), sender, receiver, content, ) receiver.AddMessage(message, false) sender.AddMessage(message, true) notification := NewNotification( fmt.Sprintf("NOTIF-%d", time.Now().UnixNano()), receiver, NotificationTypeMessage, fmt.Sprintf("New message from %s", sender.Name), ) s.addNotification(receiver.ID, notification) } func (s *LinkedInService) addNotification(userID string, notification *Notification) { s.mu.Lock() defer s.mu.Unlock() s.notifications[userID] = append(s.notifications[userID], notification) } func (s *LinkedInService) GetNotifications(userID string) []*Notification { s.mu.RLock() defer s.mu.RUnlock() return s.notifications[userID] } ================================================ FILE: solutions/golang/linkedin/linkedin_service_demo.go ================================================ package linkedin import ( "fmt" ) func Run() { service := GetLinkedInService() // Create users user1 := NewUser("1", "John Doe", "john@example.com", "password") user2 := NewUser("2", "Jane Smith", "jane@example.com", "password") service.RegisterUser(user1) service.RegisterUser(user2) // Login loggedInUser, err := service.LoginUser("john@example.com", "password") if err != nil { fmt.Printf("Login failed: %v\n", err) return } fmt.Printf("User logged in: %s\n", loggedInUser.Name) // Update profile loggedInUser.Profile.SetHeadline("Software Engineer") loggedInUser.Profile.SetSummary("Passionate about coding and problem-solving.") service.UpdateUserProfile(loggedInUser) // Send connection request service.SendConnectionRequest(user1, user2) // Accept connection request service.AcceptConnectionRequest(user2, user1) // Post job listing jobPosting := NewJobPosting( "1", "Software Developer", "We are hiring!", []string{"Java", "Python"}, "San Francisco", ) service.PostJobListing(jobPosting) // Search users searchResults := service.SearchUsers("John") fmt.Println("\nSearch Results:") for _, user := range searchResults { fmt.Printf("Name: %s\n", user.Name) fmt.Printf("Headline: %s\n\n", user.Profile.Headline) } // Search job postings jobResults := service.SearchJobPostings("Software") fmt.Println("Job Posting Results:") for _, posting := range jobResults { fmt.Printf("Title: %s\n", posting.Title) fmt.Printf("Description: %s\n\n", posting.Description) } // Send message service.SendMessage(user1, user2, "Hi Jane, hope you're doing well!") // Get notifications notifications := service.GetNotifications(user2.ID) fmt.Println("Notifications:") for _, notification := range notifications { fmt.Printf("Type: %v\n", notification.Type) fmt.Printf("Content: %s\n\n", notification.Content) } } ================================================ FILE: solutions/golang/linkedin/message.go ================================================ package linkedin import "time" type Message struct { ID string Sender *User Receiver *User Content string Timestamp time.Time } func NewMessage(id string, sender, receiver *User, content string) *Message { return &Message{ ID: id, Sender: sender, Receiver: receiver, Content: content, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/linkedin/notification.go ================================================ package linkedin import "time" type Notification struct { ID string User *User Type NotificationType Content string Timestamp time.Time } func NewNotification(id string, user *User, notifType NotificationType, content string) *Notification { return &Notification{ ID: id, User: user, Type: notifType, Content: content, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/linkedin/profile.go ================================================ package linkedin import "sync" type Profile struct { ProfilePicture string Headline string Summary string Experiences []*Experience Educations []*Education Skills []*Skill mu sync.RWMutex } func NewProfile() *Profile { return &Profile{ Experiences: make([]*Experience, 0), Educations: make([]*Education, 0), Skills: make([]*Skill, 0), } } func (p *Profile) SetSummary(summary string) { p.mu.Lock() defer p.mu.Unlock() p.Summary = summary } func (p *Profile) SetHeadline(headline string) { p.mu.Lock() defer p.mu.Unlock() p.Headline = headline } ================================================ FILE: solutions/golang/linkedin/skill.go ================================================ package linkedin type Skill struct { Name string } ================================================ FILE: solutions/golang/linkedin/types.go ================================================ package linkedin type NotificationType int const ( NotificationTypeConnectionRequest NotificationType = iota NotificationTypeMessage NotificationTypeJobPosting ) ================================================ FILE: solutions/golang/linkedin/user.go ================================================ package linkedin import "sync" type User struct { ID string Name string Email string Password string Profile *Profile connections []*Connection inbox []*Message sentMessages []*Message mu sync.RWMutex } func NewUser(id, name, email, password string) *User { return &User{ ID: id, Name: name, Email: email, Password: password, Profile: NewProfile(), connections: make([]*Connection, 0), inbox: make([]*Message, 0), sentMessages: make([]*Message, 0), } } func (u *User) AddConnection(connection *Connection) { u.mu.Lock() defer u.mu.Unlock() u.connections = append(u.connections, connection) } func (u *User) AddMessage(message *Message, isSent bool) { u.mu.Lock() defer u.mu.Unlock() if isSent { u.sentMessages = append(u.sentMessages, message) } else { u.inbox = append(u.inbox, message) } } ================================================ FILE: solutions/golang/loggingframework/README.md ================================================ # Designing a Logging Framework ## Requirements 1. The logging framework should support different log levels, such as DEBUG, INFO, WARNING, ERROR, and FATAL. 2. It should allow logging messages with a timestamp, log level, and message content. 3. The framework should support multiple output destinations, such as console, file, and database. 4. It should provide a configuration mechanism to set the log level and output destination. 5. The logging framework should be thread-safe to handle concurrent logging from multiple threads. 6. It should be extensible to accommodate new log levels and output destinations in the future. ## Classes, Interfaces and Enumerations 1. The **LogLevel** enum defines the different log levels supported by the logging framework. 2. The **LogMessage** class represents a log message with a timestamp, log level, and message content. 3. The **LogAppender** interface defines the contract for appending log messages to different output destinations. 4. The **ConsoleAppender**, **FileAppender**, and **DatabaseAppender** classes are concrete implementations of the LogAppender interface, supporting logging to the console, file, and database, respectively. 5. The **LoggerConfig** class holds the configuration settings for the logger, including the log level and the selected log appender. 6. The **Logger** class is a singleton that provides the main logging functionality. It allows setting the configuration, logging messages at different levels, and provides convenience methods for each log level. 7. The **LoggingExample** class demonstrates the usage of the logging framework, showcasing different log levels, changing the configuration, and logging from multiple threads. ================================================ FILE: solutions/golang/loggingframework/console_appender.go ================================================ package loggingframework import "fmt" type ConsoleAppender struct{} func NewConsoleAppender() *ConsoleAppender { return &ConsoleAppender{} } func (a *ConsoleAppender) Append(message *LogMessage) error { fmt.Println(message.String()) return nil } ================================================ FILE: solutions/golang/loggingframework/database_appender.go ================================================ package loggingframework import ( "database/sql" "fmt" ) type DatabaseAppender struct { db *sql.DB } func NewDatabaseAppender(jdbcURL, username, password string) (*DatabaseAppender, error) { db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s", username, password, jdbcURL)) if err != nil { return nil, err } return &DatabaseAppender{ db: db, }, nil } func (a *DatabaseAppender) Append(message *LogMessage) error { stmt, err := a.db.Prepare("INSERT INTO logs (level, message, timestamp) VALUES (?, ?, ?)") if err != nil { return err } defer stmt.Close() _, err = stmt.Exec(message.Level.String(), message.Message, message.Timestamp) return err } ================================================ FILE: solutions/golang/loggingframework/file_appender.go ================================================ package loggingframework import ( "os" ) type FileAppender struct { filePath string } func NewFileAppender(filePath string) *FileAppender { return &FileAppender{ filePath: filePath, } } func (a *FileAppender) Append(message *LogMessage) error { f, err := os.OpenFile(a.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } defer f.Close() _, err = f.WriteString(message.String() + "\n") return err } ================================================ FILE: solutions/golang/loggingframework/log_appender.go ================================================ package loggingframework type LogAppender interface { Append(message *LogMessage) error } ================================================ FILE: solutions/golang/loggingframework/log_level.go ================================================ package loggingframework type LogLevel int const ( LogLevelDebug LogLevel = iota LogLevelInfo LogLevelWarning LogLevelError LogLevelFatal ) func (l LogLevel) String() string { return [...]string{"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"}[l] } ================================================ FILE: solutions/golang/loggingframework/log_message.go ================================================ package loggingframework import ( "fmt" "time" ) type LogMessage struct { Level LogLevel Message string Timestamp int64 } func NewLogMessage(level LogLevel, message string) *LogMessage { return &LogMessage{ Level: level, Message: message, Timestamp: time.Now().UnixMilli(), } } func (m *LogMessage) String() string { return fmt.Sprintf("[%s] %d - %s", m.Level, m.Timestamp, m.Message) } ================================================ FILE: solutions/golang/loggingframework/logger.go ================================================ package loggingframework import ( "sync" ) type Logger struct { config *LoggerConfig mu sync.RWMutex } var ( instance *Logger once sync.Once ) func GetLogger() *Logger { once.Do(func() { instance = &Logger{ config: NewLoggerConfig(LogLevelInfo, NewConsoleAppender()), } }) return instance } func (l *Logger) SetConfig(config *LoggerConfig) { l.mu.Lock() defer l.mu.Unlock() l.config = config } func (l *Logger) log(level LogLevel, message string) error { l.mu.RLock() if level < l.config.Level { l.mu.RUnlock() return nil } appender := l.config.Appender l.mu.RUnlock() logMessage := NewLogMessage(level, message) return appender.Append(logMessage) } func (l *Logger) Debug(message string) error { return l.log(LogLevelDebug, message) } func (l *Logger) Info(message string) error { return l.log(LogLevelInfo, message) } func (l *Logger) Warning(message string) error { return l.log(LogLevelWarning, message) } func (l *Logger) Error(message string) error { return l.log(LogLevelError, message) } func (l *Logger) Fatal(message string) error { return l.log(LogLevelFatal, message) } ================================================ FILE: solutions/golang/loggingframework/logger_config.go ================================================ package loggingframework type LoggerConfig struct { Level LogLevel Appender LogAppender } func NewLoggerConfig(level LogLevel, appender LogAppender) *LoggerConfig { return &LoggerConfig{ Level: level, Appender: appender, } } ================================================ FILE: solutions/golang/loggingframework/logging_framework_demo.go ================================================ package loggingframework import ( "fmt" ) func Run() { logger := GetLogger() // Logging with default configuration logger.Info("This is an information message") logger.Warning("This is a warning message") logger.Error("This is an error message") // Changing log level and appender fileAppender := NewFileAppender("app.log") config := NewLoggerConfig(LogLevelDebug, fileAppender) logger.SetConfig(config) if err := logger.Debug("This is a debug message"); err != nil { fmt.Printf("Error logging debug message: %v\n", err) } if err := logger.Info("This is an information message"); err != nil { fmt.Printf("Error logging info message: %v\n", err) } } ================================================ FILE: solutions/golang/lrucache/README.md ================================================ # Designing a LRU Cache ## Requirements 1. The LRU cache should support the following operations: - put(key, value): Insert a key-value pair into the cache. If the cache is at capacity, remove the least recently used item before inserting the new item. - get(key): Get the value associated with the given key. If the key exists in the cache, move it to the front of the cache (most recently used) and return its value. If the key does not exist, return -1. 2. The cache should have a fixed capacity, specified during initialization. 3. The cache should be thread-safe, allowing concurrent access from multiple threads. 4. The cache should be efficient in terms of time complexity for both put and get operations, ideally O(1). ## Classes, Interfaces and Enumerations 1. The **Node** class represents a node in the doubly linked list, containing the key, value, and references to the previous and next nodes. 2. The **LRUCache** class implements the LRU cache functionality using a combination of a hash map (cache) and a doubly linked list (head and tail). 3. The get method retrieves the value associated with a given key. If the key exists in the cache, it is moved to the head of the linked list (most recently used) and its value is returned. If the key does not exist, null is returned. 4. The put method inserts a key-value pair into the cache. If the key already exists, its value is updated, and the node is moved to the head of the linked list. If the key does not exist and the cache is at capacity, the least recently used item (at the tail of the linked list) is removed, and the new item is inserted at the head. 5. The addToHead, removeNode, moveToHead, and removeTail methods are helper methods to manipulate the doubly linked list. 6. The synchronized keyword is used on the get and put methods to ensure thread safety, allowing concurrent access from multiple threads. 7. The **LRUCacheDemo** class demonstrates the usage of the LRU cache by creating an instance of LRUCache with a capacity of 3, performing various put and get operations, and printing the results. ================================================ FILE: solutions/golang/lrucache/lru_cache.go ================================================ package lrucache import ( "sync" ) // Node represents a node in the doubly linked list type Node[K comparable, V any] struct { key K value V prev *Node[K, V] next *Node[K, V] } // LRUCache represents a thread-safe LRU cache implementation type LRUCache[K comparable, V any] struct { capacity int cache map[K]*Node[K, V] head *Node[K, V] tail *Node[K, V] mu sync.RWMutex } // NewLRUCache creates a new LRU cache with the specified capacity func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] { cache := &LRUCache[K, V]{ capacity: capacity, cache: make(map[K]*Node[K, V]), } // Initialize dummy head and tail nodes cache.head = &Node[K, V]{} cache.tail = &Node[K, V]{} cache.head.next = cache.tail cache.tail.prev = cache.head return cache } // Get retrieves a value from the cache func (c *LRUCache[K, V]) Get(key K) (V, bool) { c.mu.Lock() defer c.mu.Unlock() if node, exists := c.cache[key]; exists { c.moveToHead(node) return node.value, true } var zero V return zero, false } // Put adds or updates a value in the cache func (c *LRUCache[K, V]) Put(key K, value V) { c.mu.Lock() defer c.mu.Unlock() if node, exists := c.cache[key]; exists { node.value = value c.moveToHead(node) return } newNode := &Node[K, V]{ key: key, value: value, } c.cache[key] = newNode c.addToHead(newNode) if len(c.cache) > c.capacity { lastNode := c.removeTail() delete(c.cache, lastNode.key) } } // addToHead adds a node right after the head func (c *LRUCache[K, V]) addToHead(node *Node[K, V]) { node.prev = c.head node.next = c.head.next c.head.next.prev = node c.head.next = node } // removeNode removes a node from the list func (c *LRUCache[K, V]) removeNode(node *Node[K, V]) { node.prev.next = node.next node.next.prev = node.prev } // moveToHead moves an existing node to the front of the list func (c *LRUCache[K, V]) moveToHead(node *Node[K, V]) { c.removeNode(node) c.addToHead(node) } // removeTail removes and returns the last node before the tail func (c *LRUCache[K, V]) removeTail() *Node[K, V] { node := c.tail.prev c.removeNode(node) return node } // Size returns the current number of items in the cache func (c *LRUCache[K, V]) Size() int { c.mu.RLock() defer c.mu.RUnlock() return len(c.cache) } // Clear removes all items from the cache func (c *LRUCache[K, V]) Clear() { c.mu.Lock() defer c.mu.Unlock() c.cache = make(map[K]*Node[K, V]) c.head.next = c.tail c.tail.prev = c.head } ================================================ FILE: solutions/golang/lrucache/lru_cache_demo.go ================================================ package lrucache import ( "fmt" ) func Run() { // Create a new cache with capacity 3 lruCache := NewLRUCache[int, string](3) // Add some values lruCache.Put(1, "Value 1") lruCache.Put(2, "Value 2") lruCache.Put(3, "Value 3") // Get values and print them if val, exists := lruCache.Get(1); exists { fmt.Println(val) // Output: Value 1 } if val, exists := lruCache.Get(2); exists { fmt.Println(val) // Output: Value 2 } // Add a new value that should evict the least recently used one lruCache.Put(4, "Value 4") // Try to get the evicted value if val, exists := lruCache.Get(3); exists { fmt.Println(val) } else { fmt.Println("Value 3 was evicted") // Output: Value 3 was evicted } // Get the newly added value if val, exists := lruCache.Get(4); exists { fmt.Println(val) // Output: Value 4 } // Update an existing value lruCache.Put(2, "Updated Value 2") // Get the values again if val, exists := lruCache.Get(1); exists { fmt.Println(val) // Output: Value 1 } if val, exists := lruCache.Get(2); exists { fmt.Println(val) // Output: Updated Value 2 } } ================================================ FILE: solutions/golang/main.go ================================================ package main import ( "fmt" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/movieticketbookingsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/airlinemanagementsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/linkedin" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/librarymanagementsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/fooddeliveryservice" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/elevatorsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/digitalwallet" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/courseregistrationsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/coffeevendingmachine" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/chessgame" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/carrentalsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/atm" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/lrucache" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/loggingframework" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/music_streaming_service" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/onlineauctionsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/onlineshopping" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/onlinestockbrokeragesystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/parkinglot" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/pubsubsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/restaurantmanagementsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/ridesharingservice" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/snake_and_ladder_game" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/social_networking_service" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/splitwise" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/stackoverflow" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/taskmanagementsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/tictactoe" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/trafficsignalsystem" // "github.com/ashishps1/awesome-low-level-design/solutions/golang/vending_machine" ) func main() { fmt.Println("Starting Projects") // airlinemanagementsystem.Run() // atm.Run() // carrentalsystem.Run() // chessgame.Run() // coffeevendingmachine.Run() // concertbookingsystem.Run() // courseregistrationsystem.Run() // cricinfo.Run() // digitalwallet.Run() // elevatorsystem.Run() // fooddeliveryservice.Run() // hotelmanagement.Run() // librarymanagementsystem.Run() // linkedin.Run() // loggingframework.Run() // lrucache.Run() // movieticketbookingsystem.Run() // musicstreamingservice.Run() // onlineauctionsystem.Run() // onlineshopping.Run() // onlinestockbrokeragesystem.Run() // parkinglot.Run() // pubsubsystem.Run() // restaurantmanagementsystem.Run() // ridesharingservice.Run() // snakeandladdergame.Run() // socialnetworkingservice.Run() // splitwise.Run() // stackoverflow.Run() // taskmanagementsystem.Run() // tictactoe.Run() // trafficsignalsystem.Run() // vending_machine.Run() } ================================================ FILE: solutions/golang/movieticketbookingsystem/README.md ================================================ # Designing a Movie Ticket Booking System like BookMyShow ## Requirements 1. The system should allow users to view the list of movies playing in different theaters. 2. Users should be able to select a movie, theater, and show timing to book tickets. 3. The system should display the seating arrangement of the selected show and allow users to choose seats. 4. Users should be able to make payments and confirm their booking. 5. The system should handle concurrent bookings and ensure seat availability is updated in real-time. 6. The system should support different types of seats (e.g., normal, premium) and pricing. 7. The system should allow theater administrators to add, update, and remove movies, shows, and seating arrangements. 8. The system should be scalable to handle a large number of concurrent users and bookings. ## Classes, Interfaces and Enumerations 1. The **Movie** class represents a movie with properties such as ID, title, description, and duration. 2. The **Theater** class represents a theater with properties such as ID, name, location, and a list of shows. 3. The **Show** class represents a movie show in a theater, with properties such as ID, movie, theater, start time, end time, and a map of seats. 4. The **Seat** class represents a seat in a show, with properties such as ID, row, column, type, price, and status. 5. The **SeatType** enum defines the different types of seats (normal or premium). 6. The **SeatStatus** enum defines the different statuses of a seat (available or booked). 7. The **Booking** class represents a booking made by a user, with properties such as ID, user, show, selected seats, total price, and status. 8. The **BookingStatus** enum defines the different statuses of a booking (pending, confirmed, or cancelled). 9. The **User** class represents a user of the booking system, with properties such as ID, name, and email. 10. The **MovieTicketBookingSystem** class is the main class that manages the movie ticket booking system. It follows the Singleton pattern to ensure only one instance of the system exists. 11. The MovieTicketBookingSystem class provides methods for adding movies, theaters, and shows, as well as booking tickets, confirming bookings, and cancelling bookings. 12. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap to handle concurrent access to shared resources like shows and bookings. 13. The **MovieTicketBookingDemo** class demonstrates the usage of the movie ticket booking system by adding movies, theaters, shows, booking tickets, and confirming or cancelling bookings. ================================================ FILE: solutions/golang/movieticketbookingsystem/booking.go ================================================ package movieticketbookingsystem import "sync" type Booking struct { ID string User *User Show *Show Seats []*Seat TotalPrice float64 Status BookingStatus mu sync.RWMutex } func NewBooking(id string, user *User, show *Show, seats []*Seat, totalPrice float64, status BookingStatus) *Booking { return &Booking{ ID: id, User: user, Show: show, Seats: seats, TotalPrice: totalPrice, Status: status, } } func (b *Booking) GetStatus() BookingStatus { b.mu.RLock() defer b.mu.RUnlock() return b.Status } func (b *Booking) SetStatus(status BookingStatus) { b.mu.Lock() defer b.mu.Unlock() b.Status = status } ================================================ FILE: solutions/golang/movieticketbookingsystem/movie.go ================================================ package movieticketbookingsystem type Movie struct { ID string Title string Description string DurationMinutes int } func NewMovie(id, title, description string, durationMinutes int) *Movie { return &Movie{ ID: id, Title: title, Description: description, DurationMinutes: durationMinutes, } } ================================================ FILE: solutions/golang/movieticketbookingsystem/movie_ticket_booking_system.go ================================================ package movieticketbookingsystem import ( "fmt" "sync" "sync/atomic" "time" ) type MovieTicketBookingSystem struct { movies []*Movie theaters []*Theater shows map[string]*Show bookings map[string]*Booking mu sync.RWMutex bookingCount int64 } var ( instance *MovieTicketBookingSystem once sync.Once ) func GetBookingSystem() *MovieTicketBookingSystem { once.Do(func() { instance = &MovieTicketBookingSystem{ movies: make([]*Movie, 0), theaters: make([]*Theater, 0), shows: make(map[string]*Show), bookings: make(map[string]*Booking), } }) return instance } func (bs *MovieTicketBookingSystem) AddMovie(movie *Movie) { bs.mu.Lock() defer bs.mu.Unlock() bs.movies = append(bs.movies, movie) } func (bs *MovieTicketBookingSystem) AddTheater(theater *Theater) { bs.mu.Lock() defer bs.mu.Unlock() bs.theaters = append(bs.theaters, theater) } func (bs *MovieTicketBookingSystem) AddShow(show *Show) { bs.mu.Lock() defer bs.mu.Unlock() bs.shows[show.ID] = show } func (bs *MovieTicketBookingSystem) GetShow(showID string) *Show { bs.mu.RLock() defer bs.mu.RUnlock() return bs.shows[showID] } func (bs *MovieTicketBookingSystem) BookTickets(user *User, show *Show, selectedSeats []*Seat) (*Booking, error) { bs.mu.Lock() defer bs.mu.Unlock() // Check seat availability for _, seat := range selectedSeats { showSeat, exists := show.Seats[seat.ID] if !exists || showSeat.GetStatus() != SeatStatusAvailable { return nil, fmt.Errorf("seat %s is not available", seat.ID) } } // Mark seats as booked for _, seat := range selectedSeats { show.Seats[seat.ID].SetStatus(SeatStatusBooked) } // Calculate total price var totalPrice float64 for _, seat := range selectedSeats { totalPrice += seat.GetPrice() } // Generate booking ID bookingID := bs.generateBookingID() // Create booking booking := NewBooking(bookingID, user, show, selectedSeats, totalPrice, BookingStatusPending) bs.bookings[bookingID] = booking return booking, nil } func (bs *MovieTicketBookingSystem) ConfirmBooking(bookingID string) error { bs.mu.Lock() defer bs.mu.Unlock() booking, exists := bs.bookings[bookingID] if !exists { return fmt.Errorf("booking not found") } if booking.GetStatus() != BookingStatusPending { return fmt.Errorf("booking is not in pending state") } booking.SetStatus(BookingStatusConfirmed) return nil } func (bs *MovieTicketBookingSystem) CancelBooking(bookingID string) error { bs.mu.Lock() defer bs.mu.Unlock() booking, exists := bs.bookings[bookingID] if !exists { return fmt.Errorf("booking not found") } if booking.GetStatus() == BookingStatusCancelled { return fmt.Errorf("booking is already cancelled") } booking.SetStatus(BookingStatusCancelled) // Release seats for _, seat := range booking.Seats { booking.Show.Seats[seat.ID].SetStatus(SeatStatusAvailable) } return nil } func (bs *MovieTicketBookingSystem) generateBookingID() string { count := atomic.AddInt64(&bs.bookingCount, 1) return fmt.Sprintf("BKG%s%06d", time.Now().Format("20060102150405"), count) } // Create utility function for demo func CreateSeats(rows, columns int) map[string]*Seat { seats := make(map[string]*Seat) for row := 1; row <= rows; row++ { for col := 1; col <= columns; col++ { seatID := fmt.Sprintf("%d-%d", row, col) seatType := SeatTypeNormal price := 100.0 if row <= 2 { seatType = SeatTypePremium price = 150.0 } seats[seatID] = NewSeat( seatID, row, col, seatType, price, SeatStatusAvailable, ) } } return seats } ================================================ FILE: solutions/golang/movieticketbookingsystem/movie_ticket_booking_system_demo.go ================================================ package movieticketbookingsystem import ( "fmt" "time" ) func Run() { bookingSystem := GetBookingSystem() // Add movies movie1 := NewMovie("M1", "Movie 1", "Description 1", 120) movie2 := NewMovie("M2", "Movie 2", "Description 2", 135) bookingSystem.AddMovie(movie1) bookingSystem.AddMovie(movie2) // Add theaters theater1 := NewTheater("T1", "Theater 1", "Location 1") theater2 := NewTheater("T2", "Theater 2", "Location 2") bookingSystem.AddTheater(theater1) bookingSystem.AddTheater(theater2) // Add shows show1 := NewShow( "S1", movie1, theater1, time.Now(), time.Now().Add(time.Duration(movie1.DurationMinutes)*time.Minute), CreateSeats(10, 10), ) show2 := NewShow( "S2", movie2, theater2, time.Now(), time.Now().Add(time.Duration(movie2.DurationMinutes)*time.Minute), CreateSeats(8, 8), ) bookingSystem.AddShow(show1) bookingSystem.AddShow(show2) // Create user user := NewUser("U1", "John Doe", "john@example.com") // Select seats selectedSeats := []*Seat{ show1.Seats["1-5"], show1.Seats["1-6"], } // Book tickets booking, err := bookingSystem.BookTickets(user, show1, selectedSeats) if err != nil { fmt.Printf("Booking failed: %v\n", err) return } fmt.Printf("Booking successful. Booking ID: %s\n", booking.ID) // Confirm booking if err := bookingSystem.ConfirmBooking(booking.ID); err != nil { fmt.Printf("Failed to confirm booking: %v\n", err) return } fmt.Println("Booking confirmed") // Cancel booking if err := bookingSystem.CancelBooking(booking.ID); err != nil { fmt.Printf("Failed to cancel booking: %v\n", err) return } fmt.Printf("Booking canceled. Booking ID: %s\n", booking.ID) } ================================================ FILE: solutions/golang/movieticketbookingsystem/seat.go ================================================ package movieticketbookingsystem import "sync" type Seat struct { ID string Row int Column int Type SeatType Price float64 status SeatStatus mu sync.RWMutex } func NewSeat(id string, row, column int, seatType SeatType, price float64, status SeatStatus) *Seat { return &Seat{ ID: id, Row: row, Column: column, Type: seatType, Price: price, status: status, } } func (s *Seat) GetStatus() SeatStatus { s.mu.RLock() defer s.mu.RUnlock() return s.status } func (s *Seat) SetStatus(status SeatStatus) { s.mu.Lock() defer s.mu.Unlock() s.status = status } func (s *Seat) GetPrice() float64 { return s.Price } ================================================ FILE: solutions/golang/movieticketbookingsystem/show.go ================================================ package movieticketbookingsystem import ( "sync" "time" ) type Show struct { ID string Movie *Movie Theater *Theater StartTime time.Time EndTime time.Time Seats map[string]*Seat mu sync.RWMutex } func NewShow(id string, movie *Movie, theater *Theater, startTime, endTime time.Time, seats map[string]*Seat) *Show { return &Show{ ID: id, Movie: movie, Theater: theater, StartTime: startTime, EndTime: endTime, Seats: seats, } } ================================================ FILE: solutions/golang/movieticketbookingsystem/theater.go ================================================ package movieticketbookingsystem type Theater struct { ID string Name string Location string Shows []*Show } func NewTheater(id, name, location string) *Theater { return &Theater{ ID: id, Name: name, Location: location, Shows: make([]*Show, 0), } } ================================================ FILE: solutions/golang/movieticketbookingsystem/types.go ================================================ package movieticketbookingsystem type SeatType int type SeatStatus int type BookingStatus int const ( SeatTypeNormal SeatType = iota SeatTypePremium ) const ( SeatStatusAvailable SeatStatus = iota SeatStatusBooked ) const ( BookingStatusPending BookingStatus = iota BookingStatusConfirmed BookingStatusCancelled ) ================================================ FILE: solutions/golang/movieticketbookingsystem/user.go ================================================ package movieticketbookingsystem type User struct { ID string Name string Email string } func NewUser(id, name, email string) *User { return &User{ ID: id, Name: name, Email: email, } } ================================================ FILE: solutions/golang/musicstreamingservice/README.md ================================================ # Designing an Online Music Streaming Service Like Spotify ## Requirements 1. The music streaming service should allow users to browse and search for songs, albums, and artists. 2. Users should be able to create and manage playlists. 3. The system should support user authentication and authorization. 4. Users should be able to play, pause, skip, and seek within songs. 5. The system should recommend songs and playlists based on user preferences and listening history. 6. The system should handle concurrent requests and ensure smooth streaming experience for multiple users. 7. The system should be scalable and handle a large volume of songs and users. 8. The system should be extensible to support additional features such as social sharing and offline playback. ## Classes, Interfaces and Enumerations 1. The **Song**, **Album**, and **Artist** classes represent the basic entities in the music streaming service, with properties such as ID, title, artist, album, duration, and relationships between them. 2. The **User** class represents a user of the music streaming service, with properties like ID, username, password, and a list of playlists. 3. The **Playlist** class represents a user-created playlist, containing a list of songs. 4. The **MusicLibrary** class serves as a central repository for storing and managing songs, albums, and artists. It follows the Singleton pattern to ensure a single instance of the music library. 5. The **UserManager** class handles user registration, login, and other user-related operations. It also follows the Singleton pattern. 6. The **MusicPlayer** class represents the music playback functionality, allowing users to play, pause, skip, and seek within songs. 7. The **MusicRecommender** class generates song recommendations based on user preferences and listening history. It follows the Singleton pattern. 8. The **MusicStreamingService** class is the main entry point of the music streaming service. It initializes the necessary components, handles user requests, and manages the overall functionality of the service. ================================================ FILE: solutions/golang/musicstreamingservice/album.go ================================================ package musicstreamingservice type Album struct { ID string Title string Artist string Songs []*Song } ================================================ FILE: solutions/golang/musicstreamingservice/artist.go ================================================ package musicstreamingservice type Artist struct { ID string Name string Albums []*Album } ================================================ FILE: solutions/golang/musicstreamingservice/music_library.go ================================================ package musicstreamingservice import ( "strings" "sync" ) type MusicLibrary struct { songs map[string]*Song albums map[string]*Album artists map[string]*Artist mu sync.RWMutex } var ( libraryInstance *MusicLibrary libraryOnce sync.Once ) func GetMusicLibrary() *MusicLibrary { libraryOnce.Do(func() { libraryInstance = &MusicLibrary{ songs: make(map[string]*Song), albums: make(map[string]*Album), artists: make(map[string]*Artist), } }) return libraryInstance } func (ml *MusicLibrary) AddSong(song *Song) { ml.mu.Lock() defer ml.mu.Unlock() ml.songs[song.ID] = song } func (ml *MusicLibrary) AddAlbum(album *Album) { ml.mu.Lock() defer ml.mu.Unlock() ml.albums[album.ID] = album for _, song := range album.Songs { ml.songs[song.ID] = song } } func (ml *MusicLibrary) AddArtist(artist *Artist) { ml.mu.Lock() defer ml.mu.Unlock() ml.artists[artist.ID] = artist for _, album := range artist.Albums { ml.albums[album.ID] = album for _, song := range album.Songs { ml.songs[song.ID] = song } } } func (ml *MusicLibrary) SearchSongs(query string) []*Song { ml.mu.RLock() defer ml.mu.RUnlock() query = strings.ToLower(query) var results []*Song for _, song := range ml.songs { if strings.Contains(strings.ToLower(song.Title), query) || strings.Contains(strings.ToLower(song.Artist), query) || strings.Contains(strings.ToLower(song.Album), query) { results = append(results, song) } } return results } ================================================ FILE: solutions/golang/musicstreamingservice/music_player.go ================================================ package musicstreamingservice import "sync" type MusicPlayer struct { CurrentSong *Song IsPlaying bool CurrentTime int mu sync.Mutex } func NewMusicPlayer() *MusicPlayer { return &MusicPlayer{} } func (p *MusicPlayer) PlaySong(song *Song) { p.mu.Lock() defer p.mu.Unlock() p.CurrentSong = song p.IsPlaying = true p.CurrentTime = 0 // Implement actual playback logic here } func (p *MusicPlayer) PauseSong() { p.mu.Lock() defer p.mu.Unlock() p.IsPlaying = false // Implement actual pause logic here } func (p *MusicPlayer) SeekTo(time int) { p.mu.Lock() defer p.mu.Unlock() p.CurrentTime = time // Implement actual seek logic here } ================================================ FILE: solutions/golang/musicstreamingservice/music_recommender.go ================================================ package musicstreamingservice import ( "sync" ) type MusicRecommender struct { userRecommendations map[string][]*Song mu sync.RWMutex } var ( recommenderInstance *MusicRecommender recommenderOnce sync.Once ) func GetMusicRecommender() *MusicRecommender { recommenderOnce.Do(func() { recommenderInstance = &MusicRecommender{ userRecommendations: make(map[string][]*Song), } }) return recommenderInstance } func (mr *MusicRecommender) RecommendSongs(user *User) []*Song { mr.mu.RLock() defer mr.mu.RUnlock() if recommendations, exists := mr.userRecommendations[user.ID]; exists { return recommendations } return make([]*Song, 0) } ================================================ FILE: solutions/golang/musicstreamingservice/music_streaming_service.go ================================================ package musicstreamingservice type MusicStreamingService struct { MusicLibrary *MusicLibrary UserManager *UserManager MusicRecommender *MusicRecommender } func NewMusicStreamingService() *MusicStreamingService { return &MusicStreamingService{ MusicLibrary: GetMusicLibrary(), UserManager: GetUserManager(), MusicRecommender: GetMusicRecommender(), } } ================================================ FILE: solutions/golang/musicstreamingservice/music_streaming_service_demo.go ================================================ package musicstreamingservice import ( "fmt" ) func Run() { service := NewMusicStreamingService() // Create users user1 := NewUser("1", "john@example.com", "password123") user2 := NewUser("2", "jane@example.com", "password456") // Create songs song1 := &Song{ID: "1", Title: "Song 1", Artist: "Artist 1", Album: "Album 1", Duration: 180} song2 := &Song{ID: "2", Title: "Song 2", Artist: "Artist 2", Album: "Album 2", Duration: 200} song3 := &Song{ID: "3", Title: "Song 3", Artist: "Artist 3", Album: "Album 3", Duration: 210} // Create albums album1 := &Album{ID: "1", Title: "Album 1", Artist: "Artist 1", Songs: []*Song{song1}} album2 := &Album{ID: "2", Title: "Album 2", Artist: "Artist 2", Songs: []*Song{song2}} album3 := &Album{ID: "3", Title: "Album 3", Artist: "Artist 3", Songs: []*Song{song3}} // Create artists artist1 := &Artist{ID: "1", Name: "Artist 1", Albums: []*Album{album1}} artist2 := &Artist{ID: "2", Name: "Artist 2", Albums: []*Album{album2}} artist3 := &Artist{ID: "3", Name: "Artist 3", Albums: []*Album{album3}} // Add artists to library service.MusicLibrary.AddArtist(artist1) service.MusicLibrary.AddArtist(artist2) service.MusicLibrary.AddArtist(artist3) // Register users service.UserManager.RegisterUser(user1) service.UserManager.RegisterUser(user2) // Login user loggedInUser := service.UserManager.LoginUser("john@example.com", "password123") if loggedInUser != nil { fmt.Printf("User logged in: %s\n", loggedInUser.Username) } else { fmt.Println("Invalid username or password.") } // Search songs searchResults := service.MusicLibrary.SearchSongs("Song") fmt.Println("\nSearch Results:") for _, song := range searchResults { fmt.Printf("Song: %s - %s\n", song.Title, song.Artist) } // Create playlist playlist := NewPlaylist("1", "My Playlist", loggedInUser) playlist.AddSong(song1) playlist.AddSong(song2) loggedInUser.AddPlaylist(playlist) // Get recommendations recommendations := service.MusicRecommender.RecommendSongs(loggedInUser) fmt.Println("\nRecommended Songs:") for _, song := range recommendations { fmt.Printf("Song: %s - %s\n", song.Title, song.Artist) } // Create and use music player player := NewMusicPlayer() player.PlaySong(song1) player.PauseSong() player.SeekTo(60) // Display user playlists fmt.Println("\nUser Playlists:") for _, p := range loggedInUser.Playlists { fmt.Printf("Playlist: %s\n", p.Name) fmt.Println("Songs:") for _, s := range p.Songs { fmt.Printf("- %s\n", s.Title) } } } ================================================ FILE: solutions/golang/musicstreamingservice/playlist.go ================================================ package musicstreamingservice type Playlist struct { ID string Name string Owner *User Songs []*Song } func NewPlaylist(id, name string, owner *User) *Playlist { return &Playlist{ ID: id, Name: name, Owner: owner, Songs: make([]*Song, 0), } } func (p *Playlist) AddSong(song *Song) { p.Songs = append(p.Songs, song) } func (p *Playlist) RemoveSong(song *Song) { for i, s := range p.Songs { if s.ID == song.ID { p.Songs = append(p.Songs[:i], p.Songs[i+1:]...) return } } } ================================================ FILE: solutions/golang/musicstreamingservice/song.go ================================================ package musicstreamingservice type Song struct { ID string Title string Artist string Album string Duration int } ================================================ FILE: solutions/golang/musicstreamingservice/user.go ================================================ package musicstreamingservice import "sync" type User struct { ID string Username string Password string Playlists []*Playlist mu sync.RWMutex } func NewUser(id, username, password string) *User { return &User{ ID: id, Username: username, Password: password, Playlists: make([]*Playlist, 0), } } func (u *User) AddPlaylist(playlist *Playlist) { u.mu.Lock() defer u.mu.Unlock() u.Playlists = append(u.Playlists, playlist) } func (u *User) RemovePlaylist(playlist *Playlist) { u.mu.Lock() defer u.mu.Unlock() for i, p := range u.Playlists { if p.ID == playlist.ID { u.Playlists = append(u.Playlists[:i], u.Playlists[i+1:]...) return } } } ================================================ FILE: solutions/golang/musicstreamingservice/userManager.go ================================================ package musicstreamingservice import ( "sync" ) type UserManager struct { users map[string]*User mu sync.RWMutex } var ( userManagerInstance *UserManager userManagerOnce sync.Once ) func GetUserManager() *UserManager { userManagerOnce.Do(func() { userManagerInstance = &UserManager{ users: make(map[string]*User), } }) return userManagerInstance } func (um *UserManager) RegisterUser(user *User) { um.mu.Lock() defer um.mu.Unlock() um.users[user.ID] = user } func (um *UserManager) LoginUser(username, password string) *User { um.mu.RLock() defer um.mu.RUnlock() for _, user := range um.users { if user.Username == username && user.Password == password { return user } } return nil } ================================================ FILE: solutions/golang/onlineauctionsystem/README.md ================================================ # Designing an Online Auction System In this article, we delve into the object-oriented design and implementation of an Online Auction System using Java. This system allows for the creation and management of auctions, user participation in bidding, and handling transactions. ## Requirements 1. The online auction system should allow users to register and log in to their accounts. 2. Users should be able to create new auction listings with details such as item name, description, starting price, and auction duration. 3. Users should be able to browse and search for auction listings based on various criteria (e.g., item name, category, price range). 4. Users should be able to place bids on active auction listings. 5. The system should automatically update the current highest bid and notify the bidders accordingly. 6. The auction should end when the specified duration is reached, and the highest bidder should be declared the winner. 7. The system should handle concurrent access to auction listings and ensure data consistency. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online auction system, with properties such as id, username, and email. 2. The **AuctionStatus** enum defines the possible states of an auction listing, such as active and closed. 3. The **AuctionListing** class represents an auction listing in the system, with properties like id, item name, description, starting price, duration, seller, current highest bid, and a list of bids. 4. The **Bid** class represents a bid placed by a user on an auction listing, with properties such as id, bidder, amount, and timestamp. 5. The **AuctionSystem** class is the core of the online auction system and follows the Singleton pattern to ensure a single instance of the auction system. 6. The AuctionSystem class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to auction listings and ensure thread safety. 7. The AuctionSystem class provides methods for registering users, creating auction listings, searching auction listings, and placing bids. 8. The **AuctionSystemDemo** class serves as the entry point of the application and demonstrates the usage of the online auction system. ================================================ FILE: solutions/golang/onlineauctionsystem/auction_listing.go ================================================ package onlineauctionsystem import ( "sync" "time" ) type AuctionListing struct { ID string ItemName string Description string StartingPrice float64 Duration time.Duration Seller *User Status AuctionStatus CurrentHighestBid float64 CurrentHighestBidder *User Bids []*Bid mu sync.Mutex observers []chan struct{} // Simple channel-based observer pattern } func NewAuctionListing(id, itemName, description string, startingPrice float64, duration time.Duration, seller *User) *AuctionListing { return &AuctionListing{ ID: id, ItemName: itemName, Description: description, StartingPrice: startingPrice, Duration: duration, Seller: seller, Status: StatusActive, CurrentHighestBid: startingPrice, Bids: make([]*Bid, 0), observers: make([]chan struct{}, 0), } } func (a *AuctionListing) PlaceBid(bid *Bid) bool { a.mu.Lock() defer a.mu.Unlock() if a.Status == StatusActive && bid.Amount > a.CurrentHighestBid { a.CurrentHighestBid = bid.Amount a.CurrentHighestBidder = bid.Bidder a.Bids = append(a.Bids, bid) a.notifyObservers() return true } return false } func (a *AuctionListing) CloseAuction() { a.mu.Lock() defer a.mu.Unlock() if a.Status == StatusActive { a.Status = StatusClosed a.notifyObservers() } } func (a *AuctionListing) notifyObservers() { for _, observer := range a.observers { select { case observer <- struct{}{}: // Non-blocking send default: } } } ================================================ FILE: solutions/golang/onlineauctionsystem/auction_status.go ================================================ package onlineauctionsystem type AuctionStatus int const ( StatusActive AuctionStatus = iota StatusClosed ) ================================================ FILE: solutions/golang/onlineauctionsystem/auction_system.go ================================================ package onlineauctionsystem import ( "strings" "sync" "time" ) type AuctionSystem struct { users map[string]*User auctionListings map[string]*AuctionListing mu sync.RWMutex } var ( instance *AuctionSystem once sync.Once ) func GetInstance() *AuctionSystem { once.Do(func() { instance = &AuctionSystem{ users: make(map[string]*User), auctionListings: make(map[string]*AuctionListing), } }) return instance } func (as *AuctionSystem) RegisterUser(user *User) { as.mu.Lock() defer as.mu.Unlock() as.users[user.ID] = user } func (as *AuctionSystem) GetUser(userID string) *User { as.mu.RLock() defer as.mu.RUnlock() return as.users[userID] } func (as *AuctionSystem) CreateAuctionListing(listing *AuctionListing) { as.mu.Lock() as.auctionListings[listing.ID] = listing as.mu.Unlock() // Start auction timer go func() { time.Sleep(listing.Duration) listing.CloseAuction() }() } func (as *AuctionSystem) SearchAuctionListings(keyword string) []*AuctionListing { as.mu.RLock() defer as.mu.RUnlock() var matchingListings []*AuctionListing keyword = strings.ToLower(keyword) for _, listing := range as.auctionListings { if strings.Contains(strings.ToLower(listing.ItemName), keyword) || strings.Contains(strings.ToLower(listing.Description), keyword) { matchingListings = append(matchingListings, listing) } } return matchingListings } func (as *AuctionSystem) PlaceBid(auctionListingID string, bid *Bid) bool { as.mu.RLock() listing, exists := as.auctionListings[auctionListingID] as.mu.RUnlock() if exists { return listing.PlaceBid(bid) } return false } ================================================ FILE: solutions/golang/onlineauctionsystem/bid.go ================================================ package onlineauctionsystem import "time" type Bid struct { ID string Bidder *User Amount float64 Timestamp time.Time } func NewBid(id string, bidder *User, amount float64) *Bid { return &Bid{ ID: id, Bidder: bidder, Amount: amount, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/onlineauctionsystem/main.go ================================================ package onlineauctionsystem import ( "fmt" "time" ) func Run() { auctionSystem := GetInstance() // Register users user1 := NewUser("1", "John Doe", "john@example.com") user2 := NewUser("2", "Jane Smith", "jane@example.com") auctionSystem.RegisterUser(user1) auctionSystem.RegisterUser(user2) // Create auction listings listing1 := NewAuctionListing("1", "Item 1", "Description 1", 100.0, 60*time.Second, user1) listing2 := NewAuctionListing("2", "Item 2", "Description 2", 50.0, 120*time.Second, user2) auctionSystem.CreateAuctionListing(listing1) auctionSystem.CreateAuctionListing(listing2) // Search auction listings searchResults := auctionSystem.SearchAuctionListings("Item") fmt.Println("Search Results:") for _, listing := range searchResults { fmt.Println(listing.ItemName) } // Place bids bid1 := NewBid("1", user2, 150.0) bid2 := NewBid("2", user1, 200.0) auctionSystem.PlaceBid(listing1.ID, bid1) auctionSystem.PlaceBid(listing1.ID, bid2) // Wait for a while to see the auction close time.Sleep(65 * time.Second) fmt.Printf("Auction 1 status: %v\n", listing1.Status) } ================================================ FILE: solutions/golang/onlineauctionsystem/user.go ================================================ package onlineauctionsystem type User struct { ID string Username string Email string } func NewUser(id, username, email string) *User { return &User{ ID: id, Username: username, Email: email, } } ================================================ FILE: solutions/golang/onlineshoppingservice/README.md ================================================ # Designing an Online Shopping System Like Amazon ## Requirements 1. The online shopping service should allow users to browse products, add them to the shopping cart, and place orders. 2. The system should support multiple product categories and provide search functionality. 3. Users should be able to manage their profiles, view order history, and track order status. 4. The system should handle inventory management and update product availability accordingly. 5. The system should support multiple payment methods and ensure secure transactions. 6. The system should handle concurrent user requests and ensure data consistency. 7. The system should be scalable to handle a large number of products and users. 8. The system should provide a user-friendly interface for a seamless shopping experience. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online shopping service, with properties such as ID, name, email, password, and a list of orders. 2. The **Product** class represents a product available for purchase, with properties like ID, name, description, price, and quantity. It provides methods to update the quantity and check product availability. 3. The **Order** class represents an order placed by a user, containing properties such as ID, user, order items, total amount, and order status. It calculates the total amount based on the order items. 4. The **OrderItem** class represents an item within an order, consisting of the product and the quantity ordered. 5. The **OrderStatus** enum represents the different statuses an order can have, such as pending, processing, shipped, delivered, or cancelled. 6. The **ShoppingCart** class represents the user's shopping cart, allowing them to add, remove, and update item quantities. It maintains a map of product IDs and order items. 7. The **Payment** interface defines the contract for processing payments, with a concrete implementation CreditCardPayment. 8. The **OnlineShoppingService** class is the central component of the online shopping service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register users, add products, search products, place orders, and retrieve order information. It handles concurrent access to shared resources using synchronization. 9. The **OnlineShoppingServiceDemo** class demonstrates the usage of the online shopping service by registering users, adding products, searching for products, placing orders, and viewing order history. ================================================ FILE: solutions/golang/onlineshoppingservice/credit_card_payment.go ================================================ package onlineshopping type CreditCardPayment struct{} func (c *CreditCardPayment) ProcessPayment(amount float64) bool { return true } ================================================ FILE: solutions/golang/onlineshoppingservice/online_shopping_service.go ================================================ package onlineshopping import ( "errors" "fmt" "strings" ) type OnlineShoppingService struct { Users map[string]*User Products map[string]*Product Orders map[string]*Order } var instance *OnlineShoppingService func GetInstance() *OnlineShoppingService { if instance == nil { instance = &OnlineShoppingService{ Users: make(map[string]*User), Products: make(map[string]*Product), Orders: make(map[string]*Order), } } return instance } func (s *OnlineShoppingService) RegisterUser(user *User) { s.Users[user.ID] = user } func (s *OnlineShoppingService) AddProduct(product *Product) { s.Products[product.ID] = product } func (s *OnlineShoppingService) SearchProducts(keyword string) []*Product { var results []*Product for _, product := range s.Products { if strings.Contains(strings.ToLower(product.Name), strings.ToLower(keyword)) { results = append(results, product) } } return results } func (s *OnlineShoppingService) PlaceOrder(user *User, cart *ShoppingCart, paymentMethod Payment) (*Order, error) { var orderItems []OrderItem for _, item := range cart.GetItems() { product := item.Product quantity := item.Quantity if product.IsAvailable(quantity) { product.UpdateQuantity(-quantity) orderItems = append(orderItems, item) } } if len(orderItems) == 0 { return nil, errors.New("no available products in the cart") } order := NewOrder(fmt.Sprintf("ORDER-%s", user.ID), user, orderItems) s.Orders[order.ID] = order user.AddOrder(*order) cart.Clear() if paymentMethod.ProcessPayment(order.TotalAmount) { order.SetStatus(Processing) } else { order.SetStatus(Cancelled) for _, item := range orderItems { item.Product.UpdateQuantity(item.Quantity) } } return order, nil } ================================================ FILE: solutions/golang/onlineshoppingservice/online_shopping_service_demo.go ================================================ package onlineshopping import ( "fmt" ) func Run() { shoppingService := GetInstance() user1 := NewUser("U001", "John Doe", "john@example.com", "password123") user2 := NewUser("U002", "Jane Smith", "jane@example.com", "password456") shoppingService.RegisterUser(user1) shoppingService.RegisterUser(user2) product1 := NewProduct("P001", "Smartphone", "High-end smartphone", 999.99, 10) product2 := NewProduct("P002", "Laptop", "Powerful gaming laptop", 1999.99, 5) shoppingService.AddProduct(product1) shoppingService.AddProduct(product2) cart1 := NewShoppingCart() cart1.AddItem(product1, 2) cart1.AddItem(product2, 1) payment1 := &CreditCardPayment{} order1, err := shoppingService.PlaceOrder(user1, cart1, payment1) if err == nil { fmt.Println("Order placed:", order1.ID) } else { fmt.Println("Failed to place order:", err) } searchResults := shoppingService.SearchProducts("laptop") fmt.Println("Search Results:") for _, product := range searchResults { fmt.Println(product.Name) } cart2 := NewShoppingCart() cart2.AddItem(searchResults[0], 1) payment2 := &CreditCardPayment{} order2, err := shoppingService.PlaceOrder(user2, cart2, payment2) if err == nil { fmt.Println("Order placed:", order2.ID) } else { fmt.Println("Failed to place order:", err) } fmt.Println("User 1 Order History:") for _, order := range user1.Orders { fmt.Printf("Order ID: %s, Total Amount: $%.2f, Status: %v\n", order.ID, order.TotalAmount, order.Status) } } ================================================ FILE: solutions/golang/onlineshoppingservice/order.go ================================================ package onlineshopping type Order struct { ID string User *User Items []OrderItem TotalAmount float64 Status OrderStatus } func NewOrder(id string, user *User, items []OrderItem) *Order { order := &Order{ ID: id, User: user, Items: items, Status: Pending, } order.TotalAmount = order.calculateTotalAmount() return order } func (o *Order) calculateTotalAmount() float64 { total := 0.0 for _, item := range o.Items { total += item.Product.Price * float64(item.Quantity) } return total } func (o *Order) SetStatus(status OrderStatus) { o.Status = status } ================================================ FILE: solutions/golang/onlineshoppingservice/order_item.go ================================================ package onlineshopping type OrderItem struct { Product *Product Quantity int } func NewOrderItem(product *Product, quantity int) OrderItem { return OrderItem{Product: product, Quantity: quantity} } ================================================ FILE: solutions/golang/onlineshoppingservice/order_status.go ================================================ package onlineshopping type OrderStatus int const ( Pending OrderStatus = iota Processing Shipped Delivered Cancelled ) ================================================ FILE: solutions/golang/onlineshoppingservice/payment.go ================================================ package onlineshopping type Payment interface { ProcessPayment(amount float64) bool } ================================================ FILE: solutions/golang/onlineshoppingservice/product.go ================================================ package onlineshopping type Product struct { ID string Name string Description string Price float64 Quantity int } func NewProduct(id, name, description string, price float64, quantity int) *Product { return &Product{ ID: id, Name: name, Description: description, Price: price, Quantity: quantity, } } func (p *Product) UpdateQuantity(quantity int) { p.Quantity += quantity } func (p *Product) IsAvailable(quantity int) bool { return p.Quantity >= quantity } ================================================ FILE: solutions/golang/onlineshoppingservice/shopping_cart.go ================================================ package onlineshopping type ShoppingCart struct { items map[string]OrderItem } func NewShoppingCart() *ShoppingCart { return &ShoppingCart{items: make(map[string]OrderItem)} } func (c *ShoppingCart) AddItem(product *Product, quantity int) { item := c.items[product.ID] item.Quantity += quantity c.items[product.ID] = OrderItem{Product: product, Quantity: item.Quantity} } func (c *ShoppingCart) RemoveItem(productId string) { delete(c.items, productId) } func (c *ShoppingCart) GetItems() []OrderItem { items := []OrderItem{} for _, item := range c.items { items = append(items, item) } return items } func (c *ShoppingCart) Clear() { c.items = make(map[string]OrderItem) } ================================================ FILE: solutions/golang/onlineshoppingservice/user.go ================================================ package onlineshopping type User struct { ID string Name string Email string Password string Orders []Order } func NewUser(id, name, email, password string) *User { return &User{ ID: id, Name: name, Email: email, Password: password, Orders: []Order{}, } } func (u *User) AddOrder(order Order) { u.Orders = append(u.Orders, order) } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/README.md ================================================ # Designing an Online Stock Brokerage System ## Requirements 1. The online stock brokerage system should allow users to create and manage their trading accounts. 2. Users should be able to buy and sell stocks, as well as view their portfolio and transaction history. 3. The system should provide real-time stock quotes and market data to users. 4. The system should handle order placement, execution, and settlement processes. 5. The system should enforce various business rules and validations, such as checking account balances and stock availability. 6. The system should handle concurrent user requests and ensure data consistency and integrity. 7. The system should be scalable and able to handle a large number of users and transactions. 8. The system should be secure and protect sensitive user information. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the stock brokerage system, with properties such as user ID, name, and email. 2. The **Account** class represents a user's trading account, with properties like account ID, associated user, and balance. It provides methods for depositing and withdrawing funds. 3. The **Stock** class represents a stock that can be traded, with properties such as symbol, name, and price. It provides a method for updating the stock price. 4. The **Order** class is an abstract base class representing an order placed by a user. It contains common properties such as order ID, associated account, stock, quantity, price, and order status. The execute() method is declared as abstract, to be implemented by concrete order classes. 5. The **BuyOrder** and **SellOrder** classes are concrete implementations of the Order class, representing buy and sell orders respectively. They provide the implementation for the execute() method specific to each order type. 6. The **OrderStatus** enum represents the possible statuses of an order, such as PENDING, EXECUTED, or REJECTED. 7. The **Portfolio** class represents a user's portfolio, which holds the stocks owned by the user. It provides methods for adding and removing stocks from the portfolio. 8. The **StockBroker** class is the central component of the stock brokerage system. It follows the Singleton pattern to ensure a single instance of the stock broker. It manages user accounts, stocks, and order processing. It provides methods for creating accounts, adding stocks, placing orders, and processing orders. 9. The **InsufficientFundsException** and **InsufficientStockException** classes are custom exceptions used to handle insufficient funds and insufficient stock scenarios respectively. 10. The **StockBrokerageSystem** class serves as the entry point of the application and demonstrates the usage of the stock brokerage system. ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/account.go ================================================ package onlinestockbrokeragesystem import "sync" type Account struct { AccountID string User *User balance float64 Portfolio *Portfolio mu sync.RWMutex } func NewAccount(accountID string, user *User, initialBalance float64) *Account { account := &Account{ AccountID: accountID, User: user, balance: initialBalance, } account.Portfolio = NewPortfolio(account) return account } func (a *Account) Deposit(amount float64) { a.mu.Lock() defer a.mu.Unlock() a.balance += amount } func (a *Account) Withdraw(amount float64) error { a.mu.Lock() defer a.mu.Unlock() if a.balance < amount { return NewInsufficientFundsError("insufficient funds in account") } a.balance -= amount return nil } func (a *Account) GetBalance() float64 { a.mu.RLock() defer a.mu.RUnlock() return a.balance } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/buy_order.go ================================================ package onlinestockbrokeragesystem type BuyOrder struct { BaseOrder } func NewBuyOrder(orderID string, account *Account, stock *Stock, quantity int, price float64) *BuyOrder { return &BuyOrder{ BaseOrder: BaseOrder{ OrderID: orderID, Account: account, Stock: stock, Quantity: quantity, Price: price, Status: OrderStatusPending, }, } } func (o *BuyOrder) Execute() error { totalCost := float64(o.Quantity) * o.Price if err := o.Account.Withdraw(totalCost); err != nil { o.Status = OrderStatusRejected return err } o.Account.Portfolio.AddStock(o.Stock, o.Quantity) o.Status = OrderStatusExecuted return nil } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/exceptions.go ================================================ package onlinestockbrokeragesystem type InsufficientFundsError struct { message string } func NewInsufficientFundsError(message string) *InsufficientFundsError { return &InsufficientFundsError{message: message} } func (e *InsufficientFundsError) Error() string { return e.message } type InsufficientStockError struct { message string } func NewInsufficientStockError(message string) *InsufficientStockError { return &InsufficientStockError{message: message} } func (e *InsufficientStockError) Error() string { return e.message } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/order.go ================================================ package onlinestockbrokeragesystem type Order interface { Execute() error GetStatus() OrderStatus SetStatus(status OrderStatus) } type BaseOrder struct { OrderID string Account *Account Stock *Stock Quantity int Price float64 Status OrderStatus } func (o *BaseOrder) GetStatus() OrderStatus { return o.Status } func (o *BaseOrder) SetStatus(status OrderStatus) { o.Status = status } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/portfolio.go ================================================ package onlinestockbrokeragesystem import "sync" type Portfolio struct { account *Account holdings map[string]int mu sync.RWMutex } func NewPortfolio(account *Account) *Portfolio { return &Portfolio{ account: account, holdings: make(map[string]int), } } func (p *Portfolio) AddStock(stock *Stock, quantity int) { p.mu.Lock() defer p.mu.Unlock() p.holdings[stock.Symbol] += quantity } func (p *Portfolio) RemoveStock(stock *Stock, quantity int) error { p.mu.Lock() defer p.mu.Unlock() currentQuantity, exists := p.holdings[stock.Symbol] if !exists { return NewInsufficientStockError("stock not found in portfolio") } if currentQuantity < quantity { return NewInsufficientStockError("insufficient stock quantity in portfolio") } p.holdings[stock.Symbol] -= quantity if p.holdings[stock.Symbol] == 0 { delete(p.holdings, stock.Symbol) } return nil } func (p *Portfolio) GetHoldings() map[string]int { p.mu.RLock() defer p.mu.RUnlock() holdings := make(map[string]int) for symbol, quantity := range p.holdings { holdings[symbol] = quantity } return holdings } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/sell_order.go ================================================ package onlinestockbrokeragesystem type SellOrder struct { BaseOrder } func NewSellOrder(orderID string, account *Account, stock *Stock, quantity int, price float64) *SellOrder { return &SellOrder{ BaseOrder: BaseOrder{ OrderID: orderID, Account: account, Stock: stock, Quantity: quantity, Price: price, Status: OrderStatusPending, }, } } func (o *SellOrder) Execute() error { if err := o.Account.Portfolio.RemoveStock(o.Stock, o.Quantity); err != nil { o.Status = OrderStatusRejected return err } totalProceeds := float64(o.Quantity) * o.Price o.Account.Deposit(totalProceeds) o.Status = OrderStatusExecuted return nil } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/stock.go ================================================ package onlinestockbrokeragesystem import "sync" type Stock struct { Symbol string Name string price float64 mu sync.RWMutex } func NewStock(symbol, name string, price float64) *Stock { return &Stock{ Symbol: symbol, Name: name, price: price, } } func (s *Stock) UpdatePrice(newPrice float64) { s.mu.Lock() defer s.mu.Unlock() s.price = newPrice } func (s *Stock) GetPrice() float64 { s.mu.RLock() defer s.mu.RUnlock() return s.price } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/stock_broker.go ================================================ package onlinestockbrokeragesystem import ( "fmt" "sync" "sync/atomic" ) type StockBroker struct { accounts map[string]*Account stocks map[string]*Stock orderQueue chan Order accountIDCount int64 mu sync.RWMutex } var ( instance *StockBroker once sync.Once ) func GetStockBroker() *StockBroker { once.Do(func() { instance = &StockBroker{ accounts: make(map[string]*Account), stocks: make(map[string]*Stock), orderQueue: make(chan Order, 100), // Buffered channel for orders } go instance.processOrders() // Start order processing goroutine }) return instance } func (sb *StockBroker) CreateAccount(user *User, initialBalance float64) { sb.mu.Lock() defer sb.mu.Unlock() accountID := sb.generateAccountID() account := NewAccount(accountID, user, initialBalance) sb.accounts[accountID] = account } func (sb *StockBroker) GetAccount(accountID string) *Account { sb.mu.RLock() defer sb.mu.RUnlock() return sb.accounts[accountID] } func (sb *StockBroker) AddStock(stock *Stock) { sb.mu.Lock() defer sb.mu.Unlock() sb.stocks[stock.Symbol] = stock } func (sb *StockBroker) GetStock(symbol string) *Stock { sb.mu.RLock() defer sb.mu.RUnlock() return sb.stocks[symbol] } func (sb *StockBroker) PlaceOrder(order Order) { sb.orderQueue <- order } func (sb *StockBroker) processOrders() { for order := range sb.orderQueue { if err := order.Execute(); err != nil { fmt.Printf("Order failed: %v\n", err) } } } func (sb *StockBroker) generateAccountID() string { id := atomic.AddInt64(&sb.accountIDCount, 1) return fmt.Sprintf("A%03d", id) } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/stock_broker_demo.go ================================================ package onlinestockbrokeragesystem import "fmt" func Run() { broker := GetStockBroker() // Create user and account user := NewUser("U001", "John Doe", "john@example.com") broker.CreateAccount(user, 10000.0) account := broker.GetAccount("A001") // Add stocks apple := NewStock("AAPL", "Apple Inc.", 150.0) google := NewStock("GOOGL", "Alphabet Inc.", 2000.0) broker.AddStock(apple) broker.AddStock(google) // Place buy orders buyOrder1 := NewBuyOrder("O001", account, apple, 10, 150.0) buyOrder2 := NewBuyOrder("O002", account, google, 5, 2000.0) broker.PlaceOrder(buyOrder1) broker.PlaceOrder(buyOrder2) // Give some time for orders to process // In a real system, you'd use proper synchronization fmt.Println("Processing buy orders...") // Place sell order sellOrder := NewSellOrder("O003", account, apple, 5, 160.0) broker.PlaceOrder(sellOrder) fmt.Println("Processing sell order...") // Print account details fmt.Printf("Account Balance: $%.2f\n", account.GetBalance()) fmt.Println("Portfolio Holdings:") for symbol, quantity := range account.Portfolio.GetHoldings() { fmt.Printf("%s: %d shares\n", symbol, quantity) } } ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/types.go ================================================ package onlinestockbrokeragesystem type OrderStatus int const ( OrderStatusPending OrderStatus = iota OrderStatusExecuted OrderStatusRejected ) ================================================ FILE: solutions/golang/onlinestockbrokeragesystem/user.go ================================================ package onlinestockbrokeragesystem type User struct { UserID string Name string Email string } func NewUser(userID, name, email string) *User { return &User{ UserID: userID, Name: name, Email: email, } } ================================================ FILE: solutions/golang/parkinglot/README.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot should have multiple levels, each level with a certain number of parking spots. 2. The parking lot should support different types of vehicles, such as cars, motorcycles, and trucks. 3. Each parking spot should be able to accommodate a specific type of vehicle. 4. The system should assign a parking spot to a vehicle upon entry and release it when the vehicle exits. 5. The system should track the availability of parking spots and provide real-time information to customers. 6. The system should handle multiple entry and exit points and support concurrent access. ## Classes, Interfaces and Enumerations 1. The **ParkingLot** class follows the Singleton pattern to ensure only one instance of the parking lot exists. It maintains a list of levels and provides methods to park and unpark vehicles. 2. The **Level** class represents a level in the parking lot and contains a list of parking spots. It handles parking and unparking of vehicles within the level. 3. The **ParkingSpot** class represents an individual parking spot and tracks the availability and the parked vehicle. 4. The **Vehicle** class is an abstract base class for different types of vehicles. It is extended by Car, Motorcycle, and Truck classes. 5. The **VehicleType** enum defines the different types of vehicles supported by the parking lot. 6. Multi-threading is achieved through the use of synchronized keyword on critical sections to ensure thread safety. 7. The **Main** class demonstrates the usage of the parking lot system. ## Design Patterns Used: 1. Singleton Pattern: Ensures only one instance of the ParkingLot class. 2. Factory Pattern (optional extension): Could be used for creating vehicles based on input. 3. Observer Pattern (optional extension): Could notify customers about available spots. ================================================ FILE: solutions/golang/parkinglot/car.go ================================================ package parkinglot func NewCar(licensePlate string) Vehicle { return &BaseVehicle{licensePlate: licensePlate, vehicleType: CAR} } ================================================ FILE: solutions/golang/parkinglot/level.go ================================================ package parkinglot type Level struct { floor int parkingSpots []*ParkingSpot } func NewLevel(floor int, numSpots int) *Level { level := &Level{floor: floor} bikeSpots := int(float64(numSpots) * 0.50) carSpots := int(float64(numSpots) * 0.40) for i := 1; i <= bikeSpots; i++ { level.parkingSpots = append(level.parkingSpots, NewParkingSpot(i, MOTORCYCLE)) } for i := bikeSpots + 1; i <= bikeSpots+carSpots; i++ { level.parkingSpots = append(level.parkingSpots, NewParkingSpot(i, CAR)) } for i := bikeSpots + carSpots + 1; i <= numSpots; i++ { level.parkingSpots = append(level.parkingSpots, NewParkingSpot(i, TRUCK)) } return level } func (l *Level) ParkVehicle(vehicle Vehicle) bool { for _, spot := range l.parkingSpots { if spot.IsAvailable() && spot.GetVehicleType() == vehicle.GetType() { spot.ParkVehicle(vehicle) return true } } return false } func (l *Level) UnparkVehicle(vehicle Vehicle) bool { for _, spot := range l.parkingSpots { if !spot.IsAvailable() && spot.GetParkedVehicle() == vehicle { spot.UnparkVehicle() return true } } return false } func (l *Level) DisplayAvailability() { for _, spot := range l.parkingSpots { status := "Available" if !spot.IsAvailable() { status = "Occupied" } println("Level:", l.floor, "Spot:", spot.GetSpotNumber(), "Status:", status, "Type:", spot.GetVehicleType()) } } ================================================ FILE: solutions/golang/parkinglot/motorcycle.go ================================================ package parkinglot func NewMotorcycle(licensePlate string) Vehicle { return &BaseVehicle{licensePlate: licensePlate, vehicleType: MOTORCYCLE} } ================================================ FILE: solutions/golang/parkinglot/parking_lot.go ================================================ package parkinglot type ParkingLot struct { levels []*Level } var instance *ParkingLot func GetParkingLotInstance() *ParkingLot { if instance == nil { instance = &ParkingLot{levels: []*Level{}} } return instance } func (p *ParkingLot) AddLevel(level *Level) { p.levels = append(p.levels, level) } func (p *ParkingLot) ParkVehicle(vehicle Vehicle) bool { for _, level := range p.levels { if level.ParkVehicle(vehicle) { return true } } return false } func (p *ParkingLot) UnparkVehicle(vehicle Vehicle) bool { for _, level := range p.levels { if level.UnparkVehicle(vehicle) { return true } } return false } func (p *ParkingLot) DisplayAvailability() { for _, level := range p.levels { level.DisplayAvailability() } } ================================================ FILE: solutions/golang/parkinglot/parking_lot_demo.go ================================================ package parkinglot func Run() { parkingLot := GetParkingLotInstance() parkingLot.AddLevel(NewLevel(1, 100)) parkingLot.AddLevel(NewLevel(2, 80)) car := NewCar("ABC123") truck := NewTruck("XYZ789") motorcycle := NewMotorcycle("M1234") parkingLot.ParkVehicle(car) parkingLot.ParkVehicle(truck) parkingLot.ParkVehicle(motorcycle) parkingLot.DisplayAvailability() parkingLot.UnparkVehicle(motorcycle) parkingLot.DisplayAvailability() } ================================================ FILE: solutions/golang/parkinglot/parking_spot.go ================================================ package parkinglot type ParkingSpot struct { spotNumber int vehicleType VehicleType parkedVehicle Vehicle } func NewParkingSpot(spotNumber int, vehicleType VehicleType) *ParkingSpot { return &ParkingSpot{spotNumber: spotNumber, vehicleType: vehicleType} } func (ps *ParkingSpot) IsAvailable() bool { return ps.parkedVehicle == nil } func (ps *ParkingSpot) ParkVehicle(vehicle Vehicle) { if ps.IsAvailable() && vehicle.GetType() == ps.vehicleType { ps.parkedVehicle = vehicle } } func (ps *ParkingSpot) UnparkVehicle() { ps.parkedVehicle = nil } func (ps *ParkingSpot) GetSpotNumber() int { return ps.spotNumber } func (ps *ParkingSpot) GetVehicleType() VehicleType { return ps.vehicleType } func (ps *ParkingSpot) GetParkedVehicle() Vehicle { return ps.parkedVehicle } ================================================ FILE: solutions/golang/parkinglot/truck.go ================================================ package parkinglot func NewTruck(licensePlate string) Vehicle { return &BaseVehicle{licensePlate: licensePlate, vehicleType: TRUCK} } ================================================ FILE: solutions/golang/parkinglot/vehicle.go ================================================ package parkinglot type VehicleType int const ( CAR VehicleType = iota MOTORCYCLE TRUCK ) type Vehicle interface { GetLicensePlate() string GetType() VehicleType } type BaseVehicle struct { licensePlate string vehicleType VehicleType } func (v *BaseVehicle) GetLicensePlate() string { return v.licensePlate } func (v *BaseVehicle) GetType() VehicleType { return v.vehicleType } ================================================ FILE: solutions/golang/pubsubsystem/README.md ================================================ # Designing a Pub-Sub System in Java ## Requirements 1. The Pub-Sub system should allow publishers to publish messages to specific topics. 2. Subscribers should be able to subscribe to topics of interest and receive messages published to those topics. 3. The system should support multiple publishers and subscribers. 4. Messages should be delivered to all subscribers of a topic in real-time. 5. The system should handle concurrent access and ensure thread safety. 6. The Pub-Sub system should be scalable and efficient in terms of message delivery. ## Classes, Interfaces and Enumerations 1. The **Message** class represents a message that can be published and received by subscribers. It contains the message content. 2. The **Topic** class represents a topic to which messages can be published. It maintains a set of subscribers and provides methods to add and remove subscribers, as well as publish messages to all subscribers. 3. The **Subscriber** interface defines the contract for subscribers. It declares the onMessage method that is invoked when a subscriber receives a message. 4. The **PrintSubscriber** class is a concrete implementation of the Subscriber interface. It receives messages and prints them to the console. 5. The **Publisher** class represents a publisher that publishes messages to a specific topic. 6. The **PubSubSystem** class is the main class that manages topics, subscribers, and message publishing. It uses a ConcurrentHashMap to store topics and an ExecutorService to handle concurrent message publishing. 7. The **PubSubDemo** class demonstrates the usage of the Pub-Sub system by creating topics, subscribers, and publishers, and publishing messages. ================================================ FILE: solutions/golang/pubsubsystem/message.go ================================================ package pubsubsystem type Message struct { Content string } func NewMessage(content string) *Message { return &Message{Content: content} } ================================================ FILE: solutions/golang/pubsubsystem/print_subscriber.go ================================================ package pubsubsystem import "fmt" type PrintSubscriber struct { Name string } func NewPrintSubscriber(name string) *PrintSubscriber { return &PrintSubscriber{Name: name} } func (ps *PrintSubscriber) OnMessage(message *Message) { fmt.Printf("Subscriber %s received message: %s\n", ps.Name, message.Content) } ================================================ FILE: solutions/golang/pubsubsystem/publisher.go ================================================ package pubsubsystem import "fmt" type Publisher struct { Topics map[*Topic]struct{} } func NewPublisher() *Publisher { return &Publisher{Topics: make(map[*Topic]struct{})} } func (p *Publisher) RegisterTopic(topic *Topic) { p.Topics[topic] = struct{}{} } func (p *Publisher) Publish(topic *Topic, message *Message) { if _, exists := p.Topics[topic]; !exists { fmt.Printf("This publisher can't publish to topic: %s\n", topic.Name) return } topic.Publish(message) } ================================================ FILE: solutions/golang/pubsubsystem/pubsub_system_demo.go ================================================ package pubsubsystem func Run() { // Create topics topic1 := NewTopic("Topic1") topic2 := NewTopic("Topic2") // Create publishers publisher1 := NewPublisher() publisher2 := NewPublisher() // Create subscribers subscriber1 := NewPrintSubscriber("Subscriber1") subscriber2 := NewPrintSubscriber("Subscriber2") subscriber3 := NewPrintSubscriber("Subscriber3") publisher1.RegisterTopic(topic1) publisher2.RegisterTopic(topic2) // Subscribe to topics topic1.AddSubscriber(subscriber1) topic1.AddSubscriber(subscriber2) topic2.AddSubscriber(subscriber2) topic2.AddSubscriber(subscriber3) // Publish messages publisher1.Publish(topic1, NewMessage("Message1 for Topic1")) publisher1.Publish(topic1, NewMessage("Message2 for Topic1")) publisher2.Publish(topic2, NewMessage("Message1 for Topic2")) // Unsubscribe from a topic topic1.RemoveSubscriber(subscriber2) // Publish more messages publisher1.Publish(topic1, NewMessage("Message3 for Topic1")) publisher2.Publish(topic2, NewMessage("Message2 for Topic2")) } ================================================ FILE: solutions/golang/pubsubsystem/subscriber.go ================================================ package pubsubsystem type Subscriber interface { OnMessage(message *Message) } ================================================ FILE: solutions/golang/pubsubsystem/topic.go ================================================ package pubsubsystem import ( "sync" ) type Topic struct { Name string Subscribers map[Subscriber]struct{} mu sync.RWMutex } func NewTopic(name string) *Topic { return &Topic{ Name: name, Subscribers: make(map[Subscriber]struct{}), } } func (t *Topic) AddSubscriber(subscriber Subscriber) { t.mu.Lock() defer t.mu.Unlock() t.Subscribers[subscriber] = struct{}{} } func (t *Topic) RemoveSubscriber(subscriber Subscriber) { t.mu.Lock() defer t.mu.Unlock() delete(t.Subscribers, subscriber) } func (t *Topic) Publish(message *Message) { t.mu.RLock() defer t.mu.RUnlock() for subscriber := range t.Subscribers { subscriber.OnMessage(message) } } ================================================ FILE: solutions/golang/restaurantmanagementsystem/README.md ================================================ # Designing Restaurant Management System ## Requirements 1. The restaurant management system should allow customers to place orders, view the menu, and make reservations. 2. The system should manage the restaurant's inventory, including ingredients and menu items. 3. The system should handle order processing, including order preparation, billing, and payment. 4. The system should support multiple payment methods, such as cash, credit card, and mobile payments. 5. The system should manage staff information, including roles, schedules, and performance tracking. 6. The system should generate reports and analytics for management, such as sales reports and inventory analysis. 7. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **MenuItem** class represents a menu item in the restaurant, with properties such as ID, name, description, price, and availability. 2. The **Order** class represents an order placed by a customer, with properties such as ID, list of menu items, total amount, order status, and timestamp. 3. The **OrderStatus** enum represents the different statuses an order can have, such as pending, preparing, ready, completed, or cancelled. 4. The **Reservation** class represents a reservation made by a customer, with properties such as ID, customer name, contact number, party size, and reservation time. 5. The **Payment** class represents a payment made for an order, with properties such as ID, amount, payment method, and payment status. 6. The **PaymentMethod** enum represents the different payment methods supported by the restaurant, such as cash, credit card, or mobile payment. 7. The **PaymentStatus** enum represents the status of a payment, which can be pending, completed, or failed. 8. The Staff class represents a staff member of the restaurant, with properties such as ID, name, role, and contact number. 9. The **Restaurant** class is the main class that manages the restaurant operations. It follows the Singleton pattern to ensure only one instance of the restaurant exists. 10. The Restaurant class provides methods for managing menu items, placing orders, updating order status, making reservations, processing payments, and managing staff. 11. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as orders and reservations. 12. The notifyKitchen and notifyStaff methods are placeholders for notifying relevant staff about order updates and status changes. 13. The **RestaurantManagementDemo** class demonstrates the usage of the restaurant management system by adding menu items, placing an order, making a reservation, processing a payment, updating order status, adding staff, and retrieving the menu. ================================================ FILE: solutions/golang/restaurantmanagementsystem/menu_item.go ================================================ package restaurantmanagementsystem type MenuItem struct { ID int Name string Description string Price float64 Available bool } func NewMenuItem(id int, name, description string, price float64, available bool) *MenuItem { return &MenuItem{ ID: id, Name: name, Description: description, Price: price, Available: available, } } ================================================ FILE: solutions/golang/restaurantmanagementsystem/order.go ================================================ package restaurantmanagementsystem import ( "time" ) type Order struct { ID int Items []MenuItem TotalAmount float64 Status OrderStatus Timestamp time.Time } func NewOrder(id int, items []MenuItem, totalAmount float64, status OrderStatus) *Order { return &Order{ ID: id, Items: items, TotalAmount: totalAmount, Status: status, Timestamp: time.Now(), } } func (o *Order) SetStatus(status OrderStatus) { o.Status = status } ================================================ FILE: solutions/golang/restaurantmanagementsystem/order_status.go ================================================ package restaurantmanagementsystem type OrderStatus int const ( OrderPending OrderStatus = iota OrderPreparing OrderReady OrderCompleted OrderCancelled ) ================================================ FILE: solutions/golang/restaurantmanagementsystem/payment.go ================================================ package restaurantmanagementsystem type Payment struct { ID int Amount float64 Method PaymentMethod Status PaymentStatus } func NewPayment(id int, amount float64, method PaymentMethod, status PaymentStatus) *Payment { return &Payment{ ID: id, Amount: amount, Method: method, Status: status, } } ================================================ FILE: solutions/golang/restaurantmanagementsystem/payment_method.go ================================================ package restaurantmanagementsystem type PaymentMethod int const ( Cash PaymentMethod = iota CreditCard MobilePayment ) ================================================ FILE: solutions/golang/restaurantmanagementsystem/payment_status.go ================================================ package restaurantmanagementsystem type PaymentStatus int const ( PaymentPending PaymentStatus = iota PaymentCompleted PaymentFailed ) ================================================ FILE: solutions/golang/restaurantmanagementsystem/reservation.go ================================================ package restaurantmanagementsystem import ( "time" ) type Reservation struct { ID int CustomerName string ContactNumber string PartySize int ReservationTime time.Time } func NewReservation(id int, customerName, contactNumber string, partySize int, reservationTime time.Time) *Reservation { return &Reservation{ ID: id, CustomerName: customerName, ContactNumber: contactNumber, PartySize: partySize, ReservationTime: reservationTime, } } ================================================ FILE: solutions/golang/restaurantmanagementsystem/restaurant.go ================================================ package restaurantmanagementsystem import "sync" type Restaurant struct { menu []MenuItem orders map[int]*Order reservations []Reservation payments map[int]*Payment staff []Staff mu sync.Mutex } var restaurantInstance *Restaurant var once sync.Once func GetRestaurantInstance() *Restaurant { once.Do(func() { restaurantInstance = &Restaurant{ menu: []MenuItem{}, orders: make(map[int]*Order), reservations: []Reservation{}, payments: make(map[int]*Payment), staff: []Staff{}, } }) return restaurantInstance } func (r *Restaurant) AddMenuItem(item *MenuItem) { r.mu.Lock() defer r.mu.Unlock() r.menu = append(r.menu, *item) } func (r *Restaurant) RemoveMenuItem(item *MenuItem) { r.mu.Lock() defer r.mu.Unlock() for i, menuItem := range r.menu { if menuItem.ID == item.ID { r.menu = append(r.menu[:i], r.menu[i+1:]...) break } } } func (r *Restaurant) GetMenu() []MenuItem { r.mu.Lock() defer r.mu.Unlock() return r.menu } func (r *Restaurant) PlaceOrder(order *Order) { r.mu.Lock() defer r.mu.Unlock() r.orders[order.ID] = order r.notifyKitchen(order) } func (r *Restaurant) UpdateOrderStatus(orderID int, status OrderStatus) { r.mu.Lock() defer r.mu.Unlock() if order, exists := r.orders[orderID]; exists { order.SetStatus(status) r.notifyStaff(order) } } func (r *Restaurant) MakeReservation(reservation *Reservation) { r.mu.Lock() defer r.mu.Unlock() r.reservations = append(r.reservations, *reservation) } func (r *Restaurant) ProcessPayment(payment *Payment) { r.mu.Lock() defer r.mu.Unlock() r.payments[payment.ID] = payment } func (r *Restaurant) AddStaff(staff *Staff) { r.mu.Lock() defer r.mu.Unlock() r.staff = append(r.staff, *staff) } func (r *Restaurant) notifyKitchen(order *Order) { // Notify kitchen staff to prepare the order } func (r *Restaurant) notifyStaff(order *Order) { // Notify relevant staff about the order status update } ================================================ FILE: solutions/golang/restaurantmanagementsystem/restaurant_management_demo.go ================================================ package restaurantmanagementsystem import ( "fmt" "time" ) func Run() { restaurant := GetRestaurantInstance() // Add menu items restaurant.AddMenuItem(NewMenuItem(1, "Burger", "Delicious burger", 9.99, true)) restaurant.AddMenuItem(NewMenuItem(2, "Pizza", "Cheesy pizza", 12.99, true)) restaurant.AddMenuItem(NewMenuItem(3, "Salad", "Fresh salad", 7.99, true)) // Place an order order := NewOrder(1, []MenuItem{ *NewMenuItem(1, "Burger", "Delicious burger", 9.99, true), *NewMenuItem(3, "Salad", "Fresh salad", 7.99, true), }, 17.98, OrderPending) restaurant.PlaceOrder(order) // Make a reservation reservation := NewReservation(1, "John Doe", "1234567890", 4, time.Now()) restaurant.MakeReservation(reservation) // Process a payment payment := NewPayment(1, 17.98, CreditCard, PaymentPending) restaurant.ProcessPayment(payment) // Update order status restaurant.UpdateOrderStatus(1, OrderPreparing) restaurant.UpdateOrderStatus(1, OrderReady) restaurant.UpdateOrderStatus(1, OrderCompleted) // Add staff restaurant.AddStaff(NewStaff(1, "Alice", "Manager", "9876543210")) restaurant.AddStaff(NewStaff(2, "Bob", "Chef", "5432109876")) // Get menu fmt.Println("Menu:") for _, item := range restaurant.GetMenu() { fmt.Printf("%s - $%.2f\n", item.Name, item.Price) } } ================================================ FILE: solutions/golang/restaurantmanagementsystem/staff.go ================================================ package restaurantmanagementsystem type Staff struct { ID int Name string Role string ContactNumber string } func NewStaff(id int, name, role, contactNumber string) *Staff { return &Staff{ ID: id, Name: name, Role: role, ContactNumber: contactNumber, } } ================================================ FILE: solutions/golang/ridesharingservice/README.md ================================================ # Designing a Ride-Sharing Service Like Uber ## Requirements 1. The ride sharing service should allow passengers to request rides and drivers to accept and fulfill those ride requests. 2. Passengers should be able to specify their pickup location, destination, and desired ride type (e.g., regular, premium). 3. Drivers should be able to see available ride requests and choose to accept or decline them. 4. The system should match ride requests with available drivers based on proximity and other factors. 5. The system should calculate the fare for each ride based on distance, time, and ride type. 6. The system should handle payments and process transactions between passengers and drivers. 7. The system should provide real-time tracking of ongoing rides and notify passengers and drivers about ride status updates. 8. The system should handle concurrent requests and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Passenger** class represents a passenger in the ride sharing service, with properties such as ID, name, contact information, and location. 2. The **Driver** class represents a driver in the ride sharing service, with properties such as ID, name, contact information, license plate, location, and status (available or busy). 3. The **Ride** class represents a ride requested by a passenger and accepted by a driver, with properties such as ID, passenger, driver, source location, destination location, status, and fare. 4. The **Location** class represents a geographical location with latitude and longitude coordinates. 5. The **Payment** class represents a payment made for a ride, with properties such as ID, ride, amount, and payment status. 6. The **RideService** class is the main class that manages the ride sharing service. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The RideService class provides methods for adding passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. 8. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and ConcurrentLinkedQueue) to handle concurrent access to shared data, such as ride requests and driver availability. 9. The notifyDrivers, notifyPassenger, and notifyDriver methods are placeholders for notifying relevant parties about ride status updates. 10. The calculateFare and processPayment methods are placeholders for calculating ride fares and processing payments, respectively. 11. The **RideSharingDemo** class demonstrates the usage of the ride sharing service by creating passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. ================================================ FILE: solutions/golang/ridesharingservice/driver.go ================================================ package ridesharingservice type Driver struct { ID int Name string Contact string LicensePlate string Location *Location Status DriverStatus } ================================================ FILE: solutions/golang/ridesharingservice/driver_status.go ================================================ package ridesharingservice type DriverStatus int const ( Available DriverStatus = iota Busy ) ================================================ FILE: solutions/golang/ridesharingservice/location.go ================================================ package ridesharingservice type Location struct { Latitude float64 Longitude float64 } ================================================ FILE: solutions/golang/ridesharingservice/passenger.go ================================================ package ridesharingservice type Passenger struct { ID int Name string Contact string Location *Location } ================================================ FILE: solutions/golang/ridesharingservice/ride.go ================================================ package ridesharingservice type Ride struct { ID int Passenger *Passenger Driver *Driver Source *Location Destination *Location Status RideStatus Fare float64 } ================================================ FILE: solutions/golang/ridesharingservice/ride_service.go ================================================ package ridesharingservice import ( "fmt" "math/rand" "sync" "time" ) type RideService struct { passengers map[int]*Passenger drivers map[int]*Driver rides map[int]*Ride requestedRides chan *Ride mu sync.Mutex } var instance *RideService var once sync.Once func GetRideService() *RideService { once.Do(func() { instance = &RideService{ passengers: make(map[int]*Passenger), drivers: make(map[int]*Driver), rides: make(map[int]*Ride), requestedRides: make(chan *Ride, 10), } }) return instance } func (rs *RideService) AddPassenger(passenger *Passenger) { rs.mu.Lock() defer rs.mu.Unlock() rs.passengers[passenger.ID] = passenger } func (rs *RideService) AddDriver(driver *Driver) { rs.mu.Lock() defer rs.mu.Unlock() rs.drivers[driver.ID] = driver } func (rs *RideService) RequestRide(passenger *Passenger, source, destination *Location) { ride := &Ride{ ID: rs.generateRideID(), Passenger: passenger, Source: source, Destination: destination, Status: Requested, } rs.requestedRides <- ride rs.notifyDrivers(ride) } func (rs *RideService) AcceptRide(driver *Driver, ride *Ride) { rs.mu.Lock() defer rs.mu.Unlock() if ride.Status == Requested { ride.Driver = driver ride.Status = Accepted driver.Status = Busy rs.notifyPassenger(ride) } } func (rs *RideService) StartRide(ride *Ride) { rs.mu.Lock() defer rs.mu.Unlock() if ride.Status == Accepted { ride.Status = InProgress rs.notifyPassenger(ride) } } func (rs *RideService) CompleteRide(ride *Ride) { rs.mu.Lock() defer rs.mu.Unlock() if ride.Status == InProgress { ride.Status = Completed ride.Driver.Status = Available ride.Fare = rs.calculateFare(ride) rs.notifyPassenger(ride) rs.notifyDriver(ride) } } func (rs *RideService) CancelRide(ride *Ride) { rs.mu.Lock() defer rs.mu.Unlock() if ride.Status == Requested || ride.Status == Accepted { ride.Status = Cancelled if ride.Driver != nil { ride.Driver.Status = Available } rs.notifyPassenger(ride) rs.notifyDriver(ride) } } func (rs *RideService) notifyDrivers(ride *Ride) { for _, driver := range rs.drivers { if driver.Status == Available && rs.calculateDistance(driver.Location, ride.Source) <= 5.0 { fmt.Printf("Notifying driver %s about ride request: %d\n", driver.Name, ride.ID) } } } func (rs *RideService) notifyPassenger(ride *Ride) { message := "" switch ride.Status { case Accepted: message = fmt.Sprintf("Your ride has been accepted by driver: %s", ride.Driver.Name) case InProgress: message = "Your ride is in progress" case Completed: message = fmt.Sprintf("Your ride has been completed. Fare: $%.2f", ride.Fare) case Cancelled: message = "Your ride has been cancelled" } fmt.Printf("Notifying passenger %s: %s\n", ride.Passenger.Name, message) } func (rs *RideService) notifyDriver(ride *Ride) { if ride.Driver != nil { message := "" switch ride.Status { case Completed: message = fmt.Sprintf("Ride completed. Fare: $%.2f", ride.Fare) case Cancelled: message = "Ride cancelled by passenger" } fmt.Printf("Notifying driver %s: %s\n", ride.Driver.Name, message) } } func (rs *RideService) calculateFare(ride *Ride) float64 { baseFare := 2.0 perKmFare := 1.5 perMinuteFare := 0.25 distance := rs.calculateDistance(ride.Source, ride.Destination) duration := rs.calculateDuration(ride.Source, ride.Destination) return baseFare + (distance * perKmFare) + (duration * perMinuteFare) } func (rs *RideService) calculateDistance(source, destination *Location) float64 { return rand.Float64()*20 + 1 } func (rs *RideService) calculateDuration(source, destination *Location) float64 { distance := rs.calculateDistance(source, destination) return (distance / 30) * 60 } func (rs *RideService) generateRideID() int { return int(time.Now().Unix()) } ================================================ FILE: solutions/golang/ridesharingservice/ride_sharing_service_demo.go ================================================ package ridesharingservice import "fmt" func Run() { rideService := GetRideService() // Create passengers passenger1 := &Passenger{ID: 1, Name: "John Doe", Contact: "1234567890", Location: &Location{Latitude: 37.7749, Longitude: -122.4194}} passenger2 := &Passenger{ID: 2, Name: "Jane Smith", Contact: "9876543210", Location: &Location{Latitude: 37.7860, Longitude: -122.4070}} rideService.AddPassenger(passenger1) rideService.AddPassenger(passenger2) // Create drivers driver1 := &Driver{ID: 1, Name: "Alice Johnson", Contact: "4567890123", LicensePlate: "ABC123", Location: &Location{Latitude: 37.7749, Longitude: -122.4194}, Status: Available} driver2 := &Driver{ID: 2, Name: "Bob Williams", Contact: "7890123456", LicensePlate: "XYZ789", Location: &Location{Latitude: 37.7860, Longitude: -122.4070}, Status: Available} rideService.AddDriver(driver1) rideService.AddDriver(driver2) // Passenger 1 requests a ride rideService.RequestRide(passenger1, passenger1.Location, &Location{Latitude: 37.7887, Longitude: -122.4098}) // Driver 1 accepts the ride ride := <-rideService.requestedRides rideService.AcceptRide(driver1, ride) // Start and complete the ride rideService.StartRide(ride) rideService.CompleteRide(ride) // Passenger 2 requests a ride and cancels it rideService.RequestRide(passenger2, passenger2.Location, &Location{Latitude: 37.7749, Longitude: -122.4194}) ride2 := <-rideService.requestedRides rideService.AcceptRide(driver2, ride2) rideService.CancelRide(ride2) fmt.Println("Demo completed") } ================================================ FILE: solutions/golang/ridesharingservice/ride_status.go ================================================ package ridesharingservice type RideStatus int const ( Requested RideStatus = iota Accepted InProgress Completed Cancelled ) ================================================ FILE: solutions/golang/snakeandladdergame/README.md ================================================ # Designing Snake and Ladder Game ## Requirements 1. The game should be played on a board with numbered cells, typically with 100 cells. 2. The board should have a predefined set of snakes and ladders, connecting certain cells. 3. The game should support multiple players, each represented by a unique game piece. 4. Players should take turns rolling a dice to determine the number of cells to move forward. 5. If a player lands on a cell with the head of a snake, they should slide down to the cell with the tail of the snake. 6. If a player lands on a cell with the base of a ladder, they should climb up to the cell at the top of the ladder. 7. The game should continue until one of the players reaches the final cell on the board. 8. The game should handle multiple game sessions concurrently, allowing different groups of players to play independently. ## Classes, Interfaces and Enumerations 1. The **Board** class represents the game board with a fixed size (e.g., 100 cells). It contains the positions of snakes and ladders and provides methods to initialize them and retrieve the new position after encountering a snake or ladder. 2. The **Player** class represents a player in the game, with properties such as name and current position on the board. 3. The **Snake** class represents a snake on the board, with properties for the start and end positions. 4. The **Ladder** class represents a ladder on the board, with properties for the start and end positions. 5. The **Dice** class represents a dice used in the game, with a method to roll the dice and return a random value between 1 and 6. 6. The **SnakeAndLadderGame** class represents a single game session. It initializes the game with a board, a list of players, and a dice. The play method handles the game loop, where players take turns rolling the dice and moving their positions on the board. It checks for snakes and ladders and updates the player's position accordingly. The game continues until a player reaches the final position on the board. 7. The **GameManager** class is a singleton that manages multiple game sessions. It maintains a list of active games and provides a method to start a new game with a list of player names. Each game is started in a separate thread to allow concurrent game sessions. 8. The **SnakeAndLadderDemo** class demonstrates the usage of the game by creating an instance of the GameManager and starting two separate game sessions with different sets of players. ================================================ FILE: solutions/golang/snakeandladdergame/board.go ================================================ package snakeandladdergame type Board struct { Size int Snakes []*Snake Ladders []*Ladder } func NewBoard() *Board { board := &Board{ Size: 100, Snakes: []*Snake{}, Ladders: []*Ladder{}, } board.initializeSnakesAndLadders() return board } func (b *Board) initializeSnakesAndLadders() { b.Snakes = append(b.Snakes, NewSnake(16, 6), NewSnake(48, 26), NewSnake(64, 60), NewSnake(93, 73)) b.Ladders = append(b.Ladders, NewLadder(1, 38), NewLadder(4, 14), NewLadder(9, 31), NewLadder(21, 42), NewLadder(28, 84), NewLadder(51, 67), NewLadder(80, 99)) } func (b *Board) GetNewPosition(position int) int { for _, snake := range b.Snakes { if snake.Start == position { return snake.End } } for _, ladder := range b.Ladders { if ladder.Start == position { return ladder.End } } return position } ================================================ FILE: solutions/golang/snakeandladdergame/dice.go ================================================ package snakeandladdergame import "math/rand" type Dice struct{} func NewDice() *Dice { return &Dice{} } func (d *Dice) Roll() int { return rand.Intn(6) + 1 } ================================================ FILE: solutions/golang/snakeandladdergame/game_manager.go ================================================ package snakeandladdergame import "sync" type GameManager struct { Games []*SnakeAndLadderGame } var instance *GameManager func GetGameManager() *GameManager { if instance == nil { instance = &GameManager{ Games: []*SnakeAndLadderGame{}, } } return instance } func (gm *GameManager) StartNewGame(wg *sync.WaitGroup, playerNames []string) { game := NewSnakeAndLadderGame(playerNames) gm.Games = append(gm.Games, game) wg.Add(1) go game.Play(wg) } ================================================ FILE: solutions/golang/snakeandladdergame/ladder.go ================================================ package snakeandladdergame type Ladder struct { Start int End int } func NewLadder(start, end int) *Ladder { return &Ladder{Start: start, End: end} } ================================================ FILE: solutions/golang/snakeandladdergame/player.go ================================================ package snakeandladdergame type Player struct { Name string Position int } func NewPlayer(name string) *Player { return &Player{Name: name, Position: 0} } ================================================ FILE: solutions/golang/snakeandladdergame/snake.go ================================================ package snakeandladdergame type Snake struct { Start int End int } func NewSnake(start, end int) *Snake { return &Snake{Start: start, End: end} } ================================================ FILE: solutions/golang/snakeandladdergame/snake_and_ladder_demo.go ================================================ package snakeandladdergame import ( "fmt" "sync" ) func Run() { gameManager := GetGameManager() wg := new(sync.WaitGroup) // Start game 1 players1 := []string{"Player 1", "Player 2", "Player 3"} gameManager.StartNewGame(wg, players1) // Start game 2 players2 := []string{"Player 4", "Player 5"} gameManager.StartNewGame(wg, players2) fmt.Println("Games started. Check game output above.") //Wait for all games to finish wg.Wait() } ================================================ FILE: solutions/golang/snakeandladdergame/snake_and_ladder_game.go ================================================ package snakeandladdergame import ( "fmt" "sync" "sync/atomic" "time" ) type SnakeAndLadderGame struct { ID int64 Board *Board Players []*Player Dice *Dice CurrentPlayerIdx int } func NewSnakeAndLadderGame(playerNames []string) *SnakeAndLadderGame { game := &SnakeAndLadderGame{ ID: generateID(), Board: NewBoard(), Dice: NewDice(), Players: []*Player{}, CurrentPlayerIdx: 0, } for _, name := range playerNames { game.Players = append(game.Players, NewPlayer(name)) } return game } func (g *SnakeAndLadderGame) Play(wg *sync.WaitGroup) { for !g.isGameOver() { player := g.Players[g.CurrentPlayerIdx] roll := g.Dice.Roll() newPosition := player.Position + roll if newPosition <= g.Board.Size { player.Position = g.Board.GetNewPosition(newPosition) fmt.Printf("Game: %d :- %s rolled a %d and moved to position %d\n", g.ID, player.Name, roll, player.Position) } if player.Position == g.Board.Size { fmt.Printf("For Game %d :- %s wins!\n", g.ID, player.Name) break } g.CurrentPlayerIdx = (g.CurrentPlayerIdx + 1) % len(g.Players) time.Sleep(10 * time.Millisecond) //To simulate the demo } wg.Done() } func (g *SnakeAndLadderGame) isGameOver() bool { for _, player := range g.Players { if player.Position == g.Board.Size { return true } } return false } var idCounter int64 func generateID() int64 { return atomic.AddInt64(&idCounter, 1) } ================================================ FILE: solutions/golang/socialnetworkingservice/README.md ================================================ # Designing a Social Network Like Facebook ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their personal information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their information, such as profile picture, bio, and interests. - Users should be able to update their profile information. #### Friend Connections: - Users should be able to send friend requests to other users. - Users should be able to accept or decline friend requests. - Users should be able to view their list of friends. #### Posts and Newsfeed: - Users should be able to create posts with text, images, or videos. - Users should be able to view a newsfeed consisting of posts from their friends and their own posts. - The newsfeed should be sorted in reverse chronological order. #### Likes and Comments: - Users should be able to like and comment on posts. - Users should be able to view the list of likes and comments on a post. #### Privacy and Security: - Users should be able to control the visibility of their posts and profile information. - The system should enforce secure access control to ensure data privacy. #### Notifications: - Users should receive notifications for events such as friend requests, likes, comments, and mentions. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the social networking system, containing properties such as ID, name, email, password, profile picture, bio, list of friends, and list of posts. 2. The **Post** class represents a post created by a user, containing properties such as ID, user ID, content, image URLs, video URLs, timestamp, likes, and comments. 3. The **Comment** class represents a comment made by a user on a post, containing properties such as ID, user ID, post ID, content, and timestamp. 4. The **Notification** class represents a notification generated for a user, containing properties such as ID, user ID, notification type, content, and timestamp. 5. The **NotificationType** enum defines the different types of notifications, such as friend request, friend request accepted, like, comment, and mention. 6. The **SocialNetworkingService** class is the main class that manages the social networking system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SocialNetworkingService class provides methods for user registration, login, profile updates, friend requests, post creation, newsfeed generation, likes, comments, and notifications. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SocialNetworkingDemo** class demonstrates the usage of the social networking system by registering users, logging in, sending friend requests, creating posts, liking posts, commenting on posts, and retrieving newsfeed and notifications. ================================================ FILE: solutions/golang/socialnetworkingservice/comment.go ================================================ package socialnetworkingservice import "time" type Comment struct { ID string UserID string PostID string Content string Timestamp time.Time } func NewComment(id, userID, postID, content string) *Comment { return &Comment{ ID: id, UserID: userID, PostID: postID, Content: content, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/socialnetworkingservice/notification.go ================================================ package socialnetworkingservice import "time" type Notification struct { ID string UserID string Type NotificationType Content string Timestamp time.Time } func NewNotification(id, userID string, notifType NotificationType, content string) *Notification { return &Notification{ ID: id, UserID: userID, Type: notifType, Content: content, Timestamp: time.Now(), } } ================================================ FILE: solutions/golang/socialnetworkingservice/post.go ================================================ package socialnetworkingservice import ( "sync" "time" ) type Post struct { ID string UserID string Content string ImageURLs []string VideoURLs []string Timestamp time.Time likes map[string]bool comments []*Comment mu sync.RWMutex } func NewPost(id, userID, content string, imageURLs, videoURLs []string) *Post { return &Post{ ID: id, UserID: userID, Content: content, ImageURLs: imageURLs, VideoURLs: videoURLs, Timestamp: time.Now(), likes: make(map[string]bool), comments: make([]*Comment, 0), } } func (p *Post) AddLike(userID string) bool { p.mu.Lock() defer p.mu.Unlock() if !p.likes[userID] { p.likes[userID] = true return true } return false } func (p *Post) AddComment(comment *Comment) { p.mu.Lock() defer p.mu.Unlock() p.comments = append(p.comments, comment) } func (p *Post) GetLikes() []string { p.mu.RLock() defer p.mu.RUnlock() likes := make([]string, 0, len(p.likes)) for userID := range p.likes { likes = append(likes, userID) } return likes } func (p *Post) GetComments() []*Comment { p.mu.RLock() defer p.mu.RUnlock() comments := make([]*Comment, len(p.comments)) copy(comments, p.comments) return comments } ================================================ FILE: solutions/golang/socialnetworkingservice/social_networking_service.go ================================================ package socialnetworkingservice import ( "fmt" "sort" "sync" "time" ) type SocialNetwork struct { users map[string]*User posts map[string]*Post notifications map[string][]*Notification mu sync.RWMutex } var ( instance *SocialNetwork once sync.Once ) func GetSocialNetwork() *SocialNetwork { once.Do(func() { instance = &SocialNetwork{ users: make(map[string]*User), posts: make(map[string]*Post), notifications: make(map[string][]*Notification), } }) return instance } func (sn *SocialNetwork) RegisterUser(user *User) error { sn.mu.Lock() defer sn.mu.Unlock() if _, exists := sn.users[user.ID]; exists { return fmt.Errorf("user with ID %s already exists", user.ID) } sn.users[user.ID] = user return nil } func (sn *SocialNetwork) LoginUser(email, password string) (*User, error) { sn.mu.RLock() defer sn.mu.RUnlock() for _, user := range sn.users { if user.Email == email && user.Password == password { return user, nil } } return nil, fmt.Errorf("invalid email or password") } func (sn *SocialNetwork) UpdateUserProfile(user *User) { sn.mu.Lock() defer sn.mu.Unlock() sn.users[user.ID] = user } func (sn *SocialNetwork) SendFriendRequest(senderID, receiverID string) error { sn.mu.Lock() defer sn.mu.Unlock() receiver, exists := sn.users[receiverID] if !exists { return fmt.Errorf("receiver not found") } else { fmt.Printf(receiver.ID) } notification := NewNotification( fmt.Sprintf("notif-%d", time.Now().UnixNano()), receiverID, NotificationTypeFriendRequest, fmt.Sprintf("Friend request from %s", senderID), ) sn.addNotification(receiverID, notification) return nil } func (sn *SocialNetwork) AcceptFriendRequest(userID, friendID string) error { sn.mu.Lock() defer sn.mu.Unlock() user, exists1 := sn.users[userID] friend, exists2 := sn.users[friendID] if !exists1 || !exists2 { return fmt.Errorf("user or friend not found") } user.AddFriend(friendID) friend.AddFriend(userID) notification := NewNotification( fmt.Sprintf("notif-%d", time.Now().UnixNano()), friendID, NotificationTypeFriendRequestAccepted, fmt.Sprintf("Friend request accepted by %s", userID), ) sn.addNotification(friendID, notification) return nil } func (sn *SocialNetwork) CreatePost(post *Post) error { sn.mu.Lock() defer sn.mu.Unlock() user, exists := sn.users[post.UserID] if !exists { return fmt.Errorf("user not found") } sn.posts[post.ID] = post user.AddPost(post) return nil } func (sn *SocialNetwork) GetNewsfeed(userID string) ([]*Post, error) { sn.mu.RLock() defer sn.mu.RUnlock() user, exists := sn.users[userID] if !exists { return nil, fmt.Errorf("user not found") } var newsfeed []*Post // Add user's own posts newsfeed = append(newsfeed, user.GetPosts()...) // Add friends' posts for friendID := range user.friends { if friend, ok := sn.users[friendID]; ok { newsfeed = append(newsfeed, friend.GetPosts()...) } } // Sort by timestamp (newest first) sort.Slice(newsfeed, func(i, j int) bool { return newsfeed[i].Timestamp.After(newsfeed[j].Timestamp) }) return newsfeed, nil } func (sn *SocialNetwork) LikePost(userID, postID string) error { sn.mu.Lock() defer sn.mu.Unlock() post, exists := sn.posts[postID] if !exists { return fmt.Errorf("post not found") } if added := post.AddLike(userID); added { notification := NewNotification( fmt.Sprintf("notif-%d", time.Now().UnixNano()), post.UserID, NotificationTypeLike, fmt.Sprintf("Your post was liked by %s", userID), ) sn.addNotification(post.UserID, notification) } return nil } func (sn *SocialNetwork) CommentOnPost(comment *Comment) error { sn.mu.Lock() defer sn.mu.Unlock() post, exists := sn.posts[comment.PostID] if !exists { return fmt.Errorf("post not found") } post.AddComment(comment) notification := NewNotification( fmt.Sprintf("notif-%d", time.Now().UnixNano()), post.UserID, NotificationTypeComment, fmt.Sprintf("Your post received a comment from %s", comment.UserID), ) sn.addNotification(post.UserID, notification) return nil } func (sn *SocialNetwork) GetNotifications(userID string) ([]*Notification, error) { sn.mu.RLock() defer sn.mu.RUnlock() if _, exists := sn.users[userID]; !exists { return nil, fmt.Errorf("user not found") } return sn.notifications[userID], nil } func (sn *SocialNetwork) addNotification(userID string, notification *Notification) { sn.notifications[userID] = append(sn.notifications[userID], notification) } ================================================ FILE: solutions/golang/socialnetworkingservice/social_networking_service_demo.go ================================================ package socialnetworkingservice import ( "fmt" "log" ) func Run() { socialNetwork := GetSocialNetwork() // Create users user1 := NewUser("1", "John Doe", "john@example.com", "password", "profile1.jpg", "I love coding!") user2 := NewUser("2", "Jane Smith", "jane@example.com", "password", "profile2.jpg", "Exploring the world!") // Register users if err := socialNetwork.RegisterUser(user1); err != nil { log.Printf("Failed to register user1: %v", err) return } if err := socialNetwork.RegisterUser(user2); err != nil { log.Printf("Failed to register user2: %v", err) return } // Login loggedInUser, err := socialNetwork.LoginUser("john@example.com", "password") if err != nil { log.Printf("Login failed: %v", err) return } fmt.Printf("User logged in: %s\n", loggedInUser.Name) // Send friend request if err := socialNetwork.SendFriendRequest(user1.ID, user2.ID); err != nil { log.Printf("Failed to send friend request: %v", err) return } // Accept friend request if err := socialNetwork.AcceptFriendRequest(user2.ID, user1.ID); err != nil { log.Printf("Failed to accept friend request: %v", err) return } // Create posts post1 := NewPost("post1", user1.ID, "My first post!", []string{}, []string{}) post2 := NewPost("post2", user2.ID, "Having a great day!", []string{}, []string{}) if err := socialNetwork.CreatePost(post1); err != nil { log.Printf("Failed to create post1: %v", err) return } if err := socialNetwork.CreatePost(post2); err != nil { log.Printf("Failed to create post2: %v", err) return } // Like and comment if err := socialNetwork.LikePost(user2.ID, post1.ID); err != nil { log.Printf("Failed to like post: %v", err) return } comment := NewComment("comment1", user2.ID, post1.ID, "Great post!") if err := socialNetwork.CommentOnPost(comment); err != nil { log.Printf("Failed to comment on post: %v", err) return } // Get newsfeed newsfeed, err := socialNetwork.GetNewsfeed(user1.ID) if err != nil { log.Printf("Failed to get newsfeed: %v", err) return } fmt.Println("\nNewsfeed:") for _, post := range newsfeed { fmt.Printf("Post: %s\n", post.Content) fmt.Printf("Likes: %d\n", len(post.GetLikes())) fmt.Printf("Comments: %d\n\n", len(post.GetComments())) } // Get notifications notifications, err := socialNetwork.GetNotifications(user1.ID) if err != nil { log.Printf("Failed to get notifications: %v", err) return } fmt.Println("Notifications:") for _, notification := range notifications { fmt.Printf("Type: %s\n", notification.Type) fmt.Printf("Content: %s\n\n", notification.Content) } } ================================================ FILE: solutions/golang/socialnetworkingservice/types.go ================================================ package socialnetworkingservice type NotificationType int const ( NotificationTypeFriendRequest NotificationType = iota NotificationTypeFriendRequestAccepted NotificationTypeLike NotificationTypeComment NotificationTypeMention ) func (nt NotificationType) String() string { return [...]string{ "FRIEND_REQUEST", "FRIEND_REQUEST_ACCEPTED", "LIKE", "COMMENT", "MENTION", }[nt] } ================================================ FILE: solutions/golang/socialnetworkingservice/user.go ================================================ package socialnetworkingservice import "sync" type User struct { ID string Name string Email string Password string ProfilePicture string Bio string friends map[string]bool posts []*Post mu sync.RWMutex } func NewUser(id, name, email, password, profilePicture, bio string) *User { return &User{ ID: id, Name: name, Email: email, Password: password, ProfilePicture: profilePicture, Bio: bio, friends: make(map[string]bool), posts: make([]*Post, 0), } } func (u *User) AddFriend(friendID string) { u.mu.Lock() defer u.mu.Unlock() u.friends[friendID] = true } func (u *User) AddPost(post *Post) { u.mu.Lock() defer u.mu.Unlock() u.posts = append(u.posts, post) } func (u *User) GetFriends() []string { u.mu.RLock() defer u.mu.RUnlock() friends := make([]string, 0, len(u.friends)) for friendID := range u.friends { friends = append(friends, friendID) } return friends } func (u *User) GetPosts() []*Post { u.mu.RLock() defer u.mu.RUnlock() posts := make([]*Post, len(u.posts)) copy(posts, u.posts) return posts } ================================================ FILE: solutions/golang/splitwise/README.md ================================================ # Designing Splitwise ## Requirements 1. The system should allow users to create accounts and manage their profile information. 2. Users should be able to create groups and add other users to the groups. 3. Users should be able to add expenses within a group, specifying the amount, description, and participants. 4. The system should automatically split the expenses among the participants based on their share. 5. Users should be able to view their individual balances with other users and settle up the balances. 6. The system should support different split methods, such as equal split, percentage split, and exact amounts. 7. Users should be able to view their transaction history and group expenses. 8. The system should handle concurrent transactions and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the Splitwise system, with properties such as ID, name, email, and a map to store balances with other users. 2. The **Group** class represents a group in Splitwise, containing a list of member users and a list of expenses. 3. The **Expense** class represents an expense within a group, with properties such as ID, amount, description, the user who paid, and a list of splits. 4. The **Split** class is an abstract class representing the split of an expense. It is extended by EqualSplit, PercentSplit, and ExactSplit classes to handle different split methods. 5. The **Transaction** class represents a transaction between two users, with properties such as ID, sender, receiver, and amount. 6. The **SplitwiseService** class is the main class that manages the Splitwise system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SplitwiseService class provides methods for adding users, groups, and expenses, splitting expenses, updating balances, settling balances, and creating transactions. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SplitwiseDemo** class demonstrates the usage of the Splitwise system by creating users, a group, adding an expense, settling balances, and printing user balances. ================================================ FILE: solutions/golang/splitwise/equal_split.go ================================================ package splitwise type EqualSplit struct { User *User Amount float64 } func NewEqualSplit(user *User) *EqualSplit { return &EqualSplit{User: user} } func (e *EqualSplit) GetAmount() float64 { return e.Amount } func (e *EqualSplit) SetAmount(amount float64) { e.Amount = amount } func (e *EqualSplit) GetUser() *User { return e.User } ================================================ FILE: solutions/golang/splitwise/expense.go ================================================ package splitwise type Expense struct { ID string Amount float64 Description string PaidBy *User Splits []Split } func NewExpense(id string, amount float64, description string, paidBy *User) *Expense { return &Expense{ ID: id, Amount: amount, Description: description, PaidBy: paidBy, Splits: []Split{}, } } func (e *Expense) AddSplit(split Split) { e.Splits = append(e.Splits, split) } ================================================ FILE: solutions/golang/splitwise/group.go ================================================ package splitwise type Group struct { ID string Name string Members []*User Expenses []*Expense } func NewGroup(id, name string) *Group { return &Group{ ID: id, Name: name, Members: []*User{}, Expenses: []*Expense{}, } } func (g *Group) AddMember(user *User) { g.Members = append(g.Members, user) } func (g *Group) AddExpense(expense *Expense) { g.Expenses = append(g.Expenses, expense) } ================================================ FILE: solutions/golang/splitwise/percent_split.go ================================================ package splitwise type PercentSplit struct { User *User Amount float64 Percent float64 } func NewPercentSplit(user *User, percent float64) *PercentSplit { return &PercentSplit{User: user, Percent: percent} } func (p *PercentSplit) GetAmount() float64 { return p.Amount } func (p *PercentSplit) SetAmount(amount float64) { p.Amount = amount } func (p *PercentSplit) GetUser() *User { return p.User } ================================================ FILE: solutions/golang/splitwise/split.go ================================================ package splitwise type Split interface { GetAmount() float64 SetAmount(amount float64) GetUser() *User } ================================================ FILE: solutions/golang/splitwise/splitwise_demo.go ================================================ package splitwise import ( "fmt" ) func Run() { service := GetSplitwiseService() // Create users user1 := NewUser("1", "Alice", "alice@example.com") user2 := NewUser("2", "Bob", "bob@example.com") user3 := NewUser("3", "Charlie", "charlie@example.com") service.AddUser(user1) service.AddUser(user2) service.AddUser(user3) // Create group and add users group := NewGroup("1", "Apartment") group.AddMember(user1) group.AddMember(user2) group.AddMember(user3) service.AddGroup(group) // Add expense expense := NewExpense("1", 300, "Rent", user1) expense.AddSplit(NewEqualSplit(user1)) expense.AddSplit(NewEqualSplit(user2)) expense.AddSplit(NewPercentSplit(user3, 20)) service.AddExpense(group.ID, expense) // Settle balances service.SettleBalance(user1.ID, user2.ID) service.SettleBalance(user1.ID, user3.ID) // Print balances for _, user := range []*User{user1, user2, user3} { fmt.Printf("User: %s\n", user.Name) for key, balance := range user.Balances { fmt.Printf(" Balance with %s: %.2f\n", key, balance) } } } ================================================ FILE: solutions/golang/splitwise/splitwise_service.go ================================================ package splitwise import ( "fmt" "sync" ) type SplitwiseService struct { users map[string]*User groups map[string]*Group counter int mu sync.Mutex } var instance *SplitwiseService var once sync.Once func GetSplitwiseService() *SplitwiseService { once.Do(func() { instance = &SplitwiseService{ users: make(map[string]*User), groups: make(map[string]*Group), } }) return instance } func (s *SplitwiseService) AddUser(user *User) { s.users[user.ID] = user } func (s *SplitwiseService) AddGroup(group *Group) { s.groups[group.ID] = group } func (s *SplitwiseService) AddExpense(groupID string, expense *Expense) { group, exists := s.groups[groupID] if !exists { return } group.AddExpense(expense) s.splitExpense(expense) s.updateBalances(expense) } func (s *SplitwiseService) splitExpense(expense *Expense) { totalAmount := expense.Amount totalSplits := len(expense.Splits) for _, split := range expense.Splits { switch v := split.(type) { case *EqualSplit: v.SetAmount(totalAmount / float64(totalSplits)) case *PercentSplit: v.SetAmount(totalAmount * v.Percent / 100.0) } } } func (s *SplitwiseService) updateBalances(expense *Expense) { for _, split := range expense.Splits { paidBy := expense.PaidBy user := split.GetUser() amount := split.GetAmount() if paidBy != user { s.updateBalance(paidBy, user, amount) s.updateBalance(user, paidBy, -amount) } } } func (s *SplitwiseService) updateBalance(user1, user2 *User, amount float64) { key := user1.ID + ":" + user2.ID user1.Balances[key] += amount } func (s *SplitwiseService) SettleBalance(userID1, userID2 string) { user1, exists1 := s.users[userID1] user2, exists2 := s.users[userID2] if !exists1 || !exists2 { return } key := user1.ID + ":" + user2.ID balance := user1.Balances[key] if balance > 0 { s.createTransaction(user1, user2, balance) user1.Balances[key] = 0 user2.Balances[user2.ID+":"+user1.ID] = 0 } else if balance < 0 { s.createTransaction(user2, user1, -balance) user1.Balances[key] = 0 user2.Balances[user2.ID+":"+user1.ID] = 0 } } func (s *SplitwiseService) createTransaction(sender, receiver *User, amount float64) { fmt.Printf("Transaction: %s pays %s an amount of %.2f\n", sender.Name, receiver.Name, amount) } ================================================ FILE: solutions/golang/splitwise/transaction.go ================================================ package splitwise type Transaction struct { ID string Sender *User Receiver *User Amount float64 } func NewTransaction(id string, sender, receiver *User, amount float64) *Transaction { return &Transaction{ID: id, Sender: sender, Receiver: receiver, Amount: amount} } ================================================ FILE: solutions/golang/splitwise/user.go ================================================ package splitwise type User struct { ID string Name string Email string Balances map[string]float64 } func NewUser(id, name, email string) *User { return &User{ ID: id, Name: name, Email: email, Balances: make(map[string]float64), } } ================================================ FILE: solutions/golang/stackOverFlow/README.md ================================================ # Designing Stack Overflow ## Requirements 1. Users can post questions, answer questions, and comment on questions and answers. 2. Users can vote on questions and answers. 3. Questions should have tags associated with them. 4. Users can search for questions based on keywords, tags, or user profiles. 5. The system should assign reputation score to users based on their activity and the quality of their contributions. 6. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the Stack Overflow system, with properties such as id, username, email, and reputation. 2. The **Question** class represents a question posted by a user, with properties such as id, title, content, author, answers, comments, tags, votes and creation date. 3. The **Answer** class represents an answer to a question, with properties such as id, content, author, associated question, comments, votes and creation date. 4. The **Comment** class represents a comment on a question or an answer, with properties such as id, content, author, and creation date. 5. The **Tag** class represents a tag associated with a question, with properties such as id and name. 6. The **Vote** class represents vote associated with a question/answer. 7. The **StackOverflow** class is the main class that manages the Stack Overflow system. It provides methods for creating user, posting questions, answers, and comments, voting on questions and answers, searching for questions, and retrieving questions by tags and users. 8. The **StackOverflowDemo** class demonstrates the usage of the Stack Overflow system by creating users, posting questions and answers, voting, searching for questions, and retrieving questions by tags and users. ================================================ FILE: solutions/golang/stackOverFlow/answer.go ================================================ package stackoverflow import ( "fmt" "sync" "time" ) type Answer struct { ID string Content string Author *User Question *Question CreationDate time.Time isAccepted bool comments []*Comment votes []*Vote mu sync.RWMutex } func NewAnswer(author *User, question *Question, content string) *Answer { return &Answer{ ID: generateID(), Author: author, Question: question, Content: content, CreationDate: time.Now(), comments: make([]*Comment, 0), votes: make([]*Vote, 0), } } func (a *Answer) Vote(user *User, value int) error { a.mu.Lock() defer a.mu.Unlock() if value != 1 && value != -1 { return fmt.Errorf("vote value must be either 1 or -1") } // Remove existing vote from this user for i, v := range a.votes { if v.User.ID == user.ID { a.votes = append(a.votes[:i], a.votes[i+1:]...) break } } a.votes = append(a.votes, &Vote{User: user, Value: value}) a.Author.UpdateReputation(value * 10) // +10 for upvote, -10 for downvote return nil } func (a *Answer) GetVoteCount() int { a.mu.RLock() defer a.mu.RUnlock() count := 0 for _, vote := range a.votes { count += vote.Value } return count } func (a *Answer) AddComment(comment *Comment) error { a.mu.Lock() defer a.mu.Unlock() a.comments = append(a.comments, comment) return nil } func (a *Answer) GetComments() []*Comment { a.mu.RLock() defer a.mu.RUnlock() comments := make([]*Comment, len(a.comments)) copy(comments, a.comments) return comments } func (a *Answer) MarkAsAccepted() error { a.mu.Lock() defer a.mu.Unlock() if a.isAccepted { return fmt.Errorf("answer is already accepted") } a.isAccepted = true a.Author.UpdateReputation(15) // +15 reputation for accepted answer return nil } func (a *Answer) IsAccepted() bool { a.mu.RLock() defer a.mu.RUnlock() return a.isAccepted } ================================================ FILE: solutions/golang/stackOverFlow/stackoverflow.go ================================================ package stackoverflow import ( "fmt" "strings" "sync" ) type StackOverflow struct { users map[string]*User questions map[string]*Question answers map[string]*Answer tags map[string]*Tag mu sync.RWMutex } func NewStackOverflow() *StackOverflow { return &StackOverflow{ users: make(map[string]*User), questions: make(map[string]*Question), answers: make(map[string]*Answer), tags: make(map[string]*Tag), } } func (so *StackOverflow) CreateUser(username, email string) *User { so.mu.Lock() defer so.mu.Unlock() id := generateID() user := NewUser(id, username, email) so.users[id] = user return user } func (so *StackOverflow) AskQuestion(user *User, title, content string, tags []string) (*Question, error) { if user == nil { return nil, fmt.Errorf("user cannot be nil") } question := NewQuestion(user, title, content, tags) so.mu.Lock() defer so.mu.Unlock() so.questions[question.ID] = question user.AddQuestion(question) // Register tags for _, tag := range question.GetTags() { so.tags[tag.Name] = tag } return question, nil } func (so *StackOverflow) AnswerQuestion(user *User, question *Question, content string) (*Answer, error) { if user == nil || question == nil { return nil, fmt.Errorf("user and question cannot be nil") } answer := NewAnswer(user, question, content) so.mu.Lock() defer so.mu.Unlock() so.answers[answer.ID] = answer question.AddAnswer(answer) user.AddAnswer(answer) return answer, nil } func (so *StackOverflow) AddComment(user *User, target Commentable, content string) (*Comment, error) { if user == nil || target == nil { return nil, fmt.Errorf("user and target cannot be nil") } comment := NewComment(user, content) if err := target.AddComment(comment); err != nil { return nil, err } user.AddComment(comment) return comment, nil } func (so *StackOverflow) VoteQuestion(user *User, question *Question, value int) error { if user == nil || question == nil { return fmt.Errorf("user and question cannot be nil") } return question.Vote(user, value) } func (so *StackOverflow) VoteAnswer(user *User, answer *Answer, value int) error { if user == nil || answer == nil { return fmt.Errorf("user and answer cannot be nil") } return answer.Vote(user, value) } func (so *StackOverflow) AcceptAnswer(answer *Answer) error { if answer == nil { return fmt.Errorf("answer cannot be nil") } return answer.MarkAsAccepted() } func (so *StackOverflow) SearchQuestions(query string) []*Question { so.mu.RLock() defer so.mu.RUnlock() query = strings.ToLower(query) var results []*Question for _, q := range so.questions { if strings.Contains(strings.ToLower(q.Title), query) || strings.Contains(strings.ToLower(q.Content), query) { results = append(results, q) continue } // Search in tags for _, tag := range q.GetTags() { if strings.EqualFold(tag.Name, query) { results = append(results, q) break } } } return results } func (so *StackOverflow) GetQuestionsByUser(user *User) []*Question { if user == nil { return nil } return user.GetQuestions() } ================================================ FILE: solutions/golang/stackOverFlow/stackoverflow_demo.go ================================================ package stackoverflow import "fmt" func Run() { system := NewStackOverflow() // Create users alice := system.CreateUser("Alice", "alice@example.com") bob := system.CreateUser("Bob", "bob@example.com") charlie := system.CreateUser("Charlie", "charlie@example.com") fmt.Println("Users created:", alice.Username, bob.Username, charlie.Username) // Alice asks a question about Java javaQuestion, err := system.AskQuestion(alice, "What is polymorphism in Java?", "Can someone explain polymorphism in Java with an example?", []string{"java", "oop"}) if err != nil { fmt.Printf("Error asking Java question: %v\n", err) return } // Bob answers Alice's question bobAnswer, err := system.AnswerQuestion(bob, javaQuestion, "Polymorphism in Java is the ability of an object to take on many forms...") if err != nil { fmt.Printf("Error answering question: %v\n", err) return } // Charlie comments on the question _, err = system.AddComment(charlie, javaQuestion, "Great question! I'm also interested in learning about this.") if err != nil { fmt.Printf("Error adding comment to question: %v\n", err) return } // Alice comments on Bob's answer _, err = system.AddComment(alice, bobAnswer, "Thanks for the explanation! Could you provide a code example?") if err != nil { fmt.Printf("Error adding comment to answer: %v\n", err) return } // Charlie votes on the question and answer if err := system.VoteQuestion(charlie, javaQuestion, 1); err != nil { fmt.Printf("Error voting on question: %v\n", err) return } if err := system.VoteAnswer(charlie, bobAnswer, 1); err != nil { fmt.Printf("Error voting on answer: %v\n", err) return } // Alice accepts Bob's answer if err := system.AcceptAnswer(bobAnswer); err != nil { fmt.Printf("Error accepting answer: %v\n", err) return } // Bob asks a Python question pythonQuestion, err := system.AskQuestion(bob, "How to use list comprehensions in Python?", "I'm new to Python and I've heard about list comprehensions. Can someone explain how to use them?", []string{"python", "list-comprehension"}) if err != nil { fmt.Printf("Error asking Python question: %v\n", err) return } // Alice answers Bob's question aliceAnswer, err := system.AnswerQuestion(alice, pythonQuestion, "List comprehensions in Python provide a concise way to create lists...") if err != nil { fmt.Printf("Error answering Python question: %v\n", err) return } // Charlie votes on Bob's question and Alice's answer if err := system.VoteQuestion(charlie, pythonQuestion, 1); err != nil { fmt.Printf("Error voting on Python question: %v\n", err) return } if err := system.VoteAnswer(charlie, aliceAnswer, 1); err != nil { fmt.Printf("Error voting on Alice's answer: %v\n", err) return } // Print out the current state fmt.Println("\n=== Java Question ===") fmt.Printf("Title: %s\n", javaQuestion.Title) fmt.Printf("Asked by: %s\n", javaQuestion.Author.Username) fmt.Printf("Tags: ") for _, tag := range javaQuestion.GetTags() { fmt.Printf("%s ", tag.Name) } fmt.Printf("\nVotes: %d\n", javaQuestion.GetVoteCount()) fmt.Printf("Comments: %d\n", len(javaQuestion.GetComments())) fmt.Printf("\nAnswer by %s:\n", bobAnswer.Author.Username) fmt.Printf("Content: %s\n", bobAnswer.Content) fmt.Printf("Votes: %d\n", bobAnswer.GetVoteCount()) fmt.Printf("Accepted: %v\n", bobAnswer.IsAccepted()) fmt.Printf("Comments: %d\n", len(bobAnswer.GetComments())) fmt.Println("\n=== User Reputations ===") fmt.Printf("Alice: %d\n", alice.GetReputation()) fmt.Printf("Bob: %d\n", bob.GetReputation()) fmt.Printf("Charlie: %d\n", charlie.GetReputation()) fmt.Println("\n=== Search Results ===") fmt.Println("Search Results for 'java':") javaResults := system.SearchQuestions("java") for _, q := range javaResults { fmt.Printf("- %s\n", q.Title) } fmt.Println("\nSearch Results for 'python':") pythonResults := system.SearchQuestions("python") for _, q := range pythonResults { fmt.Printf("- %s\n", q.Title) } fmt.Println("\n=== Bob's Questions ===") bobQuestions := system.GetQuestionsByUser(bob) for _, q := range bobQuestions { fmt.Printf("- %s\n", q.Title) } } ================================================ FILE: solutions/golang/stackOverFlow/types.go ================================================ package stackoverflow import ( "fmt" "sync" "time" ) // Interfaces type Votable interface { Vote(user *User, value int) error GetVoteCount() int } type Commentable interface { AddComment(comment *Comment) error GetComments() []*Comment } // Reputation constants const ( QuestionReputation = 5 AnswerReputation = 10 CommentReputation = 2 ) // Vote type type Vote struct { User *User Value int } // Comment type type Comment struct { ID string Content string Author *User CreationDate time.Time mu sync.RWMutex } func NewComment(author *User, content string) *Comment { return &Comment{ ID: generateID(), Content: content, Author: author, CreationDate: time.Now(), } } // Tag type type Tag struct { ID string Name string } func NewTag(name string) *Tag { return &Tag{ ID: generateID(), Name: name, } } // User type type User struct { ID string Username string Email string reputation int questions []*Question answers []*Answer comments []*Comment mu sync.RWMutex } func NewUser(id, username, email string) *User { return &User{ ID: id, Username: username, Email: email, questions: make([]*Question, 0), answers: make([]*Answer, 0), comments: make([]*Comment, 0), } } func (u *User) UpdateReputation(value int) { u.mu.Lock() defer u.mu.Unlock() u.reputation += value if u.reputation < 0 { u.reputation = 0 } } func (u *User) GetReputation() int { u.mu.RLock() defer u.mu.RUnlock() return u.reputation } func (u *User) AddQuestion(q *Question) { u.mu.Lock() defer u.mu.Unlock() u.questions = append(u.questions, q) u.UpdateReputation(QuestionReputation) } func (u *User) AddAnswer(a *Answer) { u.mu.Lock() defer u.mu.Unlock() u.answers = append(u.answers, a) u.UpdateReputation(AnswerReputation) } func (u *User) AddComment(c *Comment) { u.mu.Lock() defer u.mu.Unlock() u.comments = append(u.comments, c) u.UpdateReputation(CommentReputation) } func (u *User) GetQuestions() []*Question { u.mu.RLock() defer u.mu.RUnlock() questions := make([]*Question, len(u.questions)) copy(questions, u.questions) return questions } // Question type type Question struct { ID string Title string Content string Author *User CreationDate time.Time answers []*Answer comments []*Comment tags []*Tag votes []*Vote mu sync.RWMutex } func NewQuestion(author *User, title, content string, tagNames []string) *Question { q := &Question{ ID: generateID(), Title: title, Content: content, Author: author, CreationDate: time.Now(), answers: make([]*Answer, 0), comments: make([]*Comment, 0), tags: make([]*Tag, 0), votes: make([]*Vote, 0), } for _, tagName := range tagNames { q.tags = append(q.tags, NewTag(tagName)) } return q } func (q *Question) AddAnswer(answer *Answer) error { q.mu.Lock() defer q.mu.Unlock() // Check for duplicate answer for _, a := range q.answers { if a.ID == answer.ID { return nil } } q.answers = append(q.answers, answer) return nil } func (q *Question) Vote(user *User, value int) error { q.mu.Lock() defer q.mu.Unlock() if value != 1 && value != -1 { return fmt.Errorf("vote value must be either 1 or -1") } // Remove existing vote from this user for i, v := range q.votes { if v.User.ID == user.ID { q.votes = append(q.votes[:i], q.votes[i+1:]...) break } } q.votes = append(q.votes, &Vote{User: user, Value: value}) q.Author.UpdateReputation(value * 5) // +5 for upvote, -5 for downvote return nil } func (q *Question) GetVoteCount() int { q.mu.RLock() defer q.mu.RUnlock() count := 0 for _, vote := range q.votes { count += vote.Value } return count } func (q *Question) AddComment(comment *Comment) error { q.mu.Lock() defer q.mu.Unlock() q.comments = append(q.comments, comment) return nil } func (q *Question) GetComments() []*Comment { q.mu.RLock() defer q.mu.RUnlock() comments := make([]*Comment, len(q.comments)) copy(comments, q.comments) return comments } func (q *Question) GetAnswers() []*Answer { q.mu.RLock() defer q.mu.RUnlock() answers := make([]*Answer, len(q.answers)) copy(answers, q.answers) return answers } func (q *Question) GetTags() []*Tag { q.mu.RLock() defer q.mu.RUnlock() tags := make([]*Tag, len(q.tags)) copy(tags, q.tags) return tags } // Utility functions func generateID() string { return fmt.Sprintf("%d", time.Now().UnixNano()) } ================================================ FILE: solutions/golang/taskmanagementsystem/README.md ================================================ # Designing a Task Management System ## Requirements 1. The task management system should allow users to create, update, and delete tasks. 2. Each task should have a title, description, due date, priority, and status (e.g., pending, in progress, completed). 3. Users should be able to assign tasks to other users and set reminders for tasks. 4. The system should support searching and filtering tasks based on various criteria (e.g., priority, due date, assigned user). 5. Users should be able to mark tasks as completed and view their task history. 6. The system should handle concurrent access to tasks and ensure data consistency. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the task management system, with properties such as id, name, and email. 2. The **TaskStatus** enum defines the possible states of a task, such as pending, in progress, and completed. 3. The **Task** class represents a task in the system, with properties like id, title, description, due date, priority, status, and assigned user. 4. The **TaskManager** class is the core of the task management system and follows the Singleton pattern to ensure a single instance of the task manager. 5. The TaskManager class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to tasks and ensure thread safety. 6. The TaskManager class provides methods for creating, updating, deleting, searching, and filtering tasks, as well as marking tasks as completed and retrieving task history for a user. 7. The **TaskManagementSystem** class serves as the entry point of the application and demonstrates the usage of the task management system. ================================================ FILE: solutions/golang/taskmanagementsystem/task.go ================================================ package taskmanagementsystem import "time" type Task struct { Id string Title string Description string DueDate time.Time Priority int Status TaskStatus AssignedUser *User } func NewTask(id, title, description string, dueDate time.Time, priority int, assignedUser *User) *Task { return &Task{ Id: id, Title: title, Description: description, DueDate: dueDate, Priority: priority, Status: Pending, AssignedUser: assignedUser, } } func (t *Task) GetId() string { return t.Id } func (t *Task) GetTitle() string { return t.Title } func (t *Task) GetDescription() string { return t.Description } func (t *Task) GetDueDate() time.Time { return t.DueDate } func (t *Task) GetPriority() int { return t.Priority } func (t *Task) GetStatus() TaskStatus { return t.Status } func (t *Task) GetAssignedUser() *User { return t.AssignedUser } func (t *Task) SetTitle(title string) { t.Title = title } func (t *Task) SetDescription(description string) { t.Description = description } func (t *Task) SetDueDate(dueDate time.Time) { t.DueDate = dueDate } func (t *Task) SetPriority(priority int) { t.Priority = priority } func (t *Task) SetStatus(status TaskStatus) { t.Status = status } ================================================ FILE: solutions/golang/taskmanagementsystem/task_management_system_demo.go ================================================ package taskmanagementsystem import ( "fmt" "time" ) func Run() { taskManager := GetTaskManager() // Create users user1 := NewUser("1", "John Doe", "john@example.com") user2 := NewUser("2", "Jane Smith", "jane@example.com") // Create tasks task1 := NewTask("1", "Task 1", "Description 1", time.Now(), 1, user1) task2 := NewTask("2", "Task 2", "Description 2", time.Now(), 2, user2) task3 := NewTask("3", "Task 3", "Description 3", time.Now(), 1, user1) // Add tasks to the task manager taskManager.CreateTask(task1) taskManager.CreateTask(task2) taskManager.CreateTask(task3) // Update a task task2.SetDescription("Updated description") taskManager.UpdateTask(task2) // Search tasks searchResults := taskManager.SearchTasks("Task") fmt.Println("Search Results:") for _, task := range searchResults { fmt.Println(task.GetTitle()) } // Filter tasks filteredTasks := taskManager.FilterTasks(Pending, time.Unix(0, 0), time.Now(), 1) fmt.Println("Filtered Tasks:") for _, task := range filteredTasks { fmt.Println(task.GetTitle()) } // Mark a task as completed taskManager.MarkTaskAsCompleted("1") // Get task history for a user taskHistory := taskManager.GetTaskHistory(user1) fmt.Printf("Task History for %s:\n", user1.GetName()) for _, task := range taskHistory { fmt.Println(task.GetTitle()) } // Delete a task taskManager.DeleteTask("3") } ================================================ FILE: solutions/golang/taskmanagementsystem/task_manager.go ================================================ package taskmanagementsystem import ( "sync" "time" ) type TaskManager struct { tasks map[string]*Task userTasks map[string][]*Task mu sync.Mutex } var instance *TaskManager var once sync.Once func GetTaskManager() *TaskManager { once.Do(func() { instance = &TaskManager{ tasks: make(map[string]*Task), userTasks: make(map[string][]*Task), } }) return instance } func (tm *TaskManager) CreateTask(task *Task) { tm.mu.Lock() defer tm.mu.Unlock() tm.tasks[task.GetId()] = task tm.assignTaskToUser(task.GetAssignedUser(), task) } func (tm *TaskManager) UpdateTask(updatedTask *Task) { tm.mu.Lock() defer tm.mu.Unlock() if existingTask, exists := tm.tasks[updatedTask.GetId()]; exists { existingTask.SetTitle(updatedTask.GetTitle()) existingTask.SetDescription(updatedTask.GetDescription()) existingTask.SetDueDate(updatedTask.GetDueDate()) existingTask.SetPriority(updatedTask.GetPriority()) existingTask.SetStatus(updatedTask.GetStatus()) if existingTask.GetAssignedUser() != updatedTask.GetAssignedUser() { tm.unassignTaskFromUser(existingTask.GetAssignedUser(), existingTask) tm.assignTaskToUser(updatedTask.GetAssignedUser(), existingTask) } } } func (tm *TaskManager) DeleteTask(taskId string) { tm.mu.Lock() defer tm.mu.Unlock() if task, exists := tm.tasks[taskId]; exists { delete(tm.tasks, taskId) tm.unassignTaskFromUser(task.GetAssignedUser(), task) } } func (tm *TaskManager) SearchTasks(keyword string) []*Task { tm.mu.Lock() defer tm.mu.Unlock() var matchingTasks []*Task for _, task := range tm.tasks { if contains(task.GetTitle(), keyword) || contains(task.GetDescription(), keyword) { matchingTasks = append(matchingTasks, task) } } return matchingTasks } func (tm *TaskManager) FilterTasks(status TaskStatus, startDate, endDate time.Time, priority int) []*Task { tm.mu.Lock() defer tm.mu.Unlock() var filteredTasks []*Task for _, task := range tm.tasks { if task.GetStatus() == status && task.GetDueDate().After(startDate) && task.GetDueDate().Before(endDate) && task.GetPriority() == priority { filteredTasks = append(filteredTasks, task) } } return filteredTasks } func (tm *TaskManager) MarkTaskAsCompleted(taskId string) { tm.mu.Lock() defer tm.mu.Unlock() if task, exists := tm.tasks[taskId]; exists { task.SetStatus(Completed) } } func (tm *TaskManager) GetTaskHistory(user *User) []*Task { tm.mu.Lock() defer tm.mu.Unlock() return tm.userTasks[user.GetId()] } func (tm *TaskManager) assignTaskToUser(user *User, task *Task) { tm.userTasks[user.GetId()] = append(tm.userTasks[user.GetId()], task) } func (tm *TaskManager) unassignTaskFromUser(user *User, task *Task) { tasks := tm.userTasks[user.GetId()] for i, t := range tasks { if t == task { tm.userTasks[user.GetId()] = append(tasks[:i], tasks[i+1:]...) break } } } func contains(text, substr string) bool { return len(text) >= len(substr) && text[:len(substr)] == substr } ================================================ FILE: solutions/golang/taskmanagementsystem/task_status.go ================================================ package taskmanagementsystem type TaskStatus string const ( Pending TaskStatus = "PENDING" InProgress TaskStatus = "IN_PROGRESS" Completed TaskStatus = "COMPLETED" ) ================================================ FILE: solutions/golang/taskmanagementsystem/user.go ================================================ package taskmanagementsystem type User struct { Id string Name string Email string } func NewUser(id, name, email string) *User { return &User{Id: id, Name: name, Email: email} } func (u *User) GetId() string { return u.Id } func (u *User) GetName() string { return u.Name } ================================================ FILE: solutions/golang/tictactoe/README.md ================================================ # Designing a Tic Tac Toe Game ## Requirements 1. The Tic-Tac-Toe game should be played on a 3x3 grid. 2. Two players take turns marking their symbols (X or O) on the grid. 3. The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins the game. 4. If all the cells on the grid are filled and no player has won, the game ends in a draw. 5. The game should have a user interface to display the grid and allow players to make their moves. 6. The game should handle player turns and validate moves to ensure they are legal. 7. The game should detect and announce the winner or a draw at the end of the game. ## Classes, Interfaces and Enumerations 1. The **Player** class represents a player in the game, with a name and a symbol (X or O). 2. The **Board** class represents the game board, which is a 3x3 grid. It provides methods to make moves, check for a winner, and check if the board is full. 3. The **Game** class manages the game flow and player interactions. It handles player turns, validates moves, and determines the winner or a draw. 4. The **TicTacToe** class is the entry point of the application and creates instances of the players and the game. ================================================ FILE: solutions/golang/tictactoe/board.go ================================================ package tictactoe import "fmt" type Board struct { Grid [3][3]rune MovesCount int } func NewBoard() *Board { board := &Board{} board.InitializeBoard() return board } func (b *Board) InitializeBoard() { for row := 0; row < 3; row++ { for col := 0; col < 3; col++ { b.Grid[row][col] = '-' } } b.MovesCount = 0 } func (b *Board) MakeMove(row, col int, symbol rune) error { if row < 0 || row >= 3 || col < 0 || col >= 3 || b.Grid[row][col] != '-' { return fmt.Errorf("invalid move!") } b.Grid[row][col] = symbol b.MovesCount++ return nil } func (b *Board) IsFull() bool { return b.MovesCount == 9 } func (b *Board) HasWinner() bool { // Check rows for row := 0; row < 3; row++ { if b.Grid[row][0] != '-' && b.Grid[row][0] == b.Grid[row][1] && b.Grid[row][1] == b.Grid[row][2] { return true } } // Check columns for col := 0; col < 3; col++ { if b.Grid[0][col] != '-' && b.Grid[0][col] == b.Grid[1][col] && b.Grid[1][col] == b.Grid[2][col] { return true } } // Check diagonals if b.Grid[0][0] != '-' && b.Grid[0][0] == b.Grid[1][1] && b.Grid[1][1] == b.Grid[2][2] { return true } return b.Grid[0][2] != '-' && b.Grid[0][2] == b.Grid[1][1] && b.Grid[1][1] == b.Grid[2][0] } func (b *Board) PrintBoard() { for row := 0; row < 3; row++ { for col := 0; col < 3; col++ { fmt.Print(string(b.Grid[row][col]) + " ") } fmt.Println() } fmt.Println() } ================================================ FILE: solutions/golang/tictactoe/game.go ================================================ package tictactoe import ( "bufio" "fmt" "os" "strconv" ) type Game struct { Player1 *Player Player2 *Player Board *Board CurrentPlayer *Player } func NewGame(player1, player2 *Player) *Game { return &Game{ Player1: player1, Player2: player2, Board: NewBoard(), CurrentPlayer: player1, } } func (g *Game) Play() { g.Board.PrintBoard() for !g.Board.IsFull() && !g.Board.HasWinner() { fmt.Printf("%s's turn.\n", g.CurrentPlayer.Name) row := g.getValidInput("Enter row (0-2): ") col := g.getValidInput("Enter column (0-2): ") err := g.Board.MakeMove(row, col, g.CurrentPlayer.Symbol) if err != nil { fmt.Println(err.Error()) continue } g.Board.PrintBoard() g.switchPlayer() } if g.Board.HasWinner() { g.switchPlayer() // Switch back to the winner fmt.Printf("%s wins!\n", g.CurrentPlayer.Name) } else { fmt.Println("It's a draw!") } } func (g *Game) switchPlayer() { if g.CurrentPlayer == g.Player1 { g.CurrentPlayer = g.Player2 } else { g.CurrentPlayer = g.Player1 } } func (g *Game) getValidInput(prompt string) int { scanner := bufio.NewScanner(os.Stdin) for { fmt.Print(prompt) scanner.Scan() input, err := strconv.Atoi(scanner.Text()) if err == nil && input >= 0 && input <= 2 { return input } fmt.Println("Invalid input! Please enter a number between 0 and 2.") } } ================================================ FILE: solutions/golang/tictactoe/player.go ================================================ package tictactoe type Player struct { Name string Symbol rune } func NewPlayer(name string, symbol rune) *Player { return &Player{Name: name, Symbol: symbol} } ================================================ FILE: solutions/golang/tictactoe/tictactoe_demo.go ================================================ package tictactoe func Run() { player1 := NewPlayer("Player 1", 'X') player2 := NewPlayer("Player 2", 'O') game := NewGame(player1, player2) game.Play() } ================================================ FILE: solutions/golang/trafficsignalsystem/README.md ================================================ # Designing a Traffic Signal Control System ## Requirements 1. The traffic signal system should control the flow of traffic at an intersection with multiple roads. 2. The system should support different types of signals, such as red, yellow, and green. 3. The duration of each signal should be configurable and adjustable based on traffic conditions. 4. The system should handle the transition between signals smoothly, ensuring safe and efficient traffic flow. 5. The system should be able to detect and handle emergency situations, such as an ambulance or fire truck approaching the intersection. 6. The system should be scalable and extensible to support additional features and functionality. ## Classes, Interfaces and Enumerations 1. The **Signal** enum represents the different states of a traffic light: red, yellow, and green. 2. The **Road** class represents a road in the traffic signal system, with properties such as ID, name, and an associated traffic light. 3. The **TrafficLight** class represents a traffic light, with properties such as ID, current signal, and durations for each signal state. It provides methods to change the signal and notify observers (e.g., roads) about signal changes. 4. The **TrafficController** class serves as the central controller for the traffic signal system. It follows the Singleton pattern to ensure a single instance of the controller. It manages the roads and their associated traffic lights, starts the traffic control process, and handles emergency situations. 5. The **TrafficSignalSystemDemo** class is the main entry point of the application. It demonstrates the usage of the traffic signal system by creating roads, traffic lights, assigning traffic lights to roads, and starting the traffic control process. ================================================ FILE: solutions/golang/trafficsignalsystem/road.go ================================================ package trafficsignalsystem type Road struct { ID string Name string TrafficLight *TrafficLight } func NewRoad(id, name string) *Road { return &Road{ID: id, Name: name} } func (r *Road) SetTrafficLight(trafficLight *TrafficLight) { r.TrafficLight = trafficLight } ================================================ FILE: solutions/golang/trafficsignalsystem/signal.go ================================================ package trafficsignalsystem type Signal string const ( Red Signal = "RED" Yellow Signal = "YELLOW" Green Signal = "GREEN" ) ================================================ FILE: solutions/golang/trafficsignalsystem/traffic_controller.go ================================================ package trafficsignalsystem import ( "sync" "time" ) type TrafficController struct { roads map[string]*Road mu sync.Mutex } var instance *TrafficController var once sync.Once // GetTrafficController returns the singleton instance of TrafficController func GetTrafficController() *TrafficController { once.Do(func() { instance = &TrafficController{roads: make(map[string]*Road)} }) return instance } func (tc *TrafficController) AddRoad(road *Road) { tc.mu.Lock() defer tc.mu.Unlock() tc.roads[road.ID] = road } func (tc *TrafficController) StartTrafficControl() { tc.mu.Lock() defer tc.mu.Unlock() for _, road := range tc.roads { trafficLight := road.TrafficLight go func(tl *TrafficLight) { for { time.Sleep(time.Duration(tl.RedDuration) * time.Millisecond) tl.ChangeSignal(Green) time.Sleep(time.Duration(tl.GreenDuration) * time.Millisecond) tl.ChangeSignal(Yellow) time.Sleep(time.Duration(tl.YellowDuration) * time.Millisecond) tl.ChangeSignal(Red) } }(trafficLight) } } func (tc *TrafficController) HandleEmergency(roadID string) { tc.mu.Lock() defer tc.mu.Unlock() if road, exists := tc.roads[roadID]; exists { trafficLight := road.TrafficLight trafficLight.ChangeSignal(Green) // Emergency handling logic here } } ================================================ FILE: solutions/golang/trafficsignalsystem/traffic_light.go ================================================ package trafficsignalsystem import "fmt" type TrafficLight struct { ID string CurrentSignal Signal RedDuration int YellowDuration int GreenDuration int } func NewTrafficLight(id string, redDuration, yellowDuration, greenDuration int) *TrafficLight { return &TrafficLight{ ID: id, RedDuration: redDuration, YellowDuration: yellowDuration, GreenDuration: greenDuration, CurrentSignal: Red, } } func (tl *TrafficLight) ChangeSignal(newSignal Signal) { tl.CurrentSignal = newSignal tl.notifyObservers() } func (tl *TrafficLight) notifyObservers() { fmt.Printf("Traffic Light %s changed to %s\n", tl.ID, tl.CurrentSignal) } ================================================ FILE: solutions/golang/trafficsignalsystem/traffic_signal_system_demo.go ================================================ package trafficsignalsystem import "time" // Run demonstrates the Traffic Signal System functionality func Run() { // Initialize the traffic controller trafficController := GetTrafficController() // Create roads road1 := NewRoad("R1", "Main Street") road2 := NewRoad("R2", "Broadway") road3 := NewRoad("R3", "Park Avenue") road4 := NewRoad("R4", "Elm Street") // Create traffic lights trafficLight1 := NewTrafficLight("TL1", 6000, 3000, 9000) trafficLight2 := NewTrafficLight("TL2", 6000, 3000, 9000) trafficLight3 := NewTrafficLight("TL3", 6000, 3000, 9000) trafficLight4 := NewTrafficLight("TL4", 6000, 3000, 9000) // Assign traffic lights to roads road1.SetTrafficLight(trafficLight1) road2.SetTrafficLight(trafficLight2) road3.SetTrafficLight(trafficLight3) road4.SetTrafficLight(trafficLight4) // Add roads to the traffic controller trafficController.AddRoad(road1) trafficController.AddRoad(road2) trafficController.AddRoad(road3) trafficController.AddRoad(road4) // Start traffic control go trafficController.StartTrafficControl() // Simulate an emergency after some time time.Sleep(10 * time.Second) trafficController.HandleEmergency("R2") } ================================================ FILE: solutions/golang/vendingmachine/README.md ================================================ # Designing a Vending Machine ## Requirements 1. The vending machine should support multiple products with different prices and quantities. 1. The machine should accept coins and notes of different denominations. 1. The machine should dispense the selected product and return change if necessary. 1. The machine should keep track of the available products and their quantities. 1. The machine should handle multiple transactions concurrently and ensure data consistency. 1. The machine should provide an interface for restocking products and collecting money. 1. The machine should handle exceptional scenarios, such as insufficient funds or out-of-stock products. ## Classes, Interfaces and Enumerations 1. The **Product** class represents a product in the vending machine, with properties such as name and price. 2. The **Coin** and **Note** enums represent the different denominations of coins and notes accepted by the vending machine. 3. The **Inventory** class manages the available products and their quantities in the vending machine. It uses a concurrent hash map to ensure thread safety. 4. The **VendingMachineState** interface defines the behavior of the vending machine in different states, such as idle, ready, and dispense. 5. The **IdleState**, **ReadyState**, and **DispenseState** classes implement the VendingMachineState interface and define the specific behaviors for each state. 6. The **VendingMachine** class is the main class that represents the vending machine. It follows the Singleton pattern to ensure only one instance of the vending machine exists. 7. The VendingMachine class maintains the current state, selected product, total payment, and provides methods for state transitions and payment handling. 8. The **VendingMachineDemo** class demonstrates the usage of the vending machine by adding products to the inventory, selecting products, inserting coins and notes, dispensing products, and returning change. ================================================ FILE: solutions/golang/vendingmachine/coin.go ================================================ package vending_machine type Coin float64 const ( PENNY Coin = 0.01 NICKEL Coin = 0.05 DIME Coin = 0.10 QUARTER Coin = 0.25 ) ================================================ FILE: solutions/golang/vendingmachine/inventory.go ================================================ package vending_machine type Inventory struct { products map[*Product]int } func NewInventory() *Inventory { return &Inventory{products: make(map[*Product]int)} } func (inv *Inventory) AddProduct(product *Product, quantity int) { inv.products[product] = quantity } func (inv *Inventory) IsAvailable(product *Product) bool { qty, exists := inv.products[product] return exists && qty > 0 } ================================================ FILE: solutions/golang/vendingmachine/note.go ================================================ package vending_machine type Note int const ( ONE Note = 1 FIVE Note = 5 TEN Note = 10 TWENTY Note = 20 ) ================================================ FILE: solutions/golang/vendingmachine/product.go ================================================ package vending_machine type Product struct { name string price float64 } func NewProduct(name string, price float64) *Product { return &Product{name: name, price: price} } ================================================ FILE: solutions/golang/vendingmachine/state.go ================================================ package vending_machine import "fmt" type VendingMachineState interface { SelectProduct(product *Product) InsertCoin(coin Coin) InsertNote(note Note) DispenseProduct() ReturnChange() } // IdleState struct type IdleState struct { vendingMachine *VendingMachine } func (s *IdleState) SelectProduct(product *Product) { if s.vendingMachine.inventory.IsAvailable(product) { s.vendingMachine.selectedProduct = product s.vendingMachine.SetState(s.vendingMachine.readyState) fmt.Println("Product selected:", product.name) } else { fmt.Println("Product not available:", product.name) } } func (s *IdleState) InsertCoin(coin Coin) { fmt.Println("Please select a product first.") } func (s *IdleState) InsertNote(note Note) { fmt.Println("Please select a product first.") } func (s *IdleState) DispenseProduct() { fmt.Println("Please select a product and make payment.") } func (s *IdleState) ReturnChange() { fmt.Println("No change to return.") } // ReadyState struct type ReadyState struct { vendingMachine *VendingMachine } func (s *ReadyState) SelectProduct(product *Product) { fmt.Println("Product already selected. Please make payment.") } func (s *ReadyState) InsertCoin(coin Coin) { s.vendingMachine.totalPayment += float64(coin) fmt.Println("Coin inserted:", coin) s.checkPaymentStatus() } func (s *ReadyState) InsertNote(note Note) { s.vendingMachine.totalPayment += float64(note) fmt.Println("Note inserted:", note) s.checkPaymentStatus() } func (s *ReadyState) DispenseProduct() { fmt.Println("Please make payment first.") } func (s *ReadyState) ReturnChange() { change := s.vendingMachine.totalPayment - s.vendingMachine.selectedProduct.price if change > 0 { fmt.Printf("Change returned: $%.2f\n", change) s.vendingMachine.ResetPayment() } else { fmt.Println("No change to return.") } s.vendingMachine.SetState(s.vendingMachine.idleState) } func (s *ReadyState) checkPaymentStatus() { if s.vendingMachine.totalPayment >= s.vendingMachine.selectedProduct.price { s.vendingMachine.SetState(s.vendingMachine.dispenseState) } } // DispenseState struct type DispenseState struct { vendingMachine *VendingMachine } func (s *DispenseState) SelectProduct(product *Product) { fmt.Println("Product already selected.") } func (s *DispenseState) InsertCoin(coin Coin) { fmt.Println("Please collect the product.") } func (s *DispenseState) InsertNote(note Note) { fmt.Println("Please collect the product.") } func (s *DispenseState) DispenseProduct() { fmt.Println("Product dispensed:", s.vendingMachine.selectedProduct.name) s.vendingMachine.SetState(s.vendingMachine.returnChangeState) } func (s *DispenseState) ReturnChange() { fmt.Println("Please collect the product first.") } // ReturnChangeState struct type ReturnChangeState struct { vendingMachine *VendingMachine } func (s *ReturnChangeState) SelectProduct(product *Product) { fmt.Println("Please collect the change first.") } func (s *ReturnChangeState) InsertCoin(coin Coin) { fmt.Println("Please collect the change first.") } func (s *ReturnChangeState) InsertNote(note Note) { fmt.Println("Please collect the change first.") } func (s *ReturnChangeState) DispenseProduct() { fmt.Println("Product already dispensed. Please collect the change.") } func (s *ReturnChangeState) ReturnChange() { change := s.vendingMachine.totalPayment - s.vendingMachine.selectedProduct.price if change > 0 { fmt.Printf("Change returned: $%.2f\n", change) s.vendingMachine.ResetPayment() } else { fmt.Println("No change to return.") } s.vendingMachine.ResetSelectedProduct() s.vendingMachine.SetState(s.vendingMachine.idleState) } ================================================ FILE: solutions/golang/vendingmachine/vending_machine.go ================================================ package vending_machine type VendingMachine struct { inventory *Inventory idleState VendingMachineState readyState VendingMachineState dispenseState VendingMachineState returnChangeState VendingMachineState currentState VendingMachineState selectedProduct *Product totalPayment float64 } func NewVendingMachine() *VendingMachine { vm := &VendingMachine{ inventory: NewInventory(), } vm.idleState = &IdleState{vm} vm.readyState = &ReadyState{vm} vm.dispenseState = &DispenseState{vm} vm.returnChangeState = &ReturnChangeState{vm} vm.currentState = vm.idleState return vm } func (vm *VendingMachine) SelectProduct(product *Product) { vm.currentState.SelectProduct(product) } func (vm *VendingMachine) InsertCoin(coin Coin) { vm.currentState.InsertCoin(coin) } func (vm *VendingMachine) InsertNote(note Note) { vm.currentState.InsertNote(note) } func (vm *VendingMachine) DispenseProduct() { vm.currentState.DispenseProduct() } func (vm *VendingMachine) ReturnChange() { vm.currentState.ReturnChange() } func (vm *VendingMachine) SetState(state VendingMachineState) { vm.currentState = state } func (vm *VendingMachine) ResetPayment() { vm.totalPayment = 0 } func (vm *VendingMachine) ResetSelectedProduct() { vm.selectedProduct = nil } ================================================ FILE: solutions/golang/vendingmachine/vending_machine_demo.go ================================================ package vending_machine import "fmt" // Run demonstrates the Vending Machine functionality. func Run() { // Initialize the vending machine vm := NewVendingMachine() // Create some products coke := NewProduct("Coke", 1.5) pepsi := NewProduct("Pepsi", 1.5) water := NewProduct("Water", 1.0) // Add products to the inventory vm.inventory.AddProduct(coke, 5) vm.inventory.AddProduct(pepsi, 3) vm.inventory.AddProduct(water, 2) // Demonstrate a transaction fmt.Println("Starting Vending Machine Demo") fmt.Println("\nSelecting Coke") vm.SelectProduct(coke) fmt.Println("Inserting coins") vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) fmt.Println("Dispensing product") vm.DispenseProduct() fmt.Println("Returning change") vm.ReturnChange() // Another example with insufficient funds fmt.Println("\nSelecting Pepsi with insufficient funds") vm.SelectProduct(pepsi) vm.InsertCoin(QUARTER) fmt.Println("Trying to dispense Pepsi") vm.DispenseProduct() fmt.Println("Adding more coins for Pepsi") vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) vm.InsertCoin(QUARTER) fmt.Println("Dispensing product") vm.DispenseProduct() fmt.Println("Returning change") vm.ReturnChange() } ================================================ FILE: solutions/golang/votingsystem/README.md ================================================ ### Airline Management System This is a simple airline management system that allows you to manage flights, passengers, and bookings. ================================================ FILE: solutions/java/.gitignore ================================================ ### IntelliJ IDEA ### out/ !**/src/main/**/out/ !**/src/test/**/out/ ### Eclipse ### .apt_generated .classpath .factorypath .taskList .settings .springBeans .sts4-cache bin/ !**/src/main/**/bin/ !**/src/test/**/bin/ ### NetBeans ### /nbproject/private/ /nbbuild/ /dist/ /nbdist/ /.nb-gradle/ ### VS Code ### .vscode/ ### Mac OS ### .DS_Store *.png **/diagrams/ ================================================ FILE: solutions/java/pom.xml ================================================ 4.0.0 coffeevendingmachine coffeevendingmachine 1.0-SNAPSHOT jar Coffee Vending Machine 1.8 1.8 5.10.2 org.junit.jupiter junit-jupiter ${junit.jupiter.version} test org.apache.maven.plugins maven-surefire-plugin 3.2.5 false ================================================ FILE: solutions/java/src/LLDRunner.java ================================================ import airlinemanagementsystem.AirlineManagementSystemDemo; import atm.ATMDemo; import chessgame.ChessGameDemo; import courseregistrationsystem.CourseRegistrationSystemDemo; import fooddeliveryservice.FoodDeliveryServiceDemo; import librarymanagementsystem.LibraryManagementSystemDemo; import loggingframework.LoggingFrameworkDemo; import lrucache.LRUCacheDemo; import musicstreamingservice.MusicStreamingServiceDemo; import onlineauctionsystem.AuctionSystemDemo; import onlineshoppingservice.OnlineShoppingServiceDemo; import parkinglot.ParkingLotDemo; import ridesharingservice.RideSharingServiceDemo; import snakeandladdergame.SnakeAndLadderDemo; import socialnetworkingservice.SocialNetworkingServiceDemo; import stackoverflow.StackOverflowDemo; import taskmanagementsystem.TaskManagementSystemDemo; import vendingmachine.VendingMachineDemo; public class LLDRunner { public static void main(String[] args) { // Uncomment the LLD problem you want to run with sample input defined in the corresponding Demo class. // AirlineManagementSystemDemo.run(); // ATMDemo.run(); // CarRentalSystemDemo.run(); // ChessGameDemo.run(); // CoffeeVendingMachineDemo.run(); // ConcertTicketBookingSystemDemo.run(); // CourseRegistrationSystemDemo.run(); // CricinfoDemo.run(); // DigitalWalletDemo.run(); // ElevatorSystemDemo.run(); // FoodDeliveryServiceDemo.run(); // HotelManagementSystemDemo.run(); // LibraryManagementSystemDemo.run(); // LinkedInDemo.run(); // LoggingFrameworkDemo.run(); // LRUCacheDemo.run(); // MovieTicketBookingDemo.run(); // MusicStreamingServiceDemo.run(); // AuctionSystemDemo.run(); // OnlineShoppingServiceDemo.run(); // StockBrokerageSystemDemo.run(); // ParkingLotDemo.run(); // PubSubSystemDemo.run(); // RestaurantManagementDemo.run(); // RideSharingServiceDemo.run(); // SnakeAndLadderDemo.run(); // SocialNetworkingServiceDemo.run(); // SplitwiseDemo.run(); // StackOverflowDemo.run(); // TaskManagementSystemDemo.run(); // TicTacToeDemo.run(); // TrafficSignalSystemDemo.run(); // VendingMachineDemo.run(); // VotingSystemDemo.run(); } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/Aircraft.java ================================================ package airlinemanagementsystem; public class Aircraft { private final String tailNumber; private final String model; private final int totalSeats; public Aircraft(String tailNumber, String model, int totalSeats) { this.tailNumber = tailNumber; this.model = model; this.totalSeats = totalSeats; } public String getTailNumber() { return tailNumber; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/AirlineManagementSystem.java ================================================ package airlinemanagementsystem; import airlinemanagementsystem.booking.Booking; import airlinemanagementsystem.booking.BookingManager; import airlinemanagementsystem.flight.Flight; import airlinemanagementsystem.flight.FlightSearch; import airlinemanagementsystem.payment.Payment; import airlinemanagementsystem.payment.PaymentProcessor; import airlinemanagementsystem.seat.Seat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; public class AirlineManagementSystem { private final Map flights; private final Map aircrafts; private final Map passengers; private final FlightSearch flightSearch; private final BookingManager bookingManager; private final PaymentProcessor paymentProcessor; public AirlineManagementSystem() { flights = new HashMap<>(); aircrafts = new HashMap<>(); passengers = new HashMap<>(); flightSearch = new FlightSearch(); bookingManager = BookingManager.getInstance(); paymentProcessor = PaymentProcessor.getInstance(); } public Passenger addPassenger(String name, String email) { Passenger passenger = new Passenger(name, email); passengers.put(passenger.getId(), passenger); return passenger; } public Aircraft addAircraft(String tailNumber, String model, int totalSeats) { Aircraft aircraft = new Aircraft(tailNumber, model, totalSeats); aircrafts.put(tailNumber, aircraft); return aircraft; } public Flight addFlight(String source, String destination, LocalDateTime departure, LocalDateTime arrival, String aircraftNumber) { Aircraft aircraft = aircrafts.get(aircraftNumber); Flight flight = new Flight(source, destination, departure, arrival, aircraft); flights.put(flight.getFlightNumber(), flight); flightSearch.addFlight(flight); return flight; } public List searchFlights(String source, String destination, LocalDate date) { return flightSearch.searchFlights(source, destination, date); } public Booking bookFlight(String flightNumber, String passengerId, Seat seat, double price) { Flight flight = flights.get(flightNumber); Passenger passenger = passengers.get(passengerId); return bookingManager.createBooking(flight, passenger, seat, price); } public void cancelBooking(String bookingNumber) { bookingManager.cancelBooking(bookingNumber); } public void processPayment(Payment payment) { paymentProcessor.processPayment(payment); } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/AirlineManagementSystemDemo.java ================================================ package airlinemanagementsystem; import airlinemanagementsystem.booking.Booking; import airlinemanagementsystem.flight.Flight; import airlinemanagementsystem.seat.Seat; import airlinemanagementsystem.seat.SeatType; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; public class AirlineManagementSystemDemo { public static void run() { AirlineManagementSystem airlineManagementSystem = new AirlineManagementSystem(); // Create passengers Passenger passenger1 = airlineManagementSystem.addPassenger("John Doe", "john@example.com"); Passenger passenger2 = airlineManagementSystem.addPassenger("John Smith", "smith@example.com"); // Create aircrafts Aircraft aircraft1 = airlineManagementSystem.addAircraft("A001", "Boeing 747", 300); Aircraft aircraft2 = airlineManagementSystem.addAircraft("A002", "Airbus A380", 500); // Create flights LocalDateTime departureTime1 = LocalDateTime.now().plusDays(1); LocalDateTime arrivalTime1 = departureTime1.plusHours(2); Flight flight1 = airlineManagementSystem.addFlight("New York", "London", departureTime1, arrivalTime1, aircraft1.getTailNumber()); LocalDateTime departureTime2 = LocalDateTime.now().plusDays(3); LocalDateTime arrivalTime2 = departureTime2.plusHours(5); Flight flight2 = airlineManagementSystem.addFlight("Paris", "Tokyo", departureTime2, arrivalTime2, aircraft2.getTailNumber()); // Search flights List searchResults = airlineManagementSystem.searchFlights("New York", "London", LocalDate.now().plusDays(1)); System.out.println("Search Results:"); for (Flight flight : searchResults) { System.out.println("Flight: " + flight.getFlightNumber() + " - " + flight.getSource() + " to " + flight.getDestination()); } // Book a flight Booking booking = airlineManagementSystem.bookFlight(flight1.getFlightNumber(), passenger1.getId(), new Seat("25A", SeatType.ECONOMY), 100); if (booking != null) { System.out.println("Booking successful. Booking ID: " + booking.getId()); } else { System.out.println("Booking failed."); } // Cancel a booking airlineManagementSystem.cancelBooking(booking.getId()); System.out.println("Booking cancelled."); } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/Passenger.java ================================================ package airlinemanagementsystem; import java.util.UUID; public class Passenger { private final String id; private final String name; private final String email; public Passenger(String name, String email) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; } public String getId() { return id; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/README.md ================================================ # Airline Management System (LLD) ## Problem Statement Design and implement an Airline Management System that allows users to book flights, manage passengers, handle seat assignments, process payments, and track bookings and flights. --- ## Requirements - **Flight Management:** The system manages flights, each with a unique flight number, aircraft, source, destination, and schedule. - **Aircraft Management:** Each flight is associated with an aircraft, which has a model and a set of seats. - **Seat Management:** The system manages seat assignments and availability for each flight. - **Passenger Management:** Passengers can be added, updated, and associated with bookings. - **Booking Management:** Users can book flights, and the system tracks bookings, assigned seats, and passengers. - **Payment Processing:** The system processes payments for bookings. - **Extensibility:** Easy to add new features such as loyalty programs, meal selection, or multi-leg journeys. --- ## Core Entities - **AirlineManagementSystem:** Main class that manages flights, bookings, passengers, and payments. - **Flight:** Represents a flight with flight number, aircraft, source, destination, schedule, and seats. - **Aircraft:** Represents an aircraft with a model and a set of seats. - **Seat:** Represents a seat on an aircraft, with seat number, class, and availability. - **Passenger:** Represents a user with ID, name, and contact details. - **Booking:** Represents a booking, including user(s), flight, seat(s), and payment. - **Payment (in payment/):** Represents a payment transaction for a booking. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/airlinemanagementsystem-class-diagram.png) ### 1. AirlineManagementSystem - **Fields:** List flights, List bookings, List passengers, PaymentProcessor paymentProcessor - **Methods:** addFlight(Flight), addPassenger(Passenger), bookFlight(Passenger, Flight, Seat, Payment), getAvailableSeats(Flight), getBookings(Passenger), etc. ### 2. Flight (in flight/) - **Fields:** String flightNumber, Aircraft aircraft, String source, String destination, Date schedule, List seats ### 3. Aircraft - **Fields:** String model, List seats ### 4. Seat (in seat/) - **Fields:** String seatNumber, String seatClass, boolean isAvailable ### 5. Passenger - **Fields:** int id, String name, String contactInfo ### 6. Booking (in booking/) - **Fields:** int id, Passenger user, Flight flight, List seats, Payment payment ### 7. Payment (in payment/) - **Fields:** int id, double amount, String method, PaymentStatus status ### 8. PaymentProcessor (in payment/) - **Methods:** process(Payment), validate(Payment) --- ## Example Usage ```java AirlineManagementSystem system = new AirlineManagementSystem(); Aircraft aircraft = new Aircraft("Boeing 737", seatList); Flight flight = new Flight("AI101", aircraft, "DEL", "BOM", new Date(), seatList); system.addFlight(flight); Passenger alice = new Passenger(1, "Alice", "alice@email.com"); system.addPassenger(alice); Seat seat = flight.getAvailableSeats().get(0); Payment payment = new Payment(1, 5000.0, "CREDIT_CARD"); system.bookFlight(alice, flight, seat, payment); ``` --- ## Demo See `AirlineManagementSystemDemo.java` for a sample usage and simulation of the airline management system. --- ## Extending the Framework - **Add loyalty programs:** Track frequent flyer points and rewards. - **Add meal selection:** Allow passengers to select meals during booking. - **Add multi-leg journeys:** Support bookings with multiple connecting flights. --- ================================================ FILE: solutions/java/src/airlinemanagementsystem/booking/Booking.java ================================================ package airlinemanagementsystem.booking; import airlinemanagementsystem.flight.Flight; import airlinemanagementsystem.Passenger; import airlinemanagementsystem.seat.Seat; import java.util.UUID; public class Booking { private final String id; private final Flight flight; private final Passenger passenger; private final Seat seat; private final double price; private BookingStatus status; public Booking(Flight flight, Passenger passenger, Seat seat, double price) { this.id = UUID.randomUUID().toString(); this.flight = flight; this.passenger = passenger; this.seat = seat; this.price = price; this.status = BookingStatus.CONFIRMED; } public void cancel() { status = BookingStatus.CANCELLED; seat.release(); } public String getId() { return id; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/booking/BookingManager.java ================================================ package airlinemanagementsystem.booking; import airlinemanagementsystem.flight.Flight; import airlinemanagementsystem.Passenger; import airlinemanagementsystem.seat.Seat; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class BookingManager { private static BookingManager instance; private final Map bookings; private final Object lock = new Object(); private BookingManager() { bookings = new HashMap<>(); } public static synchronized BookingManager getInstance() { if (instance == null) { instance = new BookingManager(); } return instance; } public Booking createBooking(Flight flight, Passenger passenger, Seat seat, double price) { String bookingNumber = UUID.randomUUID().toString(); Booking booking = new Booking(flight, passenger, seat, price); synchronized (lock) { bookings.put(bookingNumber, booking); } return booking; } public void cancelBooking(String bookingNumber) { synchronized (lock) { Booking booking = bookings.get(bookingNumber); if (booking != null) { booking.cancel(); } } } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/booking/BookingStatus.java ================================================ package airlinemanagementsystem.booking; public enum BookingStatus { CONFIRMED, CANCELLED, PENDING, EXPIRED } ================================================ FILE: solutions/java/src/airlinemanagementsystem/flight/Flight.java ================================================ package airlinemanagementsystem.flight; import airlinemanagementsystem.Aircraft; import airlinemanagementsystem.seat.Seat; import java.time.LocalDateTime; import java.util.*; public class Flight { private final String flightNumber; private final String source; private final String destination; private final LocalDateTime departureTime; private final LocalDateTime arrivalTime; private final FlightStatus status; private final Aircraft aircraft; private final Map seats; private final List availableSeats; public Flight(String source, String destination, LocalDateTime departureTime, LocalDateTime arrivalTime, Aircraft aircraft) { this.flightNumber = UUID.randomUUID().toString(); this.source = source; this.destination = destination; this.departureTime = departureTime; this.arrivalTime = arrivalTime; this.status = FlightStatus.ON_TIME; this.aircraft = aircraft; this.seats = new HashMap<>(); this.availableSeats = new ArrayList<>(); } public synchronized boolean isSeatAvailable(String seatNo) { Seat seat = seats.get(seatNo); return seat != null && !seat.isBooked(); } public synchronized void reserveSeat(String seatNo) { Seat seat = seats.get(seatNo); if (seat == null) throw new IllegalArgumentException("Invalid seat number"); seat.reserve(); } public synchronized void releaseSeat(String seatNo) { Seat seat = seats.get(seatNo); if (seat != null) seat.release(); } public String getSource() { return source; } public String getDestination() { return destination; } public LocalDateTime getDepartureTime() { return departureTime; } public String getFlightNumber() { return flightNumber; } public LocalDateTime getArrivalTime() { return arrivalTime; } public List getAvailableSeats() { return availableSeats; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/flight/FlightSearch.java ================================================ package airlinemanagementsystem.flight; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class FlightSearch { private final List flights; public FlightSearch() { this.flights = new ArrayList<>(); } public void addFlight(Flight flight) { flights.add(flight); } public List searchFlights(String source, String destination, LocalDate date) { return flights.stream() .filter(flight -> flight.getSource().equalsIgnoreCase(source) && flight.getDestination().equalsIgnoreCase(destination) && flight.getDepartureTime().toLocalDate().equals(date)) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/flight/FlightStatus.java ================================================ package airlinemanagementsystem.flight; public enum FlightStatus { ON_TIME, DELAYED, CANCELLED } ================================================ FILE: solutions/java/src/airlinemanagementsystem/payment/Payment.java ================================================ package airlinemanagementsystem.payment; public class Payment { private final String paymentId; private final String paymentMethod; private final double amount; private PaymentStatus status; public Payment(String paymentId, String paymentMethod, double amount) { this.paymentId = paymentId; this.paymentMethod = paymentMethod; this.amount = amount; this.status = PaymentStatus.PENDING; } public void processPayment() { // Process payment logic status = PaymentStatus.COMPLETED; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/payment/PaymentProcessor.java ================================================ package airlinemanagementsystem.payment; public class PaymentProcessor { private static PaymentProcessor instance; private PaymentProcessor() { } public static synchronized PaymentProcessor getInstance() { if (instance == null) { instance = new PaymentProcessor(); } return instance; } public void processPayment(Payment payment) { // Process payment using the selected payment method payment.processPayment(); } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/payment/PaymentStatus.java ================================================ package airlinemanagementsystem.payment; public enum PaymentStatus { PENDING, COMPLETED, FAILED, REFUNDED } ================================================ FILE: solutions/java/src/airlinemanagementsystem/seat/Seat.java ================================================ package airlinemanagementsystem.seat; public class Seat { private final String seatNumber; private final SeatType type; private SeatStatus status; public Seat(String seatNumber, SeatType type) { this.seatNumber = seatNumber; this.type = type; this.status = SeatStatus.AVAILABLE; } public String getSeatNumber() { return seatNumber; } public void reserve() { status = SeatStatus.RESERVED; } public void release() { status = SeatStatus.AVAILABLE; } public synchronized boolean isBooked() { return status == SeatStatus.OCCUPIED; } } ================================================ FILE: solutions/java/src/airlinemanagementsystem/seat/SeatStatus.java ================================================ package airlinemanagementsystem.seat; public enum SeatStatus { AVAILABLE, RESERVED, OCCUPIED } ================================================ FILE: solutions/java/src/airlinemanagementsystem/seat/SeatType.java ================================================ package airlinemanagementsystem.seat; public enum SeatType { ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST_CLASS } ================================================ FILE: solutions/java/src/atm/ATMDemo.java ================================================ package atm; import atm.enums.OperationType; public class ATMDemo { public static void main(String[] args) { ATMSystem atmSystem = ATMSystem.getInstance(); // Perform Check Balance operation atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("1234"); atmSystem.selectOperation(OperationType.CHECK_BALANCE); // $1000 // Perform Withdraw Cash operation atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("1234"); atmSystem.selectOperation(OperationType.WITHDRAW_CASH, 570); // Perform Deposit Cash operation atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("1234"); atmSystem.selectOperation(OperationType.DEPOSIT_CASH, 200); // Perform Check Balance operation atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("1234"); atmSystem.selectOperation(OperationType.CHECK_BALANCE); // $630 // Perform Withdraw Cash more than balance atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("1234"); atmSystem.selectOperation(OperationType.WITHDRAW_CASH, 700); // Insufficient balance // Insert Incorrect PIN atmSystem.insertCard("1234-5678-9012-3456"); atmSystem.enterPin("3425"); } } ================================================ FILE: solutions/java/src/atm/ATMSystem.java ================================================ package atm; import atm.chainofresponsibility.DispenseChain; import atm.chainofresponsibility.NoteDispenser100; import atm.chainofresponsibility.NoteDispenser20; import atm.chainofresponsibility.NoteDispenser50; import atm.entities.BankService; import atm.entities.Card; import atm.entities.CashDispenser; import atm.enums.OperationType; import atm.state.ATMState; import atm.state.IdleState; import java.util.concurrent.atomic.AtomicLong; public class ATMSystem { private static ATMSystem INSTANCE; private final BankService bankService; private final CashDispenser cashDispenser; private static final AtomicLong transactionCounter = new AtomicLong(0); private ATMState currentState; private Card currentCard; private ATMSystem() { this.currentState = new IdleState(); this.bankService = new BankService(); // Setup the dispenser chain DispenseChain c1 = new NoteDispenser100(10); // 10 x $100 notes DispenseChain c2 = new NoteDispenser50(20); // 20 x $50 notes DispenseChain c3 = new NoteDispenser20(30); // 30 x $20 notes c1.setNextChain(c2); c2.setNextChain(c3); this.cashDispenser = new CashDispenser(c1); } public static ATMSystem getInstance() { if (INSTANCE == null) { INSTANCE = new ATMSystem(); } return INSTANCE; } public void changeState(ATMState newState) { this.currentState = newState; } public void setCurrentCard(Card card) { this.currentCard = card; } public void insertCard(String cardNumber) { currentState.insertCard(this, cardNumber); } public void enterPin(String pin) { currentState.enterPin(this, pin); } public void selectOperation(OperationType op, int... args) { currentState.selectOperation(this, op, args); } public Card getCard(String cardNumber) { return bankService.getCard(cardNumber); } public boolean authenticate(String pin) { return bankService.authenticate(currentCard, pin); } public void checkBalance() { double balance = bankService.getBalance(currentCard); System.out.printf("Your current account balance is: $%.2f%n", balance); } public void withdrawCash(int amount) { if (!cashDispenser.canDispenseCash(amount)) { throw new IllegalStateException("Insufficient cash available in the ATM."); } bankService.withdrawMoney(currentCard, amount); try { cashDispenser.dispenseCash(amount); } catch (Exception e) { bankService.depositMoney(currentCard, amount); // Deposit back if dispensing fails } } public void depositCash(int amount) { bankService.depositMoney(currentCard, amount); } public Card getCurrentCard() { return currentCard; } public BankService getBankService() { return bankService; } } ================================================ FILE: solutions/java/src/atm/README.md ================================================ # ATM System (LLD) ## Problem Statement Design and implement an ATM (Automated Teller Machine) system that allows users to perform basic banking operations such as balance inquiry, cash withdrawal, and cash deposit, with secure authentication and proper cash management. --- ## Requirements - **User Authentication:** Users must authenticate using a card and PIN. - **Balance Inquiry:** Users can check their account balance. - **Cash Withdrawal:** Users can withdraw cash if sufficient balance and cash are available. - **Cash Deposit:** Users can deposit cash into their account. - **Transaction Management:** The system records and processes transactions (withdrawal, deposit). - **Banking Service Integration:** The ATM interacts with a backend banking service to validate accounts and perform transactions. - **Cash Dispenser:** The ATM manages its own cash inventory and dispenses cash securely. - **Concurrency & Consistency:** The system handles concurrent access and ensures data consistency. - **User Interface:** The ATM provides a user-friendly interface for operations. - **Extensibility:** Easy to add new features such as mini-statements, fund transfers, or multi-currency support. --- ## Core Entities - **ATM:** Main class for ATM operations; interacts with `BankingService` and `CashDispenser`. - **Card:** Represents an ATM card with card number and PIN. - **Account:** Represents a bank account with account number and balance; supports debit and credit operations. - **Transaction (abstract):** Base class for transactions; extended by `WithdrawalTransaction` and `DepositTransaction`. - **WithdrawalTransaction / DepositTransaction:** Concrete transaction types for withdrawal and deposit. - **BankingService:** Manages bank accounts and processes transactions; uses thread-safe data structures. - **CashDispenser:** Manages the ATM's cash inventory and handles dispensing; ensures thread safety. - **ATMDemo:** Demonstrates the usage of the ATM system with sample accounts and operations. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/atmSystem-class-diagram.png) ### 1. ATM - **Fields:** BankingService bankService, CashDispenser cashDispenser - **Methods:** authenticateUser(Card), checkBalance(String accountNumber), withdrawCash(String accountNumber, double amount), depositCash(String accountNumber, double amount) ### 2. Card - **Fields:** String cardNumber, String pin ### 3. Account - **Fields:** String accountNumber, double balance - **Methods:** debit(double), credit(double), getBalance() ### 4. Transaction (abstract) - **Fields:** String accountNumber, double amount, Date date - **Methods:** process() ### 5. WithdrawalTransaction / DepositTransaction - **Inherits:** Transaction - **Methods:** process() ### 6. BankingService - **Fields:** Map accounts - **Methods:** createAccount(String, double), getAccount(String), processTransaction(Transaction) ### 7. CashDispenser - **Fields:** double cashAvailable - **Methods:** dispenseCash(double), addCash(double), getCashAvailable() ### 8. ATMDemo - **Methods:** run() — demonstrates sample ATM operations --- ## Example Usage ```java BankingService bankService = new BankingService(); CashDispenser cashDispenser = new CashDispenser(10000); ATM atmSystem = new ATM(bankService, cashDispenser); bankService.createAccount("1234567890", 1000.0); Card card = new Card("1234567890", "1234"); atmSystem.authenticateUser(card); double balance = atmSystem.checkBalance("1234567890"); atmSystem.withdrawCash("1234567890", 500.0); atmSystem.depositCash("1234567890", 200.0); ``` --- ## Demo See `ATMDemo.java` for a sample usage and simulation of the ATM system. --- ## Extending the Framework - **Add mini-statements:** Show recent transactions. - **Add fund transfers:** Allow transfers between accounts. - **Add multi-currency support:** Handle different currencies and conversions. --- ================================================ FILE: solutions/java/src/atm/chainofresponsibility/DispenseChain.java ================================================ package atm.chainofresponsibility; // The chain interface public interface DispenseChain { void setNextChain(DispenseChain nextChain); void dispense(int amount); boolean canDispense(int amount); } ================================================ FILE: solutions/java/src/atm/chainofresponsibility/NoteDispenser.java ================================================ package atm.chainofresponsibility; abstract class NoteDispenser implements DispenseChain { private DispenseChain nextChain; private final int noteValue; private int numNotes; public NoteDispenser(int noteValue, int numNotes) { this.noteValue = noteValue; this.numNotes = numNotes; } @Override public void setNextChain(DispenseChain nextChain) { this.nextChain = nextChain; } @Override public synchronized void dispense(int amount) { if (amount >= noteValue) { int numToDispense = Math.min(amount / noteValue, this.numNotes); int remainingAmount = amount - (numToDispense * noteValue); if (numToDispense > 0) { System.out.println("Dispensing " + numToDispense + " x $" + noteValue + " note(s)"); this.numNotes -= numToDispense; } if (remainingAmount > 0 && this.nextChain != null) { this.nextChain.dispense(remainingAmount); } } else if (this.nextChain != null) { this.nextChain.dispense(amount); } } @Override public synchronized boolean canDispense(int amount) { if (amount < 0) return false; if (amount == 0) return true; int numToUse = Math.min(amount / noteValue, this.numNotes); int remainingAmount = amount - (numToUse * noteValue); if (remainingAmount == 0) return true; if (this.nextChain != null) { return this.nextChain.canDispense(remainingAmount); } return false; } } ================================================ FILE: solutions/java/src/atm/chainofresponsibility/NoteDispenser100.java ================================================ package atm.chainofresponsibility; public class NoteDispenser100 extends NoteDispenser{ public NoteDispenser100(int numNotes) { super(100, numNotes); } } ================================================ FILE: solutions/java/src/atm/chainofresponsibility/NoteDispenser20.java ================================================ package atm.chainofresponsibility; public class NoteDispenser20 extends NoteDispenser{ public NoteDispenser20(int numNotes) { super(20, numNotes); } } ================================================ FILE: solutions/java/src/atm/chainofresponsibility/NoteDispenser50.java ================================================ package atm.chainofresponsibility; public class NoteDispenser50 extends NoteDispenser{ public NoteDispenser50(int numNotes) { super(50, numNotes); } } ================================================ FILE: solutions/java/src/atm/entities/Account.java ================================================ package atm.entities; import java.util.HashMap; import java.util.Map; public class Account { private final String accountNumber; private double balance; private Map cards; public Account(String accountNumber, double balance) { this.accountNumber = accountNumber; this.balance = balance; this.cards = new HashMap<>(); } public String getAccountNumber() { return accountNumber; } public double getBalance() { return balance; } public Map getCards() { return cards; } public synchronized void deposit(double amount) { balance += amount; } public synchronized boolean withdraw(double amount) { if (balance >= amount) { balance -= amount; return true; } return false; } } ================================================ FILE: solutions/java/src/atm/entities/BankService.java ================================================ package atm.entities; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class BankService { private final Map accounts = new ConcurrentHashMap<>(); private final Map cards = new ConcurrentHashMap<>(); private final Map cardAccountMap = new ConcurrentHashMap<>(); public BankService() { // Create sample accounts and cards Account account1 = createAccount("1234567890", 1000.0); Card card1 = createCard("1234-5678-9012-3456", "1234"); linkCardToAccount(card1, account1); Account account2 = createAccount("9876543210", 500.0); Card card2 = createCard("9876-5432-1098-7654", "4321"); linkCardToAccount(card2, account2); } public Account createAccount(String accountNumber, double initialBalance) { Account account = new Account(accountNumber, initialBalance); accounts.put(accountNumber, account); return account; } public Card createCard(String cardNumber, String pin) { Card card = new Card(cardNumber, pin); cards.put(cardNumber, card); return card; } public boolean authenticate(Card card, String pin) { return card.getPin().equals(pin); } public Card getCard(String cardNumber) { return cards.getOrDefault(cardNumber, null); } public double getBalance(Card card) { return cardAccountMap.get(card).getBalance(); } public void withdrawMoney(Card card, double amount) { cardAccountMap.get(card).withdraw(amount); } public void depositMoney(Card card, double amount) { cardAccountMap.get(card).deposit(amount); } public void linkCardToAccount(Card card, Account account) { account.getCards().put(card.getCardNumber(), card); cardAccountMap.put(card, account); } } ================================================ FILE: solutions/java/src/atm/entities/Card.java ================================================ package atm.entities; public class Card { private final String cardNumber; private final String pin; public Card(String cardNumber, String pin) { this.cardNumber = cardNumber; this.pin = pin; } public String getCardNumber() { return cardNumber; } public String getPin() { return pin; } } ================================================ FILE: solutions/java/src/atm/entities/CashDispenser.java ================================================ package atm.entities; import atm.chainofresponsibility.DispenseChain; public class CashDispenser { private final DispenseChain chain; public CashDispenser(DispenseChain chain) { this.chain = chain; } public synchronized void dispenseCash(int amount) { chain.dispense(amount); } public synchronized boolean canDispenseCash(int amount) { if (amount % 10 != 0) { return false; } return chain.canDispense(amount); } } ================================================ FILE: solutions/java/src/atm/enums/OperationType.java ================================================ package atm.enums; public enum OperationType { CHECK_BALANCE, WITHDRAW_CASH, DEPOSIT_CASH } ================================================ FILE: solutions/java/src/atm/state/ATMState.java ================================================ package atm.state; import atm.ATMSystem; import atm.enums.OperationType; public interface ATMState { void insertCard(ATMSystem atmSystem, String cardNumber); void enterPin(ATMSystem atmSystem, String pin); void selectOperation(ATMSystem atmSystem, OperationType op, int... args); void ejectCard(ATMSystem atmSystem); } ================================================ FILE: solutions/java/src/atm/state/AuthenticatedState.java ================================================ package atm.state; import atm.ATMSystem; import atm.enums.OperationType; public class AuthenticatedState implements ATMState { @Override public void insertCard(ATMSystem atmSystem, String cardNumber) { System.out.println("Error: A card is already inserted and a session is active."); } @Override public void enterPin(ATMSystem atmSystem, String pin) { System.out.println("Error: PIN has already been entered and authenticated."); } @Override public void selectOperation(ATMSystem atmSystem, OperationType op, int... args) { // In a real UI, this would be a menu. Here we use a switch. switch (op) { case CHECK_BALANCE: atmSystem.checkBalance(); break; case WITHDRAW_CASH: if (args.length == 0 || args[0] <= 0) { System.out.println("Error: Invalid withdrawal amount specified."); break; } int amountToWithdraw = args[0]; double accountBalance = atmSystem.getBankService().getBalance(atmSystem.getCurrentCard()); if (amountToWithdraw > accountBalance) { System.out.println("Error: Insufficient balance."); break; } System.out.println("Processing withdrawal for $" + amountToWithdraw); // Delegate the complex withdrawal logic to the ATM's dedicated method atmSystem.withdrawCash(amountToWithdraw); break; case DEPOSIT_CASH: if (args.length == 0 || args[0] <= 0) { System.out.println("Error: Invalid withdrawal amount specified."); break; } int amountToDeposit = args[0]; System.out.println("Processing deposit for $" + amountToDeposit); atmSystem.depositCash(amountToDeposit); break; default: System.out.println("Error: Invalid operation selected."); break; } // End the session after one transaction System.out.println("Transaction complete."); ejectCard(atmSystem); } @Override public void ejectCard(ATMSystem atmSystem) { System.out.println("Ending session. Card has been ejected. Thank you for using our ATM."); atmSystem.setCurrentCard(null); atmSystem.changeState(new IdleState()); } } ================================================ FILE: solutions/java/src/atm/state/HasCardState.java ================================================ package atm.state; import atm.ATMSystem; import atm.enums.OperationType; public class HasCardState implements ATMState { @Override public void insertCard(ATMSystem atmSystem, String cardNumber) { System.out.println("Error: A card is already inserted. Cannot insert another card."); } @Override public void enterPin(ATMSystem atmSystem, String pin) { System.out.println("Authenticating PIN..."); boolean isAuthenticated = atmSystem.authenticate(pin);; if (isAuthenticated) { System.out.println("Authentication successful."); atmSystem.changeState(new AuthenticatedState()); } else { System.out.println("Authentication failed: Incorrect PIN."); ejectCard(atmSystem); } } @Override public void selectOperation(ATMSystem atmSystem, OperationType op, int... args) { System.out.println("Error: Please enter your PIN first to select an operation."); } @Override public void ejectCard(ATMSystem atmSystem) { System.out.println("Card has been ejected. Thank you for using our ATM."); atmSystem.setCurrentCard(null); atmSystem.changeState(new IdleState()); } } ================================================ FILE: solutions/java/src/atm/state/IdleState.java ================================================ package atm.state; import atm.ATMSystem; import atm.entities.Card; import atm.enums.OperationType; public class IdleState implements ATMState { @Override public void insertCard(ATMSystem atmSystem, String cardNumber) { System.out.println("\nCard has been inserted."); Card card = atmSystem.getCard(cardNumber); if (card == null) { ejectCard(atmSystem); } else { atmSystem.setCurrentCard(card); atmSystem.changeState(new HasCardState()); } } @Override public void enterPin(ATMSystem atmSystem, String pin) { System.out.println("Error: Please insert a card first."); } @Override public void selectOperation(ATMSystem atmSystem, OperationType op, int... args) { System.out.println("Error: Please insert a card first."); } @Override public void ejectCard(ATMSystem atmSystem) { System.out.println("Error: Card not found."); atmSystem.setCurrentCard(null); } } ================================================ FILE: solutions/java/src/carrentalsystem/Car.java ================================================ package carrentalsystem; public class Car { private final String make; private final String model; private final int year; private final String licensePlate; private final double rentalPricePerDay; private boolean available; public Car(String make, String model, int year, String licensePlate, double rentalPricePerDay) { this.make = make; this.model = model; this.year = year; this.licensePlate = licensePlate; this.rentalPricePerDay = rentalPricePerDay; this.available = true; } public double getRentalPricePerDay() { return rentalPricePerDay; } public String getLicensePlate() { return licensePlate; } public String getMake() { return make; } public String getModel() { return model; } public boolean isAvailable() { return available; } public void setAvailable(boolean available) { this.available = available; } } ================================================ FILE: solutions/java/src/carrentalsystem/CarRentalSystem.java ================================================ package carrentalsystem; import carrentalsystem.payment.CreditCardPaymentProcessor; import carrentalsystem.payment.PaymentProcessor; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class CarRentalSystem { private static CarRentalSystem instance = new CarRentalSystem(); private final Map cars; private final Map reservations; private final PaymentProcessor paymentProcessor; private CarRentalSystem() { cars = new ConcurrentHashMap<>(); reservations = new ConcurrentHashMap<>(); paymentProcessor = new CreditCardPaymentProcessor(); } public static CarRentalSystem getInstance() { return instance; } public void addCar(Car car) { cars.put(car.getLicensePlate(), car); } public void removeCar(String licensePlate) { cars.remove(licensePlate); } public List searchCars(String make, String model, LocalDate startDate, LocalDate endDate) { List availableCars = new ArrayList<>(); for (Car car : cars.values()) { if (car.getMake().equalsIgnoreCase(make) && car.getModel().equalsIgnoreCase(model) && car.isAvailable()) { if (isCarAvailable(car, startDate, endDate)) { availableCars.add(car); } } } return availableCars; } private boolean isCarAvailable(Car car, LocalDate startDate, LocalDate endDate) { for (Reservation reservation : reservations.values()) { if (reservation.getCar().equals(car)) { if (startDate.isBefore(reservation.getEndDate()) && endDate.isAfter(reservation.getStartDate())) { return false; } } } return true; } public synchronized Reservation makeReservation(Customer customer, Car car, LocalDate startDate, LocalDate endDate) { if (isCarAvailable(car, startDate, endDate)) { String reservationId = generateReservationId(); Reservation reservation = new Reservation(reservationId, customer, car, startDate, endDate); reservations.put(reservationId, reservation); car.setAvailable(false); return reservation; } return null; } public synchronized void cancelReservation(String reservationId) { Reservation reservation = reservations.remove(reservationId); if (reservation != null) { reservation.getCar().setAvailable(true); } } public boolean processPayment(Reservation reservation) { return paymentProcessor.processPayment(reservation.getTotalPrice()); } private String generateReservationId() { return "RES" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); } } ================================================ FILE: solutions/java/src/carrentalsystem/CarRentalSystemDemo.java ================================================ package carrentalsystem; import java.time.LocalDate; import java.util.List; public class CarRentalSystemDemo { public static void run() { CarRentalSystem carRentalSystem = CarRentalSystem.getInstance(); // Add cars to the rental system carRentalSystem.addCar(new Car("Toyota", "Camry", 2022, "ABC123", 50.0)); carRentalSystem.addCar(new Car("Honda", "Civic", 2021, "XYZ789", 45.0)); carRentalSystem.addCar(new Car("Ford", "Mustang", 2023, "DEF456", 80.0)); // Create customers Customer customer1 = new Customer("John Doe", "john@example.com", "DL1234"); // Make reservations LocalDate startDate = LocalDate.now(); LocalDate endDate = startDate.plusDays(3); List availableCars = carRentalSystem.searchCars("Toyota", "Camry", startDate, endDate); if (!availableCars.isEmpty()) { Car selectedCar = availableCars.getFirst(); Reservation reservation = carRentalSystem.makeReservation(customer1, selectedCar, startDate, endDate); if (reservation != null) { boolean paymentSuccess = carRentalSystem.processPayment(reservation); if (paymentSuccess) { System.out.println("Reservation successful. Reservation ID: " + reservation.getReservationId()); } else { System.out.println("Payment failed. Reservation canceled."); carRentalSystem.cancelReservation(reservation.getReservationId()); } } else { System.out.println("Selected car is not available for the given dates."); } } else { System.out.println("No available cars found for the given criteria."); } } } ================================================ FILE: solutions/java/src/carrentalsystem/CarStatus.java ================================================ package carrentalsystem; public enum CarStatus { AVAILABLE, BOOKED, MAINTENANCE } ================================================ FILE: solutions/java/src/carrentalsystem/CarType.java ================================================ package carrentalsystem; public enum CarType { SUV, SEDAN, HATCHBACK } ================================================ FILE: solutions/java/src/carrentalsystem/Customer.java ================================================ package carrentalsystem; public class Customer { private final String name; private final String contactInfo; private final String driversLicenseNumber; public Customer(String name, String contactInfo, String driversLicenseNumber) { this.name = name; this.contactInfo = contactInfo; this.driversLicenseNumber = driversLicenseNumber; } } ================================================ FILE: solutions/java/src/carrentalsystem/README.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/carrentalsystem-class-diagram.png) ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: solutions/java/src/carrentalsystem/Reservation.java ================================================ package carrentalsystem; import java.time.LocalDate; import java.time.temporal.ChronoUnit; public class Reservation { private final String reservationId; private final Customer customer; private final Car car; private final LocalDate startDate; private final LocalDate endDate; private final double totalPrice; public Reservation(String reservationId, Customer customer, Car car, LocalDate startDate, LocalDate endDate) { this.reservationId = reservationId; this.customer = customer; this.car = car; this.startDate = startDate; this.endDate = endDate; this.totalPrice = calculateTotalPrice(); } private double calculateTotalPrice() { long daysRented = ChronoUnit.DAYS.between(startDate, endDate) + 1; return car.getRentalPricePerDay() * daysRented; } public LocalDate getStartDate() { return startDate; } public LocalDate getEndDate() { return endDate; } public Car getCar() { return car; } public double getTotalPrice() { return totalPrice; } public String getReservationId() { return reservationId; } } ================================================ FILE: solutions/java/src/carrentalsystem/payment/CreditCardPaymentProcessor.java ================================================ package carrentalsystem.payment; public class CreditCardPaymentProcessor implements PaymentProcessor { @Override public boolean processPayment(double amount) { // Process credit card payment // ... return true; } } ================================================ FILE: solutions/java/src/carrentalsystem/payment/PayPalPaymentProcessor.java ================================================ package carrentalsystem.payment; public class PayPalPaymentProcessor implements PaymentProcessor { @Override public boolean processPayment(double amount) { // Process PayPal payment // ... return true; } } ================================================ FILE: solutions/java/src/carrentalsystem/payment/PaymentProcessor.java ================================================ package carrentalsystem.payment; public interface PaymentProcessor { boolean processPayment(double amount); } ================================================ FILE: solutions/java/src/chessgame/Board.java ================================================ package chessgame; import chessgame.pieces.*; public class Board { private final Cell[][] board; public Board() { board = new Cell[8][8]; for (int row = 0; row < 8; row++) for (int col = 0; col < 8; col++) board[row][col] = new Cell(row, col); setupPieces(); } private void setupPieces() { // Add pawns and main pieces for both sides for (int j = 0; j < 8; j++) { board[1][j].setPiece(new Pawn(Color.WHITE)); board[6][j].setPiece(new Pawn(Color.BLACK)); } // Initialize white pieces board[0][0].setPiece(new Rook(Color.WHITE)); board[0][1].setPiece(new Knight(Color.WHITE)); board[0][2].setPiece(new Bishop(Color.WHITE)); board[0][3].setPiece(new Queen(Color.WHITE)); board[0][4].setPiece(new King(Color.WHITE)); board[0][5].setPiece(new Bishop(Color.WHITE)); board[0][6].setPiece(new Knight(Color.WHITE)); board[0][7].setPiece(new Rook(Color.WHITE)); // Initialize black pieces board[7][0].setPiece(new Rook(Color.BLACK)); board[7][1].setPiece(new Knight(Color.BLACK)); board[7][2].setPiece(new Bishop(Color.BLACK)); board[7][3].setPiece(new Queen(Color.BLACK)); board[7][4].setPiece(new King(Color.BLACK)); board[7][5].setPiece(new Bishop(Color.BLACK)); board[7][6].setPiece(new Knight(Color.BLACK)); board[7][7].setPiece(new Rook(Color.BLACK)); } public Cell getCell(int row, int col) { return board[row][col]; } public synchronized boolean movePiece(Move move) { Cell from = move.getStart(), to = move.getEnd(); Piece piece = from.getPiece(); if (piece == null || !piece.canMove(this, from, to)) return false; to.setPiece(piece); from.setPiece(null); return true; } public Piece getPiece(int row, int col) { return board[row][col].getPiece(); } public void setPiece(int row, int col, Piece piece) { board[row][col].setPiece(piece); } public boolean isCheckmate(Color color) { // TODO: Implement checkmate logic return false; } public boolean isStalemate(Color color) { // TODO: Implement stalemate logic return false; } } ================================================ FILE: solutions/java/src/chessgame/Cell.java ================================================ package chessgame; import chessgame.pieces.Piece; public class Cell { private final int row, col; private Piece piece; public Cell(int row, int col) { this.row = row; this.col = col; } public boolean isOccupied() { return piece != null; } public Piece getPiece() { return piece; } public void setPiece(Piece piece) { this.piece = piece; } public int getRow() { return row; } public int getCol() { return col; } } ================================================ FILE: solutions/java/src/chessgame/ChessGame.java ================================================ package chessgame; import chessgame.pieces.Piece; import java.util.Scanner; public class ChessGame { private final Board board; private Player whitePlayer, blackPlayer; private Player currentPlayer; public ChessGame() { board = new Board(); } public void setPlayers(String playerWhiteName, String playerBlackName) { this.whitePlayer = new Player(playerWhiteName, Color.WHITE); this.blackPlayer = new Player(playerBlackName, Color.BLACK); this.currentPlayer = whitePlayer; } public void start() { // Game loop while (!isGameOver()) { Player player = currentPlayer; System.out.println(player.getName() + "'s turn."); // Get move from the player Move move = getPlayerMove(player); // Make the move on the board try { board.movePiece(move); } catch (InvalidMoveException e) { System.out.println(e.getMessage()); System.out.println("Try again!"); continue; } // Switch to the next player switchTurn(); } // Display game result displayResult(); } private void switchTurn() { currentPlayer = currentPlayer == whitePlayer ? blackPlayer : whitePlayer; } private boolean isGameOver() { return board.isCheckmate(whitePlayer.getColor()) || board.isCheckmate(blackPlayer.getColor()) || board.isStalemate(whitePlayer.getColor()) || board.isStalemate(blackPlayer.getColor()); } private Move getPlayerMove(Player player) { // For simplicity, let's assume the player enters the move via console input Scanner scanner = new Scanner(System.in); System.out.print("Enter source row: "); int sourceRow = scanner.nextInt(); System.out.print("Enter source column: "); int sourceCol = scanner.nextInt(); System.out.print("Enter destination row: "); int destRow = scanner.nextInt(); System.out.print("Enter destination column: "); int destCol = scanner.nextInt(); Piece piece = board.getPiece(sourceRow, sourceCol); if (piece == null || piece.getColor() != player.getColor()) { throw new IllegalArgumentException("Invalid piece selection!"); } return new Move(board.getCell(sourceRow, sourceCol), board.getCell(destRow, destCol)); } private void displayResult() { if (board.isCheckmate(Color.WHITE)) { System.out.println("Black wins by checkmate!"); } else if (board.isCheckmate(Color.BLACK)) { System.out.println("White wins by checkmate!"); } else if (board.isStalemate(Color.WHITE) || board.isStalemate(Color.BLACK)) { System.out.println("The game ends in a stalemate!"); } } } ================================================ FILE: solutions/java/src/chessgame/ChessGameDemo.java ================================================ package chessgame; public class ChessGameDemo { public static void run() { ChessGame chessGame = new ChessGame(); chessGame.setPlayers("Alice", "Bob"); chessGame.start(); } } ================================================ FILE: solutions/java/src/chessgame/Color.java ================================================ package chessgame; public enum Color { WHITE, BLACK } ================================================ FILE: solutions/java/src/chessgame/InvalidMoveException.java ================================================ package chessgame; public class InvalidMoveException extends RuntimeException { public InvalidMoveException(final String message) { super(message); } } ================================================ FILE: solutions/java/src/chessgame/Move.java ================================================ package chessgame; public class Move { private final Cell start; private final Cell end; public Move(Cell start, Cell end) { this.start = start; this.end = end; } public Cell getStart() { return start; } public Cell getEnd() { return end; } } ================================================ FILE: solutions/java/src/chessgame/Player.java ================================================ package chessgame; public class Player { private final String name; private final Color color; public Player(String name, Color color) { this.name = name; this.color = color; } public Color getColor() { return color; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/chessgame/README.md ================================================ # Chess Game (LLD) ## Problem Statement Design and implement a Chess Game that allows two players to play chess on a standard 8x8 board, enforces chess rules, validates moves, and determines game status (check, checkmate, stalemate). --- ## Requirements - **Two Players:** The game is played between two players (White and Black). - **Board:** The game uses a standard 8x8 chess board. - **Pieces:** All standard chess pieces (King, Queen, Rook, Bishop, Knight, Pawn) with their movement rules. - **Move Validation:** The game validates moves according to chess rules and prevents illegal moves. - **Turn Management:** Players alternate turns. - **Game Status:** The game detects check, checkmate, and stalemate. - **Exception Handling:** The system throws exceptions for invalid moves. - **Extensibility:** Easy to add features such as move history, undo, or AI opponent. --- ## Core Entities - **ChessGame:** Main class that manages the game flow, player turns, and game status. - **Board:** Represents the 8x8 chess board and manages piece positions. - **Cell:** Represents a cell on the board, with row, column, and piece. - **Player:** Represents a player with a name and color. - **Color (enum):** WHITE, BLACK. - **Move:** Represents a move from one cell to another. - **Piece (abstract, in pieces/):** Base class for all chess pieces. - **King, Queen, Rook, Bishop, Knight, Pawn (in pieces/):** Concrete piece classes with movement logic. - **InvalidMoveException:** Exception thrown for invalid moves. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/chessgame-class-diagram.png) ### 1. ChessGame - **Fields:** Board board, Player[] players, int currentPlayerIndex, boolean isGameOver - **Methods:** start(), makeMove(Move), switchPlayer(), isCheck(), isCheckmate(), isStalemate(), getCurrentPlayer() ### 2. Board - **Fields:** Cell[][] grid, List pieces - **Methods:** getCell(int row, int col), movePiece(Move), isCellOccupied(int row, int col), isCheck(Color), isCheckmate(Color), isStalemate(Color), printBoard() ### 3. Cell - **Fields:** int row, int col, Piece piece - **Methods:** getPiece(), setPiece(Piece), isEmpty() ### 4. Player - **Fields:** String name, Color color ### 5. Color (enum) - Values: WHITE, BLACK ### 6. Move - **Fields:** Cell from, Cell to ### 7. Piece (abstract, in pieces/) - **Fields:** Color color, Cell position - **Methods:** isValidMove(Board, Move), getPossibleMoves(Board) ### 8. InvalidMoveException - **Thrown:** When a move is not valid according to chess rules --- ## Example Usage ```java Player white = new Player("Alice", Color.WHITE); Player black = new Player("Bob", Color.BLACK); ChessGame game = new ChessGame(white, black); game.start(); Move move = new Move(game.getBoard().getCell(6, 4), game.getBoard().getCell(4, 4)); // e2 to e4 game.makeMove(move); ``` --- ## Demo See `ChessGameDemo.java` for a sample usage and simulation of the chess game. --- ## Extending the Framework - **Add move history:** Track all moves for undo/redo or replay. - **Add AI opponent:** Implement a computer player. - **Add GUI:** Build a graphical interface for the game. --- ================================================ FILE: solutions/java/src/chessgame/pieces/Bishop.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class Bishop extends Piece { public Bishop(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { int rowDiff = Math.abs(to.getRow() - from.getRow()); int colDiff = Math.abs(to.getCol() - from.getCol()); return (rowDiff == colDiff); } } ================================================ FILE: solutions/java/src/chessgame/pieces/King.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class King extends Piece { public King(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { int rowDiff = Math.abs(to.getRow() - from.getRow()); int colDiff = Math.abs(to.getCol()- from.getCol()); return (rowDiff <= 1 && colDiff <= 1); } } ================================================ FILE: solutions/java/src/chessgame/pieces/Knight.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class Knight extends Piece { public Knight(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { int rowDiff = Math.abs(to.getRow() - from.getRow()); int colDiff = Math.abs(to.getCol() - from.getCol()); return (rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2); } } ================================================ FILE: solutions/java/src/chessgame/pieces/Pawn.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class Pawn extends Piece { public Pawn(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { int rowDiff = to.getRow() - from.getRow(); int colDiff = Math.abs(to.getCol() - from.getCol()); if (color == Color.WHITE) { return (rowDiff == 1 && colDiff == 0) || (from.getRow() == 1 && rowDiff == 2 && colDiff == 0) || (rowDiff == 1 && colDiff == 1 && board.getPiece(to.getRow(), to.getCol()) != null); } else { return (rowDiff == -1 && colDiff == 0) || (from.getRow() == 6 && rowDiff == -2 && colDiff == 0) || (rowDiff == -1 && colDiff == 1 && board.getPiece(to.getRow(), to.getCol()) != null); } } } ================================================ FILE: solutions/java/src/chessgame/pieces/Piece.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public abstract class Piece { protected final Color color; public Piece(Color color) { this.color = color; } public abstract boolean canMove(Board board, Cell from, Cell to); public Color getColor() { return color; } } ================================================ FILE: solutions/java/src/chessgame/pieces/Queen.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class Queen extends Piece { public Queen(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { int rowDiff = Math.abs(to.getRow() - from.getRow()); int colDiff = Math.abs(to.getCol() - from.getCol()); return (rowDiff == colDiff) || (from.getRow() == to.getRow() || from.getCol() == to.getCol()); } } ================================================ FILE: solutions/java/src/chessgame/pieces/Rook.java ================================================ package chessgame.pieces; import chessgame.Board; import chessgame.Cell; import chessgame.Color; public class Rook extends Piece { public Rook(Color color) { super(color); } @Override public boolean canMove(Board board, Cell from, Cell to) { return (from.getRow() == to.getRow() || from.getCol() == to.getCol()); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/CoffeeVendingMachine.java ================================================ package coffeevendingmachine; import coffeevendingmachine.decorator.CaramelSyrupDecorator; import coffeevendingmachine.decorator.ExtraSugarDecorator; import coffeevendingmachine.enums.CoffeeType; import coffeevendingmachine.enums.ToppingType; import coffeevendingmachine.factory.CoffeeFactory; import coffeevendingmachine.state.ReadyState; import coffeevendingmachine.state.VendingMachineState; import coffeevendingmachine.decorator.Coffee; import java.util.List; public class CoffeeVendingMachine { private static final CoffeeVendingMachine INSTANCE = new CoffeeVendingMachine(); private VendingMachineState state; private Coffee selectedCoffee; private int moneyInserted; private CoffeeVendingMachine() { this.state = new ReadyState(); this.moneyInserted = 0; } public static CoffeeVendingMachine getInstance() { return INSTANCE; } // --- Actions delegated to the current state --- public void selectCoffee(CoffeeType type, List toppings) { // 1. Create the base coffee using the factory Coffee coffee = CoffeeFactory.createCoffee(type); // 2. Wrap it with decorators for (ToppingType topping : toppings) { switch (topping) { case EXTRA_SUGAR: coffee = new ExtraSugarDecorator(coffee); break; case CARAMEL_SYRUP: coffee = new CaramelSyrupDecorator(coffee); break; } } // Let the state handle the rest this.state.selectCoffee(this, coffee); } public void insertMoney(int amount) { state.insertMoney(this, amount); } public void dispenseCoffee() { state.dispenseCoffee(this); } public void cancel() { state.cancel(this); } // --- Getters and Setters used by State objects --- public void setState(VendingMachineState state) { this.state = state; } public VendingMachineState getState() { return state; } public void setSelectedCoffee(Coffee selectedCoffee) { this.selectedCoffee = selectedCoffee; } public Coffee getSelectedCoffee() { return selectedCoffee; } public void setMoneyInserted(int moneyInserted) { this.moneyInserted = moneyInserted; } public int getMoneyInserted() { return moneyInserted; } public void reset() { this.selectedCoffee = null; this.moneyInserted = 0; } public Map showIngredientsMap() { return ingredientStore.getAllIngredients(); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/CoffeeVendingMachineDemo.java ================================================ package coffeevendingmachine; import coffeevendingmachine.enums.CoffeeType; import coffeevendingmachine.enums.Ingredient; import coffeevendingmachine.enums.ToppingType; import java.util.List; public class CoffeeVendingMachineDemo { public static void main(String[] args) { CoffeeVendingMachine machine = CoffeeVendingMachine.getInstance(); Inventory inventory = Inventory.getInstance(); // --- Initial setup: Refill inventory --- System.out.println("=== Initializing Vending Machine ==="); inventory.addStock(Ingredient.COFFEE_BEANS, 50); inventory.addStock(Ingredient.WATER, 500); inventory.addStock(Ingredient.MILK, 200); inventory.addStock(Ingredient.SUGAR, 100); inventory.addStock(Ingredient.CARAMEL_SYRUP, 50); inventory.printInventory(); // --- Scenario 1: Successful Purchase of a Latte --- System.out.println("\n--- SCENARIO 1: Buy a Latte (Success) ---"); machine.selectCoffee(CoffeeType.LATTE, List.of()); machine.insertMoney(200); machine.insertMoney(50); // Total 250, price is 220 machine.dispenseCoffee(); inventory.printInventory(); // --- Scenario 2: Purchase with Insufficient Funds & Cancellation --- System.out.println("\n--- SCENARIO 2: Buy Espresso (Insufficient Funds & Cancel) ---"); machine.selectCoffee(CoffeeType.ESPRESSO, List.of()); machine.insertMoney(100); // Price is 150 machine.dispenseCoffee(); // Should fail machine.cancel(); // Should refund 100 inventory.printInventory(); // Should be unchanged // --- Scenario 3: Attempt to Buy with Insufficient Ingredients --- System.out.println("\n--- SCENARIO 3: Buy Cappuccino (Out of Milk) ---"); inventory.printInventory(); machine.selectCoffee(CoffeeType.CAPPUCCINO, List.of(ToppingType.CARAMEL_SYRUP, ToppingType.EXTRA_SUGAR)); machine.insertMoney(300); machine.dispenseCoffee(); // Should fail and refund inventory.printInventory(); // --- Refill and final test --- System.out.println("\n--- REFILLING AND FINAL TEST ---"); inventory.addStock(Ingredient.MILK, 200); inventory.printInventory(); machine.selectCoffee(CoffeeType.LATTE, List.of(ToppingType.CARAMEL_SYRUP)); machine.insertMoney(250); machine.dispenseCoffee(); inventory.printInventory(); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/Inventory.java ================================================ package coffeevendingmachine; import coffeevendingmachine.enums.Ingredient; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Inventory { private static final Inventory INSTANCE = new Inventory(); private final Map stock = new ConcurrentHashMap<>(); private Inventory() { // Private constructor to prevent instantiation } public static Inventory getInstance() { return INSTANCE; } public void addStock(Ingredient ingredient, int quantity) { stock.put(ingredient, stock.getOrDefault(ingredient, 0) + quantity); } public boolean hasIngredients(Map recipe) { return recipe.entrySet().stream() .allMatch(entry -> stock.getOrDefault(entry.getKey(), 0) >= entry.getValue()); } public synchronized void deductIngredients(Map recipe) { if (!hasIngredients(recipe)) { System.err.println("Not enough ingredients to make coffee."); return; } recipe.forEach((ingredient, quantity) -> stock.put(ingredient, stock.get(ingredient) - quantity)); } public void printInventory() { System.out.println("--- Current Inventory ---"); stock.forEach((key, value) -> System.out.println(key + ": " + value)); System.out.println("-------------------------"); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/README.md ================================================ # Coffee Vending Machine (LLD) ## Problem Statement Design and implement a Coffee Vending Machine system that can serve different types of coffee, manage ingredient inventory, process payments, and handle user interactions such as selecting coffee and refilling ingredients. --- ## Requirements - **Multiple Coffee Types:** The machine should support multiple coffee recipes (e.g., Espresso, Latte, Cappuccino). - **Ingredient Management:** The machine should track and manage ingredient levels, and prevent dispensing if ingredients are insufficient. - **Payment Processing:** The machine should process payments before dispensing coffee. - **Refill Ingredients:** The machine should allow refilling of ingredients. - **Extensibility:** Easy to add new coffee types or payment methods. --- ## Core Entities - **CoffeeVendingMachine:** Main class that manages the overall operation, user interaction, and coordinates other components. - **CoffeeRecipe:** Represents a coffee recipe, including required ingredients and their quantities. - **IngredientStore:** Manages the inventory of ingredients, supports checking and refilling. - **Dispenser:** Handles the dispensing of coffee after successful payment and ingredient check. - **PaymentProcessor:** Handles payment logic and validation. - **Payment:** Represents a payment transaction. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/coffeevendingmachine-class-diagram.png) ### 1. CoffeeVendingMachine - **Fields:** ingredientStore, paymentProcessor, Map recipes, Dispenser - **Methods:** selectCoffee(String), makeCoffee(String, Payment), refillIngredient(String, int), addRecipe(CoffeeRecipe), etc. ### 2. CoffeeRecipe - **Fields:** name, Map ingredients - **Methods:** getName(), getIngredients() ### 3. IngredientStore - **Fields:** Map ingredientLevels - **Methods:** hasIngredients(Map), useIngredients(Map), refill(String, int), getLevel(String) ### 4. Dispenser - **Methods:** dispense(String) ### 5. PaymentProcessor - **Methods:** processPayment(Payment) ### 6. Payment - **Fields:** amount, paymentType, etc. --- ## Design Patterns Used - **Strategy Pattern:** (Conceptually) for supporting different payment methods or coffee recipes. - **Separation of Concerns:** Each class has a single responsibility (inventory, payment, dispensing, etc.). --- ## Example Usage ```java CoffeeVendingMachine machine = new CoffeeVendingMachine(); machine.addRecipe(new CoffeeRecipe("Espresso", Map.of("CoffeeBeans", 10, "Water", 30))); machine.refillIngredient("CoffeeBeans", 100); machine.refillIngredient("Water", 200); Payment payment = new Payment(50, "CASH"); machine.makeCoffee("Espresso", payment); ``` --- ## Demo See `CoffeeVendingMachineDemo.java` for a sample usage and simulation of the coffee vending machine. --- ## Extending the Framework - **Add new coffee types:** Create new `CoffeeRecipe` instances and add them to the machine. - **Add new payment methods:** Extend `PaymentProcessor` to support new payment types. - **Add new ingredients:** Update `IngredientStore` and recipes as needed. --- ================================================ FILE: solutions/java/src/coffeevendingmachine/decorator/CaramelSyrupDecorator.java ================================================ package coffeevendingmachine.decorator; import coffeevendingmachine.enums.Ingredient; import java.util.HashMap; import java.util.Map; public class CaramelSyrupDecorator extends CoffeeDecorator { private static final int COST = 30; private static final Map RECIPE_ADDITION = Map.of(Ingredient.CARAMEL_SYRUP, 10); public CaramelSyrupDecorator(Coffee coffee) { super(coffee); } @Override public String getCoffeeType() { return decoratedCoffee.getCoffeeType() + ", Caramel Syrup"; } @Override public int getPrice() { return decoratedCoffee.getPrice() + COST; } @Override public Map getRecipe() { Map newRecipe = new HashMap<>(decoratedCoffee.getRecipe()); RECIPE_ADDITION.forEach((ingredient, qty) -> newRecipe.merge(ingredient, qty, Integer::sum)); return newRecipe; } @Override public void prepare() { // First, prepare the underlying coffee (e.g., the Latte with Sugar) super.prepare(); // Then, add the specific step for this decorator System.out.println("- Drizzling Caramel Syrup on top."); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/decorator/Coffee.java ================================================ package coffeevendingmachine.decorator; import coffeevendingmachine.enums.Ingredient; import java.util.Map; public abstract class Coffee { protected String coffeeType = "Unknown Coffee"; public String getCoffeeType() { return coffeeType; } // The Template Method public void prepare() { System.out.println("\nPreparing your " + this.getCoffeeType() + "..."); grindBeans(); brew(); addCondiments(); // The "hook" for base coffee types pourIntoCup(); System.out.println(this.getCoffeeType() + " is ready!"); } // Common steps private void grindBeans() { System.out.println("- Grinding fresh coffee beans."); } private void brew() { System.out.println("- Brewing coffee with hot water."); } private void pourIntoCup() { System.out.println("- Pouring into a cup."); } // Abstract step to be implemented by subclasses protected abstract void addCondiments(); public abstract int getPrice(); public abstract Map getRecipe(); } ================================================ FILE: solutions/java/src/coffeevendingmachine/decorator/CoffeeDecorator.java ================================================ package coffeevendingmachine.decorator; import coffeevendingmachine.enums.Ingredient; import java.util.Map; public abstract class CoffeeDecorator extends Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; } // Delegate calls to the wrapped object. // Concrete decorators will override these to add their own logic. @Override public int getPrice() { return decoratedCoffee.getPrice(); } @Override public Map getRecipe() { return decoratedCoffee.getRecipe(); } @Override protected void addCondiments() { decoratedCoffee.addCondiments(); } @Override public void prepare() { decoratedCoffee.prepare(); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/decorator/ExtraSugarDecorator.java ================================================ package coffeevendingmachine.decorator; import coffeevendingmachine.enums.Ingredient; import java.util.HashMap; import java.util.Map; public class ExtraSugarDecorator extends CoffeeDecorator { private static final int COST = 10; private static final Map RECIPE_ADDITION = Map.of(Ingredient.SUGAR, 1); public ExtraSugarDecorator(Coffee coffee) { super(coffee); } @Override public String getCoffeeType() { return decoratedCoffee.getCoffeeType() + ", Extra Sugar"; } @Override public int getPrice() { return decoratedCoffee.getPrice() + COST; } @Override public Map getRecipe() { // Merge the recipes Map newRecipe = new HashMap<>(decoratedCoffee.getRecipe()); RECIPE_ADDITION.forEach((ingredient, qty) -> newRecipe.merge(ingredient, qty, Integer::sum)); return newRecipe; } @Override public void prepare() { super.prepare(); System.out.println("- Stirring in Extra Sugar."); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/enums/CoffeeType.java ================================================ package coffeevendingmachine.enums; public enum CoffeeType { ESPRESSO, LATTE, CAPPUCCINO; } ================================================ FILE: solutions/java/src/coffeevendingmachine/enums/Ingredient.java ================================================ package coffeevendingmachine.enums; public enum Ingredient { COFFEE_BEANS, MILK, SUGAR, WATER, CARAMEL_SYRUP } ================================================ FILE: solutions/java/src/coffeevendingmachine/enums/ToppingType.java ================================================ package coffeevendingmachine.enums; public enum ToppingType { EXTRA_SUGAR, CARAMEL_SYRUP } ================================================ FILE: solutions/java/src/coffeevendingmachine/factory/CoffeeFactory.java ================================================ package coffeevendingmachine.factory; import coffeevendingmachine.enums.CoffeeType; import coffeevendingmachine.templatemethod.Cappuccino; import coffeevendingmachine.decorator.Coffee; import coffeevendingmachine.templatemethod.Espresso; import coffeevendingmachine.templatemethod.Latte; public class CoffeeFactory { public static Coffee createCoffee(CoffeeType type) { switch (type) { case ESPRESSO: return new Espresso(); case LATTE: return new Latte(); case CAPPUCCINO: return new Cappuccino(); default: throw new IllegalArgumentException("Unsupported coffee type: " + type); } } } ================================================ FILE: solutions/java/src/coffeevendingmachine/state/OutOfIngredientState.java ================================================ package coffeevendingmachine.state; import coffeevendingmachine.CoffeeVendingMachine; import coffeevendingmachine.decorator.Coffee; public class OutOfIngredientState implements VendingMachineState { @Override public void selectCoffee(CoffeeVendingMachine m, Coffee c) { System.out.println("Sorry, the machine is out of ingredients."); } @Override public void insertMoney(CoffeeVendingMachine m, int a) { System.out.println("Sorry, the machine is out of ingredients. Money refunded."); } @Override public void dispenseCoffee(CoffeeVendingMachine m) { System.out.println("Sorry, the machine is out of ingredients."); } @Override public void cancel(CoffeeVendingMachine machine) { System.out.println("Refunding " + machine.getMoneyInserted()); machine.reset(); machine.setState(new ReadyState()); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/state/PaidState.java ================================================ package coffeevendingmachine.state; import coffeevendingmachine.CoffeeVendingMachine; import coffeevendingmachine.Inventory; import coffeevendingmachine.decorator.Coffee; public class PaidState implements VendingMachineState { @Override public void selectCoffee(CoffeeVendingMachine m, Coffee c) { System.out.println("Cannot select another coffee now."); } @Override public void insertMoney(CoffeeVendingMachine m, int a) { System.out.println("Already paid. Please wait for your coffee."); } @Override public void dispenseCoffee(CoffeeVendingMachine machine) { Inventory inventory = Inventory.getInstance(); Coffee coffeeToDispense = machine.getSelectedCoffee(); if (!inventory.hasIngredients(machine.getSelectedCoffee().getRecipe())) { System.out.println("Sorry, out of ingredients for " + machine.getSelectedCoffee().getCoffeeType()); machine.setState(new OutOfIngredientState()); machine.getState().cancel(machine); return; } inventory.deductIngredients(machine.getSelectedCoffee().getRecipe()); coffeeToDispense.prepare(); int change = machine.getMoneyInserted() - machine.getSelectedCoffee().getPrice(); if (change > 0) System.out.println("Returning change: " + change); machine.reset(); machine.setState(new ReadyState()); } @Override public void cancel(CoffeeVendingMachine m) { new SelectingState().cancel(m); // Same as in SelectingState } } ================================================ FILE: solutions/java/src/coffeevendingmachine/state/ReadyState.java ================================================ package coffeevendingmachine.state; import coffeevendingmachine.CoffeeVendingMachine; import coffeevendingmachine.decorator.Coffee; public class ReadyState implements VendingMachineState { @Override public void selectCoffee(CoffeeVendingMachine machine, Coffee coffee) { machine.setSelectedCoffee(coffee); machine.setState(new SelectingState()); System.out.println(coffee.getCoffeeType() + " selected. Price: " + coffee.getPrice()); } @Override public void insertMoney(CoffeeVendingMachine m, int a) { System.out.println("Please select a coffee first."); } @Override public void dispenseCoffee(CoffeeVendingMachine m) { System.out.println("Please select and pay first."); } @Override public void cancel(CoffeeVendingMachine m) { System.out.println("Nothing to cancel."); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/state/SelectingState.java ================================================ package coffeevendingmachine.state; import coffeevendingmachine.CoffeeVendingMachine; import coffeevendingmachine.decorator.Coffee; public class SelectingState implements VendingMachineState { @Override public void selectCoffee(CoffeeVendingMachine m, Coffee c) { System.out.println("Already selected. Please pay or cancel."); } @Override public void insertMoney(CoffeeVendingMachine machine, int amount) { machine.setMoneyInserted(machine.getMoneyInserted() + amount); System.out.println("Inserted " + amount + ". Total: " + machine.getMoneyInserted()); if (machine.getMoneyInserted() >= machine.getSelectedCoffee().getPrice()) { machine.setState(new PaidState()); } } @Override public void dispenseCoffee(CoffeeVendingMachine m) { System.out.println("Please insert enough money first."); } @Override public void cancel(CoffeeVendingMachine machine) { System.out.println("Transaction cancelled. Refunding " + machine.getMoneyInserted()); machine.reset(); machine.setState(new ReadyState()); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/state/VendingMachineState.java ================================================ package coffeevendingmachine.state; import coffeevendingmachine.CoffeeVendingMachine; import coffeevendingmachine.decorator.Coffee; public interface VendingMachineState { void selectCoffee(CoffeeVendingMachine machine, Coffee coffee); void insertMoney(CoffeeVendingMachine machine, int amount); void dispenseCoffee(CoffeeVendingMachine machine); void cancel(CoffeeVendingMachine machine); } ================================================ FILE: solutions/java/src/coffeevendingmachine/templatemethod/Cappuccino.java ================================================ package coffeevendingmachine.templatemethod; import coffeevendingmachine.decorator.Coffee; import coffeevendingmachine.enums.Ingredient; import java.util.Map; public class Cappuccino extends Coffee { public Cappuccino() { this.coffeeType = "Cappuccino"; } @Override protected void addCondiments() { System.out.println("- Adding steamed milk and foam."); } @Override public int getPrice() { return 250; } @Override public Map getRecipe() { return Map.of(Ingredient.COFFEE_BEANS, 7, Ingredient.WATER, 30, Ingredient.MILK, 100); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/templatemethod/Espresso.java ================================================ package coffeevendingmachine.templatemethod; import coffeevendingmachine.decorator.Coffee; import coffeevendingmachine.enums.Ingredient; import java.util.Map; public class Espresso extends Coffee { public Espresso() { this.coffeeType = "Espresso"; } @Override protected void addCondiments() { /* No extra condiments for espresso */ } @Override public int getPrice() { return 150; } @Override public Map getRecipe() { return Map.of(Ingredient.COFFEE_BEANS, 7, Ingredient.WATER, 30); } } ================================================ FILE: solutions/java/src/coffeevendingmachine/templatemethod/Latte.java ================================================ package coffeevendingmachine.templatemethod; import coffeevendingmachine.decorator.Coffee; import coffeevendingmachine.enums.Ingredient; import java.util.Map; public class Latte extends Coffee { public Latte() { this.coffeeType = "Latte"; } // Latte's implementation of the template hook @Override protected void addCondiments() { System.out.println("- Adding steamed milk."); } @Override public int getPrice() { return 220; } @Override public Map getRecipe() { return Map.of(Ingredient.COFFEE_BEANS, 7, Ingredient.WATER, 30, Ingredient.MILK, 150); } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/Booking.java ================================================ package concertticketbookingsystem; import java.util.List; public class Booking { private final String id; private final User user; private final Concert concert; private final List seats; private final double totalPrice; private BookingStatus status; public Booking(String id, User user, Concert concert, List seats) { this.id = id; this.user = user; this.concert = concert; this.seats = seats; this.totalPrice = calculateTotalPrice(); this.status = BookingStatus.PENDING; } private double calculateTotalPrice() { return seats.stream().mapToDouble(Seat::getPrice).sum(); } public void confirmBooking() { if (status == BookingStatus.PENDING) { status = BookingStatus.CONFIRMED; // Send booking confirmation to the user // ... } } public void cancelBooking() { if (status == BookingStatus.CONFIRMED) { status = BookingStatus.CANCELLED; seats.forEach(Seat::release); System.out.printf("Booking %s cancelled\n", id); // Send booking cancellation notification to the user // ... } } public String getId() { return id; } public User getUser() { return user; } public Concert getConcert() { return concert; } public List getSeats() { return seats; } public double getTotalPrice() { return totalPrice; } public BookingStatus getStatus() { return status; } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/BookingStatus.java ================================================ package concertticketbookingsystem; public enum BookingStatus { PENDING, CONFIRMED, CANCELLED } ================================================ FILE: solutions/java/src/concertticketbookingsystem/Concert.java ================================================ package concertticketbookingsystem; import java.time.LocalDateTime; import java.util.List; public class Concert { private final String id; private final String artist; private final String venue; private final LocalDateTime dateTime; private final List seats; public Concert(String id, String artist, String venue, LocalDateTime dateTime, List seats) { this.id = id; this.artist = artist; this.venue = venue; this.dateTime = dateTime; this.seats = seats; } public String getId() { return id; } public String getArtist() { return artist; } public String getVenue() { return venue; } public LocalDateTime getDateTime() { return dateTime; } public List getSeats() { return seats; } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/ConcertTicketBookingSystem.java ================================================ package concertticketbookingsystem; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class ConcertTicketBookingSystem { private static ConcertTicketBookingSystem instance; private final Map concerts; private final Map bookings; private final Object lock = new Object(); private ConcertTicketBookingSystem() { concerts = new ConcurrentHashMap<>(); bookings = new ConcurrentHashMap<>(); } public static synchronized ConcertTicketBookingSystem getInstance() { if (instance == null) { instance = new ConcertTicketBookingSystem(); } return instance; } public void addConcert(Concert concert) { concerts.put(concert.getId(), concert); } public Concert getConcert(String concertId) { return concerts.get(concertId); } public List searchConcerts(String artist, String venue, LocalDateTime dateTime) { return concerts.values().stream() .filter(concert -> concert.getArtist().equalsIgnoreCase(artist) && concert.getVenue().equalsIgnoreCase(venue) && concert.getDateTime().equals(dateTime)) .collect(Collectors.toList()); } public Booking bookTickets(User user, Concert concert, List seats) { synchronized (lock) { // Check seat availability and book seats for (Seat seat : seats) { if (seat.getStatus() != SeatStatus.AVAILABLE) { throw new SeatNotAvailableException("Seat " + seat.getSeatNumber() + " is not available."); } } seats.forEach(Seat::book); // Create booking String bookingId = generateBookingId(); Booking booking = new Booking(bookingId, user, concert, seats); bookings.put(bookingId, booking); // Process payment processPayment(booking); // Confirm booking booking.confirmBooking(); System.out.println("Booking " + booking.getId() + " - " + booking.getSeats().size() + " seats booked"); return booking; } } public void cancelBooking(String bookingId) { Booking booking = bookings.get(bookingId); if (booking != null) { booking.cancelBooking(); bookings.remove(bookingId); } } private void processPayment(Booking booking) { // Process payment for the booking // ... } private String generateBookingId() { return "BKG" + UUID.randomUUID(); } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/ConcertTicketBookingSystemDemo.java ================================================ package concertticketbookingsystem; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class ConcertTicketBookingSystemDemo { public static void run() { // Create concert ticket booking system instance ConcertTicketBookingSystem bookingSystem = ConcertTicketBookingSystem.getInstance(); // Create concerts List concert1Seats = generateSeats(100); Concert concert1 = new Concert("C001", "Artist 1", "Venue 1", LocalDateTime.now().plusDays(30), concert1Seats); bookingSystem.addConcert(concert1); List concert2Seats = generateSeats(50); Concert concert2 = new Concert("C002", "Artist 2", "Venue 2", LocalDateTime.now().plusDays(60), concert2Seats); bookingSystem.addConcert(concert2); // Create users User user1 = new User("U001", "John Doe", "john@example.com"); User user2 = new User("U002", "Jane Smith", "jane@example.com"); // Search concerts List searchResults = bookingSystem.searchConcerts("Artist 1", "Venue 1", LocalDateTime.now().plusDays(30)); System.out.println("Search Results:"); for (Concert concert : searchResults) { System.out.println("Concert: " + concert.getArtist() + " at " + concert.getVenue()); } // Book tickets List selectedSeats1 = selectSeats(concert1, 3); Booking booking1 = bookingSystem.bookTickets(user1, concert1, selectedSeats1); List selectedSeats2 = selectSeats(concert2, 2); Booking booking2 = bookingSystem.bookTickets(user2, concert2, selectedSeats2); // Cancel booking bookingSystem.cancelBooking(booking1.getId()); // Book tickets again List selectedSeats3 = selectSeats(concert1, 2); Booking booking3 = bookingSystem.bookTickets(user2, concert1, selectedSeats3); } private static List generateSeats(int numberOfSeats) { List seats = new ArrayList<>(); for (int i = 1; i <= numberOfSeats; i++) { String seatNumber = "S" + i; SeatType seatType = (i <= 10) ? SeatType.VIP : (i <= 30) ? SeatType.PREMIUM : SeatType.REGULAR; double price = (seatType == SeatType.VIP) ? 100.0 : (seatType == SeatType.PREMIUM) ? 75.0 : 50.0; seats.add(new Seat(seatNumber, seatNumber, seatType, price)); } return seats; } private static List selectSeats(Concert concert, int numberOfSeats) { List selectedSeats = new ArrayList<>(); List availableSeats = concert.getSeats().stream() .filter(seat -> seat.getStatus() == SeatStatus.AVAILABLE) .limit(numberOfSeats) .toList(); selectedSeats.addAll(availableSeats); return selectedSeats; } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/README.md ================================================ # Concert Ticket Booking System (LLD) ## Problem Statement Design and implement a Concert Ticket Booking System that allows users to book seats for concerts. The system should manage concert details, seat availability, and handle bookings with proper validation. --- ## Requirements - **Concert Management:** The system manages concert details including name, date, venue, and available seats. - **Seat Management:** The system tracks different types of seats (VIP, STANDARD, ECONOMY) and their availability. - **Booking Management:** Users can book seats, and the system handles booking status (CONFIRMED, CANCELLED). - **User Management:** The system maintains user information for bookings. - **Validation:** The system prevents double bookings and handles seat availability checks. --- ## Core Entities - **ConcertTicketBookingSystem:** Main class that manages concerts, bookings, and seat allocation. - **Concert:** Represents a concert with its details and seat management. - **Seat:** Represents a seat with its type, status, and booking information. - **User:** Represents a user who can book tickets. - **Booking:** Represents a booking with its status and associated details. - **SeatType:** Enum for different seat categories (VIP, STANDARD, ECONOMY). - **SeatStatus:** Enum for seat states (AVAILABLE, BOOKED). - **BookingStatus:** Enum for booking states (CONFIRMED, CANCELLED). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/concertticketbookingsystem-class-diagram.png) ### 1. ConcertTicketBookingSystem - **Fields:** List concerts, List bookings - **Methods:** addConcert(), bookSeat(), cancelBooking(), getAvailableSeats(), etc. ### 2. Concert - **Fields:** String name, String date, String venue, List seats - **Methods:** addSeat(), getAvailableSeats(), bookSeat(), etc. ### 3. Seat - **Fields:** String seatNumber, SeatType type, SeatStatus status, Booking booking - **Methods:** isAvailable(), book(), cancel(), etc. ### 4. User - **Fields:** String name, String email ### 5. Booking - **Fields:** String bookingId, User user, Concert concert, Seat seat, BookingStatus status - **Methods:** confirm(), cancel(), etc. ### 6. Enums - **SeatType:** VIP, STANDARD, ECONOMY - **SeatStatus:** AVAILABLE, BOOKED - **BookingStatus:** CONFIRMED, CANCELLED --- ## Example Usage ```java ConcertTicketBookingSystem system = new ConcertTicketBookingSystem(); // Add a concert Concert concert = system.addConcert("Rock Concert", "2024-12-31", "Stadium"); // Book a seat User user = new User("John Doe", "john@example.com"); Booking booking = system.bookSeat(concert, "A1", user); // Cancel booking system.cancelBooking(booking); ``` --- ## Demo See `ConcertTicketBookingSystemDemo.java` for a sample usage and simulation of the booking system. --- ## Extending the Framework - **Add payment processing:** Integrate payment gateway for parkingTicket purchases - **Add waitlist functionality:** Handle seat waitlist when fully booked - **Add discount management:** Support for different pricing tiers and discounts - **Add notification system:** Send booking confirmations and updates --- ## Design Patterns Used - **Singleton Pattern:** For managing the booking system instance - **Factory Pattern:** For creating different types of seats - **Observer Pattern:** For notifying users about booking status changes --- ================================================ FILE: solutions/java/src/concertticketbookingsystem/Seat.java ================================================ package concertticketbookingsystem; public class Seat { private final String id; private final String seatNumber; private final SeatType seatType; private final double price; private SeatStatus status; public Seat(String id, String seatNumber, SeatType seatType, double price) { this.id = id; this.seatNumber = seatNumber; this.seatType = seatType; this.price = price; this.status = SeatStatus.AVAILABLE; } public synchronized void book() { if (status == SeatStatus.AVAILABLE) { status = SeatStatus.BOOKED; } else { throw new SeatNotAvailableException("Seat is already booked or reserved."); } } public synchronized void release() { if (status == SeatStatus.BOOKED) { status = SeatStatus.AVAILABLE; } } public double getPrice() { return price; } public String getId() { return id; } public String getSeatNumber() { return seatNumber; } public SeatType getSeatType() { return seatType; } public SeatStatus getStatus() { return status; } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/SeatNotAvailableException.java ================================================ package concertticketbookingsystem; public class SeatNotAvailableException extends RuntimeException { public SeatNotAvailableException(String message) { super(message); } } ================================================ FILE: solutions/java/src/concertticketbookingsystem/SeatStatus.java ================================================ package concertticketbookingsystem; public enum SeatStatus { AVAILABLE, BOOKED, RESERVED } ================================================ FILE: solutions/java/src/concertticketbookingsystem/SeatType.java ================================================ package concertticketbookingsystem; public enum SeatType { REGULAR, PREMIUM, VIP } ================================================ FILE: solutions/java/src/concertticketbookingsystem/User.java ================================================ package concertticketbookingsystem; public class User { private final String id; private final String name; private final String email; public User(String id, String name, String email) { this.id = id; this.name = name; this.email = email; } } ================================================ FILE: solutions/java/src/courseregistrationsystem/CourseRegistrationDemo.java ================================================ package courseregistrationsystem; import courseregistrationsystem.model.*; import courseregistrationsystem.observer.WaitlistManager; import courseregistrationsystem.repository.CourseRepository; import courseregistrationsystem.repository.StudentRepository; import java.time.DayOfWeek; import java.time.LocalTime; public class CourseRegistrationDemo { public static void main(String[] args) { // 1. Setup the system CourseRegistrationSystemFacade system = new CourseRegistrationSystemFacade(); StudentRepository studentRepo = StudentRepository.getInstance(); CourseRepository courseRepo = CourseRepository.getInstance(); WaitlistManager waitlistManager = WaitlistManager.getInstance(); // 2. Setup courses and professors Course cs101 = new Course("CS101", "Intro to Programming"); Course cs201 = new Course("CS201", "Data Structures"); cs201.addPrerequisite(cs101); courseRepo.saveCourse(cs101); courseRepo.saveCourse(cs201); Professor profA = new Professor("P1", "Dr. Smith"); // 3. Setup course offerings using the Builder CourseOffering cs101Offering = new CourseOffering.Builder("CS101-F23", cs101) .withProfessor(profA).at(new TimeSlot(DayOfWeek.MONDAY, LocalTime.of(10, 0), LocalTime.of(11, 30))) .withCapacity(1).build(); CourseOffering cs201Offering = new CourseOffering.Builder("CS201-F23", cs201) .withProfessor(profA).at(new TimeSlot(DayOfWeek.WEDNESDAY, LocalTime.of(14, 0), LocalTime.of(15, 30))) .withCapacity(2).build(); // Register the WaitlistManager as an observer for the course offering cs101Offering.addObserver(waitlistManager); courseRepo.saveOffering(cs101Offering); courseRepo.saveOffering(cs201Offering); // 4. Setup students Student alice = new Student("S1", "Alice"); Student bob = new Student("S2", "Bob"); Student charlie = new Student("S3", "Charlie"); alice.addCompletedCourse(cs101); // Alice has the prerequisite for CS201 studentRepo.save(alice); studentRepo.save(bob); studentRepo.save(charlie); // 5. Run Registration Scenarios System.out.println("----------- SCENARIO 1: Successful Registration -----------"); system.registerStudentForCourse(alice.getId(), cs201Offering.getId()); System.out.println("\n----------- SCENARIO 2: Prerequisite Failure -----------"); system.registerStudentForCourse(bob.getId(), cs201Offering.getId()); System.out.println("\n----------- SCENARIO 3: Course Capacity and Waitlist -----------"); system.registerStudentForCourse(bob.getId(), cs101Offering.getId()); // Bob gets the last spot system.registerStudentForCourse(charlie.getId(), cs101Offering.getId()); // Charlie gets waitlisted System.out.println("\n----------- SCENARIO 4: Dropping a course and Observer pattern triggering waitlist promotion -----------"); system.dropStudentFromCourse(bob.getId(), cs101Offering.getId()); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/CourseRegistrationService.java ================================================ package courseregistrationsystem; import courseregistrationsystem.chain.*; import courseregistrationsystem.exception.RegistrationException; public class CourseRegistrationService { private final RegistrationRuleHandler registrationChain; public CourseRegistrationService() { // Build the chain of responsibility RegistrationRuleHandler capacityHandler = new CapacityRuleHandler(); RegistrationRuleHandler conflictHandler = new ScheduleConflictRuleHandler(); conflictHandler.setNext(capacityHandler); RegistrationRuleHandler prereqHandler = new PrerequisiteRuleHandler(); prereqHandler.setNext(conflictHandler); this.registrationChain = prereqHandler; } public void register(RegistrationRequest request) throws RegistrationException { registrationChain.handle(request); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/CourseRegistrationSystemFacade.java ================================================ package courseregistrationsystem; import courseregistrationsystem.chain.RegistrationRequest; import courseregistrationsystem.exception.RegistrationException; import courseregistrationsystem.repository.CourseRepository; import courseregistrationsystem.repository.StudentRepository; public class CourseRegistrationSystemFacade { private final CourseRegistrationService courseRegistrationService = new CourseRegistrationService(); private final StudentRepository studentRepo = StudentRepository.getInstance(); private final CourseRepository courseRepo = CourseRepository.getInstance(); public void registerStudentForCourse(String studentId, String offeringId) { studentRepo.findById(studentId).ifPresentOrElse(student -> courseRepo.findOfferingById(offeringId).ifPresentOrElse(offering -> { try { courseRegistrationService.register(new RegistrationRequest(student, offering)); } catch (RegistrationException e) { System.err.println("Registration Failed for " + student.getName() + ": " + e.getMessage()); } }, () -> System.err.println("Error: Course offering " + offeringId + " not found.") ), () -> System.err.println("Error: Student " + studentId + " not found.")); } public void dropStudentFromCourse(String studentId, String offeringId) { studentRepo.findById(studentId).ifPresent(student -> courseRepo.findOfferingById(offeringId).ifPresent(offering -> { offering.dropStudent(student); System.out.println(student.getName() + " dropped from " + offering.getCourse().getCourseCode()); }) ); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/README.md ================================================ # Course Registration System (LLD) ## Problem Statement Design and implement a Course Registration System that allows students to register for courses, manages course capacity, and tracks student enrollments. --- ## Requirements - **Student Registration:** Students can register for courses. - **Course Management:** The system manages courses, each with a unique code, name, and capacity. - **Capacity Enforcement:** Students cannot register for a course if it is full. - **Duplicate Prevention:** A student cannot register for the same course more than once. - **Enrollment Tracking:** The system tracks which students are enrolled in which courses. - **Extensibility:** Easy to add new features such as course prerequisites, waitlists, or drop functionality. --- ## Core Entities ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/CourseRegistrationSystem-class-diagram.png) - **CourseRegistrationSystem:** Main class that manages students, courses, and registrations. - **Student:** Represents a student with a unique ID and name. - **Course:** Represents a course with a unique code, name, and capacity. - **Registration:** Represents a registration record of a student in a course. --- ## Class Design ### 1. CourseRegistrationSystem - **Fields:** Map courses, Map students, List registrations - **Methods:** registerStudent(Student), addCourse(Course), register(int studentId, String courseCode), getStudentCourses(int studentId), getCourseStudents(String courseCode), etc. ### 2. Student - **Fields:** int id, String name ### 3. Course - **Fields:** String code, String name, int capacity, List enrolledStudents - **Methods:** enrollStudent(Student), isFull(), getEnrolledStudents() ### 4. Registration - **Fields:** Student student, Course course --- ## Example Usage ```java CourseRegistrationSystem system = new CourseRegistrationSystem(); system.registerStudent(new Student(1, "Alice")); system.registerStudent(new Student(2, "Bob")); system.addCourse(new Course("CS101", "Intro to CS", 2)); system.addCourse(new Course("MATH101", "Calculus I", 1)); system.register(1, "CS101"); // Alice registers for CS101 system.register(2, "CS101"); // Bob registers for CS101 system.register(1, "MATH101"); // Alice registers for MATH101 // List courses for Alice List aliceCourses = system.getStudentCourses(1); // List students in CS101 List cs101Students = system.getCourseStudents("CS101"); ``` --- ## Demo See `CourseRegistrationSystemDemo.java` for a sample usage and simulation of the course registration system. --- ## Extending the Framework - **Add course prerequisites:** Track and enforce prerequisites for course registration. - **Add waitlists:** Allow students to join a waitlist if a course is full. - **Add drop functionality:** Allow students to drop courses. --- ================================================ FILE: solutions/java/src/courseregistrationsystem/chain/CapacityRuleHandler.java ================================================ package courseregistrationsystem.chain; import courseregistrationsystem.exception.RegistrationException; public class CapacityRuleHandler extends RegistrationRuleHandler { @Override public void handle(RegistrationRequest request) throws RegistrationException { if (request.offering().isFull()) { request.offering().addToWaitlist(request.student()); System.out.println("Course " + request.offering().getCourse().getCourseCode() + " is full. " + request.student().getName() + " added to waitlist."); } else { request.offering().addStudent(request.student()); System.out.println(request.student().getName() + " successfully registered for " + request.offering().getCourse().getCourseCode()); } handleNext(request); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/chain/PrerequisiteRuleHandler.java ================================================ package courseregistrationsystem.chain; import courseregistrationsystem.exception.RegistrationException; import courseregistrationsystem.model.Course; import java.util.Set; public class PrerequisiteRuleHandler extends RegistrationRuleHandler { @Override public void handle(RegistrationRequest request) throws RegistrationException { Set completed = request.student().getCompletedCourses(); Set prereqs = request.offering().getCourse().getPrerequisites(); if (!completed.containsAll(prereqs)) { throw new RegistrationException("Prerequisite not met for course " + request.offering().getCourse().getCourseCode()); } handleNext(request); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/chain/RegistrationRequest.java ================================================ package courseregistrationsystem.chain; import courseregistrationsystem.model.CourseOffering; import courseregistrationsystem.model.Student; public record RegistrationRequest(Student student, CourseOffering offering) {} ================================================ FILE: solutions/java/src/courseregistrationsystem/chain/RegistrationRuleHandler.java ================================================ package courseregistrationsystem.chain; import courseregistrationsystem.exception.RegistrationException; public abstract class RegistrationRuleHandler { private RegistrationRuleHandler next; public void setNext(RegistrationRuleHandler next) { this.next = next; } public abstract void handle(RegistrationRequest request) throws RegistrationException; protected void handleNext(RegistrationRequest request) throws RegistrationException { if (next != null) { next.handle(request); } } } ================================================ FILE: solutions/java/src/courseregistrationsystem/chain/ScheduleConflictRuleHandler.java ================================================ package courseregistrationsystem.chain; import courseregistrationsystem.exception.RegistrationException; public class ScheduleConflictRuleHandler extends RegistrationRuleHandler { @Override public void handle(RegistrationRequest request) throws RegistrationException { boolean conflict = request.student().getRegisteredOfferings().stream() .anyMatch(offering -> offering.getTimeSlot().overlaps(request.offering().getTimeSlot())); if (conflict) { throw new RegistrationException("Schedule conflict detected for course " + request.offering().getCourse().getCourseCode()); } handleNext(request); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/exception/RegistrationException.java ================================================ package courseregistrationsystem.exception; public class RegistrationException extends Exception { public RegistrationException(String message) { super(message); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/model/Course.java ================================================ package courseregistrationsystem.model; import java.util.HashSet; import java.util.Set; public class Course { private final String courseCode; private final String title; private final Set prerequisites = new HashSet<>(); public Course(String courseCode, String title) { this.courseCode = courseCode; this.title = title; } public void addPrerequisite(Course course) { prerequisites.add(course); } public String getCourseCode() { return courseCode; } public Set getPrerequisites() { return prerequisites; } } ================================================ FILE: solutions/java/src/courseregistrationsystem/model/CourseOffering.java ================================================ package courseregistrationsystem.model; import courseregistrationsystem.observer.CourseOfferingObserver; import java.util.*; public class CourseOffering { private final String id; private final Course course; private final Professor professor; private final TimeSlot timeSlot; private final int capacity; private final List registeredStudents = new ArrayList<>(); private final Queue waitlistedStudents = new LinkedList<>(); private final List observers = new ArrayList<>(); private CourseOffering(Builder builder) { this.id = builder.id; this.course = builder.course; this.professor = builder.professor; this.timeSlot = builder.timeSlot; this.capacity = builder.capacity; } public void addObserver(CourseOfferingObserver observer) { observers.add(observer); } private void notifyObservers() { observers.forEach(o -> o.onSpotAvailable(this)); } public boolean isFull() { return registeredStudents.size() >= capacity; } public void addStudent(Student student) { registeredStudents.add(student); student.enroll(this); } public void addToWaitlist(Student student) { waitlistedStudents.add(student); } public void dropStudent(Student student) { boolean wasFull = isFull(); registeredStudents.remove(student); student.drop(this); if (wasFull && !isFull()) { notifyObservers(); } } public Optional getNextFromWaitlist() { return Optional.ofNullable(waitlistedStudents.poll()); } public String getId() { return id; } public Course getCourse() { return course; } public TimeSlot getTimeSlot() { return timeSlot; } // Builder Pattern public static class Builder { private String id; private Course course; private Professor professor; private TimeSlot timeSlot; private int capacity; public Builder(String id, Course course) { this.id = id; this.course = course; } public Builder withProfessor(Professor professor) { this.professor = professor; return this; } public Builder at(TimeSlot timeSlot) { this.timeSlot = timeSlot; return this; } public Builder withCapacity(int capacity) { this.capacity = capacity; return this; } public CourseOffering build() { return new CourseOffering(this); } } } ================================================ FILE: solutions/java/src/courseregistrationsystem/model/Professor.java ================================================ package courseregistrationsystem.model; public record Professor(String id, String name) {} ================================================ FILE: solutions/java/src/courseregistrationsystem/model/Student.java ================================================ package courseregistrationsystem.model; import java.util.HashSet; import java.util.Set; public class Student { private final String id; private final String name; private final Set completedCourses = new HashSet<>(); private final Set registeredOfferings = new HashSet<>(); public Student(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public String getName() { return name; } public Set getCompletedCourses() { return completedCourses; } public Set getRegisteredOfferings() { return registeredOfferings; } public void addCompletedCourse(Course course) { completedCourses.add(course); } public void enroll(CourseOffering offering) { registeredOfferings.add(offering); } public void drop(CourseOffering offering) { registeredOfferings.remove(offering); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/model/TimeSlot.java ================================================ package courseregistrationsystem.model; import java.time.DayOfWeek; import java.time.LocalTime; public record TimeSlot(DayOfWeek day, LocalTime startTime, LocalTime endTime) { public boolean overlaps(TimeSlot other) { return this.day == other.day && this.startTime.isBefore(other.endTime) && this.endTime.isAfter(other.startTime); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/observer/CourseOfferingObserver.java ================================================ package courseregistrationsystem.observer; import courseregistrationsystem.model.CourseOffering; public interface CourseOfferingObserver { void onSpotAvailable(CourseOffering offering); } ================================================ FILE: solutions/java/src/courseregistrationsystem/observer/WaitlistManager.java ================================================ package courseregistrationsystem.observer; import courseregistrationsystem.CourseRegistrationService; import courseregistrationsystem.chain.RegistrationRequest; import courseregistrationsystem.exception.RegistrationException; import courseregistrationsystem.model.CourseOffering; public class WaitlistManager implements CourseOfferingObserver { private static final WaitlistManager INSTANCE = new WaitlistManager(); private final CourseRegistrationService courseRegistrationService = new CourseRegistrationService(); // To re-register a waitlisted student public static WaitlistManager getInstance() { return INSTANCE; } private WaitlistManager() {} @Override public void onSpotAvailable(CourseOffering offering) { System.out.println("OBSERVER (WaitlistManager): Spot available in " + offering.getCourse().getCourseCode() + ". Processing waitlist."); offering.getNextFromWaitlist().ifPresent(student -> { System.out.println("Promoting " + student.getName() + " from waitlist for " + offering.getCourse().getCourseCode()); try { // We can re-use the registration service, but a real system might have a simplified "promote" logic courseRegistrationService.register(new RegistrationRequest(student, offering)); } catch (RegistrationException e) { System.err.println("Failed to promote " + student.getName() + ": " + e.getMessage()); // Handle failure: try next student or notify admin } }); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/repository/CourseRepository.java ================================================ package courseregistrationsystem.repository; import courseregistrationsystem.model.Course; import courseregistrationsystem.model.CourseOffering; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; public class CourseRepository { private static final CourseRepository INSTANCE = new CourseRepository(); private final Map courses = new ConcurrentHashMap<>(); private final Map offerings = new ConcurrentHashMap<>(); public static CourseRepository getInstance() { return INSTANCE; } public void saveCourse(Course c) { courses.put(c.getCourseCode(), c); } public void saveOffering(CourseOffering o) { offerings.put(o.getId(), o); } public Optional findOfferingById(String id) { return Optional.ofNullable(offerings.get(id)); } } ================================================ FILE: solutions/java/src/courseregistrationsystem/repository/StudentRepository.java ================================================ package courseregistrationsystem.repository; import courseregistrationsystem.model.Student; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; public class StudentRepository { private static final StudentRepository INSTANCE = new StudentRepository(); private final Map students = new ConcurrentHashMap<>(); public static StudentRepository getInstance() { return INSTANCE; } public void save(Student s) { students.put(s.getId(), s); } public Optional findById(String id) { return Optional.ofNullable(students.get(id)); } } ================================================ FILE: solutions/java/src/cricinfo/CommentaryManager.java ================================================ package cricinfo; import cricinfo.enums.ExtraType; import cricinfo.enums.WicketType; import cricinfo.entity.Ball; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; public class CommentaryManager { private static volatile CommentaryManager instance; private final Random random = new Random(); private final Map> commentaryTemplates = new ConcurrentHashMap<>(); private CommentaryManager() { initializeTemplates(); } public static CommentaryManager getInstance() { if (instance == null) { synchronized (CommentaryManager.class) { if (instance == null) { instance = new CommentaryManager(); } } } return instance; } private void initializeTemplates() { // Templates for runs commentaryTemplates.put("RUNS_0", List.of( "%s defends solidly.", "No run, good fielding by the cover fielder.", "A dot ball to end the over.", "Pushed to mid-on, but no run." )); commentaryTemplates.put("RUNS_1", List.of( "Tucked away to the leg side for a single.", "Quick single taken by %s.", "Pushed to long-on for one." )); commentaryTemplates.put("RUNS_2", List.of( "Two runs taken!", "Quick double taken by %s.", "Pushed to mid-on for two." )); commentaryTemplates.put("RUNS_4", List.of( "FOUR! %s smashes it through the covers!", "Beautiful shot! That's a boundary.", "Finds the gap perfectly. Four runs." )); commentaryTemplates.put("RUNS_6", List.of( "SIX! That's out of the park!", "%s sends it sailing over the ropes!", "Massive hit! It's a maximum." )); // Templates for wickets commentaryTemplates.put("WICKET_" + WicketType.BOWLED, List.of( "BOWLED HIM! %s misses completely and the stumps are shattered!", "Cleaned up! A perfect yorker from %s." )); commentaryTemplates.put("WICKET_" + WicketType.CAUGHT, List.of( "CAUGHT! %s skies it and the fielder takes a comfortable catch.", "Out! A brilliant catch in the deep by %s." )); commentaryTemplates.put("WICKET_" + WicketType.LBW, List.of( "LBW! That one kept low and struck %s right in front.", "%s completely misjudged the line and pays the price." )); commentaryTemplates.put("WICKET_" + WicketType.STUMPED, List.of( "STUMPED! %s misses it, and the keeper does the rest!", "Gone! Lightning-fast work by the keeper to stump %s." )); // Templates for extras commentaryTemplates.put("EXTRA_" + ExtraType.WIDE, List.of( "That's a wide. The umpire signals an extra run.", "Too far down the leg side, that'll be a wide." )); commentaryTemplates.put("EXTRA_" + ExtraType.NO_BALL, List.of( "No ball! %s has overstepped. It's a free hit.", "It's a no-ball for overstepping." )); } public String generateCommentary(Ball ball) { String key = getEventKey(ball); List templates = commentaryTemplates.getOrDefault(key, List.of("Just a standard delivery.")); String template = templates.get(random.nextInt(templates.size())); // Format the commentary with player names String batsmanName = ball.getFacedBy() != null ? ball.getFacedBy().getName() : ""; String bowlerName = ball.getBowledBy() != null ? ball.getBowledBy().getName() : ""; // This handles cases where a template might have more or fewer placeholders // and avoids exceptions. return String.format(template.replace("%s", "%1$s"), batsmanName, bowlerName); } private String getEventKey(Ball ball) { if (ball.isWicket()) { return "WICKET_" + ball.getWicket().getWicketType().toString(); } if (ball.getExtraType() != null) { return "EXTRA_" + ball.getExtraType().toString(); } if (ball.getRunsScored() >= 0 && ball.getRunsScored() <= 6) { switch(ball.getRunsScored()) { case 0: return "RUNS_0"; case 1: return "RUNS_1"; case 2: return "RUNS_2"; case 3: return "RUNS_3"; case 4: return "RUNS_4"; case 6: return "RUNS_6"; } } return "DEFAULT"; // Fallback key } } ================================================ FILE: solutions/java/src/cricinfo/CricInfoService.java ================================================ package cricinfo; import cricinfo.enums.PlayerRole; import cricinfo.entity.Ball; import cricinfo.entity.Match; import cricinfo.entity.Player; import cricinfo.entity.Team; import cricinfo.observer.MatchObserver; import cricinfo.repository.MatchRepository; import cricinfo.repository.PlayerRepository; import cricinfo.state.FinishedState; import cricinfo.state.LiveState; import cricinfo.strategy.MatchFormatStrategy; import java.util.UUID; public class CricInfoService { private static volatile CricInfoService instance; private final MatchRepository matchRepository; private final PlayerRepository playerRepository; private CricInfoService() { this.matchRepository = new MatchRepository(); this.playerRepository = new PlayerRepository(); } public static CricInfoService getInstance() { if (instance == null) { synchronized (CricInfoService.class) { if (instance == null) { instance = new CricInfoService(); } } } return instance; } public Match createMatch(Team team1, Team team2, MatchFormatStrategy format) { String matchId = UUID.randomUUID().toString(); Match match = new Match(matchId, team1, team2, format); matchRepository.save(match); System.out.printf("Match %s created between %s and %s.%n", format.getFormatName(), team1.getName(), team2.getName()); return match; } public void startMatch(String matchId) { matchRepository.findById(matchId).ifPresent(match -> { match.setState(new LiveState()); System.out.printf("Match %s is now LIVE.%n", matchId); }); } public void processBallUpdate(String matchId, Ball ball) { matchRepository.findById(matchId).ifPresent(match -> match.processBall(ball)); } public void startNextInnings(String matchId) { matchRepository.findById(matchId).ifPresent(Match::startNextInnings); } public void subscribeToMatch(String matchId, MatchObserver observer) { matchRepository.findById(matchId).ifPresent(match -> match.addObserver(observer)); } public void endMatch(String matchId) { matchRepository.findById(matchId).ifPresent(match -> { match.setState(new FinishedState()); System.out.printf("Match %s has FINISHED.%n", matchId); }); } public Player addPlayer(String playerId, String playerName, PlayerRole playerRole) { Player player = new Player(playerId, playerName, playerRole); playerRepository.save(player); return player; } } ================================================ FILE: solutions/java/src/cricinfo/CricinfoDemo.java ================================================ package cricinfo; import cricinfo.enums.PlayerRole; import cricinfo.enums.WicketType; import cricinfo.entity.*; import cricinfo.observer.CommentaryDisplay; import cricinfo.observer.ScorecardDisplay; import cricinfo.observer.UserNotifier; import cricinfo.strategy.T20FormatStrategy; import java.util.List; public class CricinfoDemo { public static void main(String[] args) { // Get the Singleton service instance CricInfoService service = CricInfoService.getInstance(); // 1. Setup Players and Teams Player p1 = service.addPlayer("P1", "Virat", PlayerRole.BATSMAN); Player p2 = service.addPlayer("P2", "Rohit", PlayerRole.BATSMAN); Player p3 = service.addPlayer("P3", "Bumrah", PlayerRole.BOWLER); Player p4 = service.addPlayer("P4", "Jadeja", PlayerRole.ALL_ROUNDER); Player p5 = service.addPlayer("P5", "Warner", PlayerRole.BATSMAN); Player p6 = service.addPlayer("P6", "Smith", PlayerRole.BATSMAN); Player p7 = service.addPlayer("P7", "Starc", PlayerRole.BOWLER); Player p8 = service.addPlayer("P8", "Maxwell", PlayerRole.ALL_ROUNDER); Team india = new Team("T1", "India", List.of(p1, p2, p3, p4)); Team australia = new Team("T2", "Australia", List.of(p5, p6, p7, p8)); // 2. Create a T20 Match using the service Match t20Match = service.createMatch(india, australia, new T20FormatStrategy()); String matchId = t20Match.getId(); // 3. Create and subscribe observers ScorecardDisplay scorecard = new ScorecardDisplay(); CommentaryDisplay commentary = new CommentaryDisplay(); UserNotifier notifier = new UserNotifier(); service.subscribeToMatch(matchId, scorecard); service.subscribeToMatch(matchId, commentary); service.subscribeToMatch(matchId, notifier); // 4. Start the match service.startMatch(matchId); System.out.println("\n--- SIMULATING FIRST INNINGS ---"); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p1).withRuns(2).build()); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p1).withRuns(1).build()); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p2).withRuns(6).build()); Wicket p2Wicket = new Wicket.Builder(WicketType.BOWLED, p2).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p2).withRuns(0).withWicket(p2Wicket).build()); Wicket p3Wicket = new Wicket.Builder(WicketType.LBW, p3).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p3).withRuns(0).withWicket(p3Wicket).build()); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p4).withRuns(4).build()); Wicket p4Wicket = new Wicket.Builder(WicketType.CAUGHT, p4).caughtBy(p6).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p7).facedBy(p4).withRuns(0).withWicket(p4Wicket).build()); // The system is now in an IN_BREAK state System.out.println("\n\n--- INNINGS BREAK ---"); System.out.println("Players are off the field. Preparing for the second innings."); // 2. Start the second innings service.startNextInnings(matchId); System.out.println("\n--- SIMULATING SECOND INNINGS ---"); // Simulate a few balls of the second innings to show it works // Now Australia is batting (p5, p6) and India is bowling (p3) service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p3).facedBy(p5).withRuns(4).build()); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p3).facedBy(p5).withRuns(1).build()); Wicket p5Wicket = new Wicket.Builder(WicketType.BOWLED, p5).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p3).facedBy(p5).withRuns(0).withWicket(p5Wicket).build()); Wicket p7Wicket = new Wicket.Builder(WicketType.LBW, p7).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p3).facedBy(p7).withRuns(0).withWicket(p7Wicket).build()); Wicket p8Wicket = new Wicket.Builder(WicketType.STUMPED, p8).build(); service.processBallUpdate(matchId, new Ball.BallBuilder() .bowledBy(p3).facedBy(p8).withRuns(0).withWicket(p8Wicket).build()); service.endMatch(matchId); } } ================================================ FILE: solutions/java/src/cricinfo/README.md ================================================ # Cricket Information System (LLD) ## Problem Statement Design and implement a Cricket Information System similar to CricInfo that provides comprehensive information about cricket matches, teams, players, and live scores. The system should handle real-time updates, match statistics, and user interactions. --- ## Requirements 1. **Match Information Management:** - Store and manage cricket match details - Track match schedules and results - Support real-time score updates - Handle match status transitions 2. **Team and Player Management:** - Maintain team rosters and player information - Track player roles and statistics - Support team composition changes 3. **Scorecard Management:** - Record detailed match statistics - Track innings, overs, and ball-by-ball information - Maintain batting and bowling statistics 4. **Search and Retrieval:** - Search for matches, teams, and players - View detailed match information - Access historical data and statistics 5. **System Requirements:** - Handle concurrent access - Ensure data consistency - Support scalability - Allow for future extensions --- ## Core Entities ### 1. Match - **Fields:** String id, String title, String venue, Date startTime, Team team1, Team team2, MatchStatus status, Scorecard scorecard - **Methods:** updateStatus(), getScorecard(), getMatchDetails() ### 2. Team - **Fields:** String id, String name, List players - **Methods:** addPlayer(), removePlayer(), getTeamStats() ### 3. Player - **Fields:** String id, String name, String role - **Methods:** getPlayerStats(), updateRole() ### 4. Scorecard - **Fields:** Match match, List innings - **Methods:** addInnings(), updateScore(), getMatchSummary() ### 5. Innings - **Fields:** String id, Team battingTeam, Team bowlingTeam, List overs - **Methods:** addOver(), getInningsSummary() ### 6. Over - **Fields:** int overNumber, List balls - **Methods:** addBall(), getOverSummary() ### 7. Ball - **Fields:** int ballNumber, Player bowler, Player batsman, String result - **Methods:** recordResult(), getBallDetails() ### 8. MatchStatus (Enum) - **Values:** SCHEDULED, IN_PROGRESS, COMPLETED, ABANDONED ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/cricinfo-class-diagram.png) --- ## Services ### 1. MatchService (Singleton) - **Methods:** - addMatch(Match match) - getMatch(String id) - updateMatchStatus(String id, MatchStatus status) - searchMatches(String query) ### 2. ScorecardService (Singleton) - **Methods:** - createScorecard(Match match) - updateScorecard(String matchId, Scorecard scorecard) - getScorecard(String matchId) - addInnings(String matchId, Innings innings) ### 3. CricinfoSystem - **Methods:** - getMatchDetails(String matchId) - getTeamDetails(String teamId) - getPlayerDetails(String playerId) - search(String query) --- ## Example Usage ```java CricinfoSystem system = CricinfoSystem.getInstance(); // Create a new match Match match = system.createMatch("IND vs AUS", "Melbourne Cricket Ground", new Date()); // Update match status system.updateMatchStatus(match.getId(), MatchStatus.IN_PROGRESS); // Record a ball system.recordBall(match.getId(), 1, 1, "FOUR"); // Get match details MatchDetails details = system.getMatchDetails(match.getId()); ``` --- ## Demo See the demo class for a sample usage and simulation of the cricket information system. --- ## Extending the Framework - **Add user authentication:** Support for user accounts and preferences - **Add commentary system:** Real-time match commentary - **Add statistics engine:** Advanced player and team statistics - **Add notification system:** Match updates and alerts - **Add social features:** User comments and discussions --- ## Design Patterns Used - **Singleton Pattern:** For service classes (MatchService, ScorecardService) - **Factory Pattern:** For creating matches and scorecards - **Observer Pattern:** For real-time updates and notifications - **Strategy Pattern:** For different types of match formats --- ================================================ FILE: solutions/java/src/cricinfo/entity/Ball.java ================================================ package cricinfo.entity; import cricinfo.CommentaryManager; import cricinfo.enums.ExtraType; public class Ball { private final int ballNumber; private final Player bowledBy; private final Player facedBy; private final int runsScored; private final Wicket wicket; // Null if no wicket private final ExtraType extraType; // Null if no extra private final String commentary; private Ball(BallBuilder builder) { this.ballNumber = builder.ballNumber; this.bowledBy = builder.bowledBy; this.facedBy = builder.facedBy; this.runsScored = builder.runsScored; this.wicket = builder.wicket; this.extraType = builder.extraType; this.commentary = builder.commentary; } public boolean isWicket() { return wicket != null; } public boolean isBoundary() { return runsScored == 4 || runsScored == 6; } public String getCommentary() { return commentary; } public int getRunsScored() { return runsScored; } public Player getFacedBy() { return facedBy; } public Player getBowledBy() { return bowledBy; } public Wicket getWicket() { return wicket; } public ExtraType getExtraType() { return extraType; } // Other getters public static class BallBuilder { private int ballNumber; private Player bowledBy; private Player facedBy; private int runsScored; private Wicket wicket; private ExtraType extraType; private String commentary; public BallBuilder withBallNumber(int ballNumber) { this.ballNumber = ballNumber; return this; } public BallBuilder bowledBy(Player bowler) { this.bowledBy = bowler; return this; } public BallBuilder facedBy(Player batsman) { this.facedBy = batsman; return this; } public BallBuilder withRuns(int runs) { this.runsScored = runs; return this; } public BallBuilder withWicket(Wicket wicket) { this.wicket = wicket; return this; } public BallBuilder withExtraType(ExtraType extra) { this.extraType = extra; return this; } public BallBuilder withCommentary(String commentary) { this.commentary = commentary; return this; } public Ball build() { // This is needed because the manager needs the ball's final state to generate commentary Ball tempBall = new Ball(this); if (this.commentary == null) { this.commentary = CommentaryManager.getInstance().generateCommentary(tempBall); } return new Ball(this); } } } ================================================ FILE: solutions/java/src/cricinfo/entity/Innings.java ================================================ package cricinfo.entity; import cricinfo.enums.ExtraType; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class Innings { private final Team battingTeam; private final Team bowlingTeam; private int score; private int wickets; private final List balls; private final Map playerStats; public Innings(Team battingTeam, Team bowlingTeam) { this.battingTeam = battingTeam; this.bowlingTeam = bowlingTeam; this.score = 0; this.wickets = 0; this.balls = new ArrayList<>(); this.playerStats = new ConcurrentHashMap<>(); for(Player player: battingTeam.getPlayers()) { playerStats.put(player, new PlayerStats()); } for(Player player: bowlingTeam.getPlayers()) { playerStats.put(player, new PlayerStats()); } } public void addBall(Ball ball) { balls.add(ball); int runsScored = ball.getRunsScored(); this.score += runsScored; if (ball.getExtraType() == ExtraType.WIDE || ball.getExtraType() == ExtraType.NO_BALL) { this.score += 1; } else { ball.getFacedBy().getStats().updateRuns(runsScored); ball.getFacedBy().getStats().incrementBallsPlayed(); playerStats.get(ball.getFacedBy()).updateRuns(runsScored); playerStats.get(ball.getFacedBy()).incrementBallsPlayed(); } if (ball.isWicket()) { this.wickets++; ball.getBowledBy().getStats().incrementWickets(); playerStats.get(ball.getBowledBy()).incrementWickets(); } } public void printPlayerStats() { for (Map.Entry entry : playerStats.entrySet()) { Player player = entry.getKey(); PlayerStats stats = entry.getValue(); if (stats.getBallsPlayed() > 0 || stats.getWickets() > 0) { System.out.println("Player: " + player.getName() + " - Stats: " + stats); } } } public int getScore() { return score; } public int getWickets() { return wickets; } public Team getBattingTeam() { return battingTeam; } public double getOvers() { int validBalls = (int) balls.stream() .filter(b -> b.getExtraType() != ExtraType.WIDE && b.getExtraType() != ExtraType.NO_BALL) .count(); int completedOvers = validBalls / 6; int ballsInCurrentOver = validBalls % 6; return completedOvers + (ballsInCurrentOver / 10.0); } } ================================================ FILE: solutions/java/src/cricinfo/entity/Match.java ================================================ package cricinfo.entity; import cricinfo.enums.MatchStatus; import cricinfo.observer.MatchObserver; import cricinfo.state.MatchState; import cricinfo.state.ScheduledState; import cricinfo.strategy.MatchFormatStrategy; import java.util.ArrayList; import java.util.List; public class Match { private final String id; private final Team team1; private final Team team2; private final MatchFormatStrategy formatStrategy; private final List innings; private MatchState currentState; private MatchStatus currentStatus; private final List observers = new ArrayList<>(); private Team winner; private String resultMessage; public Match(String id, Team team1, Team team2, MatchFormatStrategy formatStrategy) { this.id = id; this.team1 = team1; this.team2 = team2; this.formatStrategy = formatStrategy; this.innings = new ArrayList<>(); this.innings.add(new Innings(team1, team2)); // Start first innings this.currentState = new ScheduledState(); // Initial state this.resultMessage = ""; } // State Pattern Methods public void processBall(Ball ball) { currentState.processBall(this, ball); } public void startNextInnings() { currentState.startNextInnings(this); } public void setState(MatchState state) { this.currentState = state; } public void setCurrentStatus(MatchStatus status) { this.currentStatus = status; } public void setWinner(Team winner) { this.winner = winner; } public void setResultMessage(String resultMessage) { this.resultMessage = resultMessage; } public void createNewInnings() { if (innings.size() >= formatStrategy.getTotalInnings()) { System.out.println("Cannot create a new innings, match has already reached its limit."); return; } // Swap the teams for the next innings Innings nextInnings = new Innings(this.team2, this.team1); this.innings.add(nextInnings); } // Observer Pattern Methods public void addObserver(MatchObserver observer) { observers.add(observer); } public void removeObserver(MatchObserver observer) { observers.remove(observer); } public void notifyObservers(Ball ball) { for (MatchObserver observer : observers) { observer.update(this, ball); } } public Innings getCurrentInnings() { return innings.get(innings.size() - 1); } public Team getTeam1() { return team1; } public Team getTeam2() { return team2; } public Team getWinner() { return winner; } public String getResultMessage() { return resultMessage; } public List getInnings() { return innings; } public String getId() { return id; } public MatchStatus getCurrentStatus() { return currentStatus; } public MatchFormatStrategy getFormatStrategy() { return formatStrategy; } } ================================================ FILE: solutions/java/src/cricinfo/entity/Player.java ================================================ package cricinfo.entity; import cricinfo.enums.PlayerRole; public class Player { private final String id; private final String name; private final PlayerRole role; private PlayerStats stats; public Player(String id, String name, PlayerRole role) { this.id = id; this.name = name; this.role = role; this.stats = new PlayerStats(); } public String getId() { return id; } public String getName() { return name; } public PlayerStats getStats() { return stats; } } ================================================ FILE: solutions/java/src/cricinfo/entity/PlayerStats.java ================================================ package cricinfo.entity; public class PlayerStats { private int runs; private int ballsPlayed; private int wickets; public PlayerStats() { runs = 0; wickets = 0; } public void updateRuns(int runScored) { runs += runScored; } public void incrementBallsPlayed() { ballsPlayed += 1; } public void incrementWickets() { wickets += 1; } public int getRuns() { return runs; } public int getWickets() { return wickets; } public int getBallsPlayed() { return ballsPlayed; } @Override public String toString() { return "Runs: " + runs + ", Balls Played: " + ballsPlayed + ", Wickets: " + wickets; } } ================================================ FILE: solutions/java/src/cricinfo/entity/Team.java ================================================ package cricinfo.entity; import java.util.List; public class Team { private final String id; private final String name; private final List players; public Team(String id, String name, List players) { this.id = id; this.name = name; this.players = players; } public String getName() { return name; } public List getPlayers() { return players; } } ================================================ FILE: solutions/java/src/cricinfo/entity/Wicket.java ================================================ package cricinfo.entity; import cricinfo.enums.WicketType; public class Wicket { private final WicketType wicketType; private final Player playerOut; private final Player caughtBy; private final Player runoutBy; private Wicket(Builder builder) { this.wicketType = builder.wicketType; this.playerOut = builder.playerOut; this.caughtBy = builder.caughtBy; this.runoutBy = builder.runoutBy; } public WicketType getWicketType() { return wicketType; } public Player getPlayerOut() { return playerOut; } public Player getCaughtBy() { return caughtBy; } public Player getRunoutBy() { return runoutBy; } public static class Builder { // Required parameters private final WicketType wicketType; private final Player playerOut; // Optional parameters private Player caughtBy = null; private Player runoutBy = null; public Builder(WicketType wicketType, Player playerOut) { this.wicketType = wicketType; this.playerOut = playerOut; } public Builder caughtBy(Player player) { this.caughtBy = player; return this; } public Builder runoutBy(Player player) { this.runoutBy = player; return this; } public Wicket build() { // We could add validation here, e.g., ensure 'caughtBy' is only set for WicketType.CAUGHT return new Wicket(this); } } } ================================================ FILE: solutions/java/src/cricinfo/enums/ExtraType.java ================================================ package cricinfo.enums; public enum ExtraType { WIDE, NO_BALL, BYE, LEG_BYE } ================================================ FILE: solutions/java/src/cricinfo/enums/MatchStatus.java ================================================ package cricinfo.enums; public enum MatchStatus { SCHEDULED, LIVE, IN_BREAK, FINISHED, ABANDONED } ================================================ FILE: solutions/java/src/cricinfo/enums/PlayerRole.java ================================================ package cricinfo.enums; public enum PlayerRole { BATSMAN, BOWLER, ALL_ROUNDER, WICKET_KEEPER } ================================================ FILE: solutions/java/src/cricinfo/enums/WicketType.java ================================================ package cricinfo.enums; public enum WicketType { BOWLED, CAUGHT, LBW, RUN_OUT, STUMPED, HIT_WICKET } ================================================ FILE: solutions/java/src/cricinfo/observer/CommentaryDisplay.java ================================================ package cricinfo.observer; import cricinfo.enums.MatchStatus; import cricinfo.entity.Match; import cricinfo.entity.Ball; public class CommentaryDisplay implements MatchObserver { @Override public void update(Match match, Ball lastBall) { if (match.getCurrentStatus() == MatchStatus.FINISHED) { System.out.println("[COMMENTARY]: Match has finished!"); } else if (match.getCurrentStatus() == MatchStatus.IN_BREAK) { System.out.println("[COMMENTARY]: Inning has ended!"); } else { System.out.printf("[COMMENTARY]: %s%n", lastBall.getCommentary()); } } } ================================================ FILE: solutions/java/src/cricinfo/observer/MatchObserver.java ================================================ package cricinfo.observer; import cricinfo.entity.Match; import cricinfo.entity.Ball; public interface MatchObserver { void update(Match match, Ball lastBall); } ================================================ FILE: solutions/java/src/cricinfo/observer/ScorecardDisplay.java ================================================ package cricinfo.observer; import cricinfo.enums.MatchStatus; import cricinfo.entity.Innings; import cricinfo.entity.Match; import cricinfo.entity.Ball; public class ScorecardDisplay implements MatchObserver { @Override public void update(Match match, Ball lastBall) { // This block handles end-of-innings or end-of-match signals if (match.getCurrentStatus() == MatchStatus.FINISHED) { System.out.println("\n--- MATCH RESULT ---"); System.out.println(match.getResultMessage().toUpperCase()); System.out.println("--------------------"); System.out.println("Player Stats:"); int counter = 1; for (Innings inning: match.getInnings()) { System.out.println("Inning " + counter++); inning.printPlayerStats(); } } else if (match.getCurrentStatus() == MatchStatus.IN_BREAK) { System.out.println("\n--- END OF INNINGS ---"); Innings lastInnings = match.getInnings().get(match.getInnings().size() - 1); System.out.printf("Final Score: %s: %d/%d (Overs: %.1f)%n", lastInnings.getBattingTeam().getName(), lastInnings.getScore(), lastInnings.getWickets(), lastInnings.getOvers()); System.out.println("------------------------"); } else { // This block runs for every ball during a live match System.out.println("\n--- SCORECARD UPDATE ---"); Innings currentInnings = match.getCurrentInnings(); System.out.printf("%s: %d/%d (Overs: %.1f)%n", currentInnings.getBattingTeam().getName(), currentInnings.getScore(), currentInnings.getWickets(), currentInnings.getOvers()); System.out.println("------------------------"); } } } ================================================ FILE: solutions/java/src/cricinfo/observer/UserNotifier.java ================================================ package cricinfo.observer; import cricinfo.enums.MatchStatus; import cricinfo.entity.Match; import cricinfo.entity.Ball; public class UserNotifier implements MatchObserver { @Override public void update(Match match, Ball lastBall) { if (match.getCurrentStatus() == MatchStatus.FINISHED) { System.out.println("[NOTIFICATION]: Match has finished!"); } else if (match.getCurrentStatus() == MatchStatus.IN_BREAK) { System.out.println("[NOTIFICATION]: Inning has ended!"); } else if (lastBall.isWicket()) { System.out.println("[NOTIFICATION]: Wicket! A player is out."); } else if (lastBall.isBoundary()) { System.out.printf("[NOTIFICATION]: It's a boundary! %d runs.%n", lastBall.getRunsScored()); } } } ================================================ FILE: solutions/java/src/cricinfo/repository/MatchRepository.java ================================================ package cricinfo.repository; import cricinfo.entity.Match; import java.util.HashMap; import java.util.Map; import java.util.Optional; public class MatchRepository { private final Map matches = new HashMap<>(); public void save(Match match) { matches.put(match.getId(), match); } public Optional findById(String id) { return Optional.ofNullable(matches.get(id)); } } ================================================ FILE: solutions/java/src/cricinfo/repository/PlayerRepository.java ================================================ package cricinfo.repository; import cricinfo.entity.Player; import java.util.HashMap; import java.util.Map; import java.util.Optional; public class PlayerRepository { private final Map players = new HashMap<>(); public void save(Player player) { players.put(player.getId(), player); } public Optional findById(String id) { return Optional.ofNullable(players.get(id)); } } ================================================ FILE: solutions/java/src/cricinfo/state/FinishedState.java ================================================ package cricinfo.state; import cricinfo.entity.Match; import cricinfo.entity.Ball; public class FinishedState implements MatchState { @Override public void processBall(Match match, Ball ball) { System.out.println("ERROR: Cannot process a ball for a finished match."); } } ================================================ FILE: solutions/java/src/cricinfo/state/InBreakState.java ================================================ package cricinfo.state; import cricinfo.enums.MatchStatus; import cricinfo.entity.Ball; import cricinfo.entity.Match; public class InBreakState implements MatchState { @Override public void processBall(Match match, Ball ball) { System.out.println("ERROR: Cannot process a ball. The match is currently in a break."); } @Override public void startNextInnings(Match match) { System.out.println("Starting the next innings..."); match.createNewInnings(); match.setState(new LiveState()); match.setCurrentStatus(MatchStatus.LIVE); } } ================================================ FILE: solutions/java/src/cricinfo/state/LiveState.java ================================================ package cricinfo.state; import cricinfo.enums.MatchStatus; import cricinfo.entity.Innings; import cricinfo.entity.Match; import cricinfo.entity.Ball; import cricinfo.entity.Team; public class LiveState implements MatchState { @Override public void processBall(Match match, Ball ball) { // 1. Process the ball as usual Innings currentInnings = match.getCurrentInnings(); currentInnings.addBall(ball); match.notifyObservers(ball); // Notify observers about this specific ball // 2. Check for win/end conditions checkForMatchEnd(match); } private void checkForMatchEnd(Match match) { Innings currentInnings = match.getCurrentInnings(); int inningsCount = match.getInnings().size(); boolean isFinalInnings = (inningsCount == match.getFormatStrategy().getTotalInnings()); // --- A. WIN CONDITION: Chasing team surpasses the target --- if (isFinalInnings) { int targetScore = match.getInnings().get(0).getScore() + 1; if (currentInnings.getScore() >= targetScore) { int wicketsRemaining = (currentInnings.getBattingTeam().getPlayers().size() - 1) - currentInnings.getWickets(); declareWinner(match, currentInnings.getBattingTeam(), "won by " + wicketsRemaining + " wickets"); return; // Match is over } } // --- B. END OF INNINGS CONDITION: All out or overs completed --- if (isInningsOver(match)) { if (isFinalInnings) { // The whole match is over, determine winner by runs or a tie int score1 = match.getInnings().get(0).getScore(); int score2 = currentInnings.getScore(); if (score1 > score2) { declareWinner(match, match.getTeam1(), "won by " + (score1 - score2) + " runs"); } else if (score2 > score1) { // This case is technically handled above, but is a good safeguard. int wicketsRemaining = (currentInnings.getBattingTeam().getPlayers().size() - 1) - currentInnings.getWickets(); declareWinner(match, currentInnings.getBattingTeam(), "won by " + wicketsRemaining + " wickets"); } else { declareWinner(match, null, "Match Tied"); // No winner in a tie } } else { // It's just an innings break, not the end of the match System.out.println("End of the innings!"); match.setState(new InBreakState()); match.setCurrentStatus(MatchStatus.IN_BREAK); match.notifyObservers(null); // Signal innings break to observers } } } private void declareWinner(Match match, Team winningTeam, String message) { System.out.println("MATCH FINISHED!"); match.setWinner(winningTeam); String resultMessage = (winningTeam != null) ? winningTeam.getName() + " " + message : message; match.setResultMessage(resultMessage); match.setState(new FinishedState()); match.setCurrentStatus(MatchStatus.FINISHED); match.notifyObservers(null); // Signal match end to observers } private boolean isInningsOver(Match match) { Innings currentInnings = match.getCurrentInnings(); // Condition 1: A team with 11 players is all out when 10 wickets fall. boolean allOut = currentInnings.getWickets() >= currentInnings.getBattingTeam().getPlayers().size() - 1; // Condition 2: All overs have been bowled boolean oversFinished = (int) currentInnings.getOvers() >= match.getFormatStrategy().getTotalOvers(); return allOut || oversFinished; } } ================================================ FILE: solutions/java/src/cricinfo/state/MatchState.java ================================================ package cricinfo.state; import cricinfo.entity.Match; import cricinfo.entity.Ball; public interface MatchState { void processBall(Match match, Ball ball); default void startNextInnings(Match match) { System.out.println("ERROR: Cannot start the next innings from the current state."); } } ================================================ FILE: solutions/java/src/cricinfo/state/ScheduledState.java ================================================ package cricinfo.state; import cricinfo.entity.Match; import cricinfo.entity.Ball; public class ScheduledState implements MatchState { @Override public void processBall(Match match, Ball ball) { System.out.println("ERROR: Cannot process a ball for a match that has not started."); } } ================================================ FILE: solutions/java/src/cricinfo/strategy/MatchFormatStrategy.java ================================================ package cricinfo.strategy; public interface MatchFormatStrategy { int getTotalInnings(); int getTotalOvers(); String getFormatName(); } ================================================ FILE: solutions/java/src/cricinfo/strategy/ODIFormatStrategy.java ================================================ package cricinfo.strategy; public class ODIFormatStrategy implements MatchFormatStrategy { @Override public int getTotalInnings() { return 2; } @Override public int getTotalOvers() { return 50; } @Override public String getFormatName() { return "ODI"; } } ================================================ FILE: solutions/java/src/cricinfo/strategy/T20FormatStrategy.java ================================================ package cricinfo.strategy; public class T20FormatStrategy implements MatchFormatStrategy { @Override public int getTotalInnings() { return 2; } @Override public int getTotalOvers() { return 20; } @Override public String getFormatName() { return "T20"; } } ================================================ FILE: solutions/java/src/digitalwalletservice/Account.java ================================================ package digitalwalletservice; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; public class Account { private final String id; private final User user; private final String accountNumber; private final Currency currency; private BigDecimal balance; private final List transactions; public Account(String id, User user, String accountNumber, Currency currency) { this.id = id; this.user = user; this.accountNumber = accountNumber; this.currency = currency; this.balance = BigDecimal.ZERO; this.transactions = new ArrayList<>(); } public synchronized void deposit(BigDecimal amount) { balance = balance.add(amount); } public synchronized void withdraw(BigDecimal amount) { if (balance.compareTo(amount) >= 0) { balance = balance.subtract(amount); } else { throw new InsufficientFundsException("Insufficient funds in the account."); } } public synchronized void addTransaction(Transaction transaction) { transactions.add(transaction); } public String getId() { return id; } public User getUser() { return user; } public String getAccountNumber() { return accountNumber; } public Currency getCurrency() { return currency; } public BigDecimal getBalance() { return balance; } public List getTransactions() { return transactions; } } ================================================ FILE: solutions/java/src/digitalwalletservice/BankAccount.java ================================================ package digitalwalletservice; import java.math.BigDecimal; public class BankAccount extends PaymentMethod { private final String accountNumber; private final String routingNumber; public BankAccount(String id, User user, String accountNumber, String routingNumber) { super(id, user); this.accountNumber = accountNumber; this.routingNumber = routingNumber; } @Override public boolean processPayment(BigDecimal amount, Currency currency) { // Process bank account payment return true; } } ================================================ FILE: solutions/java/src/digitalwalletservice/CreditCard.java ================================================ package digitalwalletservice; import java.math.BigDecimal; public class CreditCard extends PaymentMethod { private final String cardNumber; private final String expirationDate; private final String cvv; public CreditCard(String id, User user, String cardNumber, String expirationDate, String cvv) { super(id, user); this.cardNumber = cardNumber; this.expirationDate = expirationDate; this.cvv = cvv; } @Override public boolean processPayment(BigDecimal amount, Currency currency) { // Process credit card payment return true; } } ================================================ FILE: solutions/java/src/digitalwalletservice/Currency.java ================================================ package digitalwalletservice; public enum Currency { USD, EUR, GBP, JPY } ================================================ FILE: solutions/java/src/digitalwalletservice/CurrencyConverter.java ================================================ package digitalwalletservice; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.Map; public class CurrencyConverter { private static final Map exchangeRates = new HashMap<>(); static { // Initialize exchange rates exchangeRates.put(Currency.USD, BigDecimal.ONE); exchangeRates.put(Currency.EUR, new BigDecimal("0.85")); exchangeRates.put(Currency.GBP, new BigDecimal("0.72")); exchangeRates.put(Currency.JPY, new BigDecimal("110.00")); // Add more exchange rates as needed } public static BigDecimal convert(BigDecimal amount, Currency sourceCurrency, Currency targetCurrency) { BigDecimal sourceRate = exchangeRates.get(sourceCurrency); BigDecimal targetRate = exchangeRates.get(targetCurrency); return amount.multiply(sourceRate).divide(targetRate, RoundingMode.HALF_UP); } } ================================================ FILE: solutions/java/src/digitalwalletservice/DigitalWallet.java ================================================ package digitalwalletservice; import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class DigitalWallet { private static DigitalWallet instance; private final Map users; private final Map accounts; private final Map paymentMethods; private DigitalWallet() { users = new ConcurrentHashMap<>(); accounts = new ConcurrentHashMap<>(); paymentMethods = new ConcurrentHashMap<>(); } public static synchronized DigitalWallet getInstance() { if (instance == null) { instance = new DigitalWallet(); } return instance; } public void createUser(User user) { users.put(user.getId(), user); } public User getUser(String userId) { return users.get(userId); } public void createAccount(Account account) { accounts.put(account.getId(), account); account.getUser().addAccount(account); } public Account getAccount(String accountId) { return accounts.get(accountId); } public void addPaymentMethod(PaymentMethod paymentMethod) { paymentMethods.put(paymentMethod.getId(), paymentMethod); } public PaymentMethod getPaymentMethod(String paymentMethodId) { return paymentMethods.get(paymentMethodId); } public synchronized void transferFunds(Account sourceAccount, Account destinationAccount, BigDecimal amount, Currency currency) { if (sourceAccount.getCurrency() != currency) { amount = CurrencyConverter.convert(amount, currency, sourceAccount.getCurrency()); } sourceAccount.withdraw(amount); if (destinationAccount.getCurrency() != sourceAccount.getCurrency()) { amount = CurrencyConverter.convert(amount, sourceAccount.getCurrency(), destinationAccount.getCurrency()); } destinationAccount.deposit(amount); String transactionId = generateTransactionId(); Transaction transaction = new Transaction(transactionId, sourceAccount, destinationAccount, amount, destinationAccount.getCurrency()); sourceAccount.addTransaction(transaction); destinationAccount.addTransaction(transaction); } public List getTransactionHistory(Account account) { return account.getTransactions(); } private String generateTransactionId() { return "TXN" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); } } ================================================ FILE: solutions/java/src/digitalwalletservice/DigitalWalletDemo.java ================================================ package digitalwalletservice; import java.math.BigDecimal; import java.util.List; public class DigitalWalletDemo { public static void run() { DigitalWallet digitalWallet = DigitalWallet.getInstance(); // Create users User user1 = new User("U001", "John Doe", "john@example.com", "password123"); User user2 = new User("U002", "Jane Smith", "jane@example.com", "password456"); digitalWallet.createUser(user1); digitalWallet.createUser(user2); // Create accounts Account account1 = new Account("A001", user1, "1234567890", Currency.USD); Account account2 = new Account("A002", user2, "9876543210", Currency.EUR); digitalWallet.createAccount(account1); digitalWallet.createAccount(account2); // Add payment methods PaymentMethod creditCard = new CreditCard("PM001", user1, "1234567890123456", "12/25", "123"); PaymentMethod bankAccount = new BankAccount("PM002", user2, "9876543210", "987654321"); digitalWallet.addPaymentMethod(creditCard); digitalWallet.addPaymentMethod(bankAccount); // Deposit funds account1.deposit(new BigDecimal("1000.00")); account2.deposit(new BigDecimal("500.00")); // Transfer funds digitalWallet.transferFunds(account1, account2, new BigDecimal("100.00"), Currency.USD); // Get transaction history List transactionHistory1 = digitalWallet.getTransactionHistory(account1); List transactionHistory2 = digitalWallet.getTransactionHistory(account2); // Print transaction history System.out.println("Transaction History for Account 1:"); for (Transaction transaction : transactionHistory1) { System.out.println("Transaction ID: " + transaction.getId()); System.out.println("Amount: " + transaction.getAmount() + " " + transaction.getCurrency()); System.out.println("Timestamp: " + transaction.getTimestamp()); System.out.println(); } System.out.println("Transaction History for Account 2:"); for (Transaction transaction : transactionHistory2) { System.out.println("Transaction ID: " + transaction.getId()); System.out.println("Amount: " + transaction.getAmount() + " " + transaction.getCurrency()); System.out.println("Timestamp: " + transaction.getTimestamp()); System.out.println(); } } } ================================================ FILE: solutions/java/src/digitalwalletservice/InsufficientFundsException.java ================================================ package digitalwalletservice; public class InsufficientFundsException extends RuntimeException { public InsufficientFundsException(String message) { super(message); } } ================================================ FILE: solutions/java/src/digitalwalletservice/PaymentMethod.java ================================================ package digitalwalletservice; import java.math.BigDecimal; public abstract class PaymentMethod { protected final String id; protected final User user; public PaymentMethod(String id, User user) { this.id = id; this.user = user; } public abstract boolean processPayment(BigDecimal amount, Currency currency); public String getId() { return id; } public User getUser() { return user; } } ================================================ FILE: solutions/java/src/digitalwalletservice/README.md ================================================ # Digital Wallet Service (LLD) ## Problem Statement Design and implement a Digital Wallet Service that allows users to manage their digital money, make transactions, and link multiple payment methods. The system should handle currency conversions, track transactions, and manage different types of accounts. --- ## Requirements 1. **Account Management:** - Create and manage user accounts - Support multiple payment methods (Bank Account, Credit Card) - Handle account balances and transactions 2. **Transaction Management:** - Process money transfers - Track transaction history - Handle transaction status and types 3. **Payment Methods:** - Support bank account integration - Support credit card integration - Allow adding/removing payment methods 4. **Currency Support:** - Handle multiple currencies - Provide currency conversion - Maintain exchange rates 5. **Security and Validation:** - Validate transactions - Handle insufficient funds - Ensure data consistency --- ## Core Entities ### 1. DigitalWallet - **Fields:** String id, User user, double balance, List paymentMethods, List transactions - **Methods:** addMoney(), sendMoney(), getBalance(), addPaymentMethod(), removePaymentMethod() ### 2. User - **Fields:** String id, String name, String email, String phoneNumber - **Methods:** updateProfile(), getWallet() ### 3. Account - **Fields:** String id, User user, double balance, Currency currency - **Methods:** deposit(), withdraw(), getBalance() ### 4. PaymentMethod - **Fields:** String id, User user, PaymentMethodType type - **Methods:** validate(), processPayment() ### 5. BankAccount - **Fields:** String accountNumber, String bankName, String ifscCode - **Methods:** transfer(), validate() ### 6. CreditCard - **Fields:** String cardNumber, String expiryDate, String cvv - **Methods:** charge(), validate() ### 7. Transaction - **Fields:** String id, Account from, Account to, double amount, Currency currency, TransactionStatus status - **Methods:** process(), cancel(), getStatus() ### 8. Currency - **Fields:** String code, String symbol - **Methods:** getExchangeRate() ### 9. CurrencyConverter - **Methods:** convert(double amount, Currency from, Currency to) --- ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/digitalwalletservice-class-diagram.png) ## Example Usage ```java // Create a new user User user = new User("John Doe", "john@example.com", "1234567890"); // Create a digital wallet DigitalWallet wallet = new DigitalWallet(user); // Add a bank account BankAccount bankAccount = new BankAccount("1234567890", "HDFC Bank", "HDFC0001234"); wallet.addPaymentMethod(bankAccount); // Add money to wallet wallet.addMoney(1000.0, Currency.USD); // Send money to another user User recipient = new User("Jane Doe", "jane@example.com", "9876543210"); wallet.sendMoney(recipient.getWallet(), 500.0, Currency.USD); ``` --- ## Demo See `DigitalWalletDemo.java` for a sample usage and simulation of the digital wallet system. --- ## Extending the Framework - **Add authentication:** Implement user authentication and authorization - **Add transaction limits:** Set and enforce transaction limits - **Add rewards system:** Implement cashback and rewards - **Add bill payments:** Support utility bill payments - **Add investment options:** Support investment in various instruments - **Add notification system:** Send transaction alerts and updates --- ## Design Patterns Used - **Factory Pattern:** For creating different types of payment methods - **Strategy Pattern:** For different payment processing strategies - **Observer Pattern:** For transaction notifications - **Singleton Pattern:** For currency converter service --- ## Exception Handling - **InsufficientFundsException:** Thrown when there are insufficient funds for a transaction - **InvalidPaymentMethodException:** Thrown when payment method validation fails - **TransactionFailedException:** Thrown when transaction processing fails --- ================================================ FILE: solutions/java/src/elevatorsystem/Elevator.java ================================================ package elevatorsystem; import elevatorsystem.enums.Direction; import elevatorsystem.models.Request; import elevatorsystem.observer.ElevatorObserver; import elevatorsystem.state.ElevatorState; import elevatorsystem.state.IdleState; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicInteger; public class Elevator implements Runnable { private final int id; private AtomicInteger currentFloor; private ElevatorState state; private volatile boolean isRunning = true; private final TreeSet upRequests; private final TreeSet downRequests; // Observer Pattern: List of observers private final List observers = new ArrayList<>(); public Elevator(int id) { this.id = id; this.currentFloor = new AtomicInteger(1); this.upRequests = new TreeSet<>(); this.downRequests = new TreeSet<>((a, b) -> b - a); this.state = new IdleState(); } // --- Observer Pattern Methods --- public void addObserver(ElevatorObserver observer) { observers.add(observer); observer.update(this); // Send initial state } public void notifyObservers() { for (ElevatorObserver observer : observers) { observer.update(this); } } // --- State Pattern Methods --- public void setState(ElevatorState state) { this.state = state; notifyObservers(); // Notify observers on direction change } public void move() { state.move(this); } // --- Request Handling --- public synchronized void addRequest(Request request) { System.out.println("Elevator " + id + " processing: " + request); state.addRequest(this, request); } // --- Getters and Setters --- public int getId() { return id; } public int getCurrentFloor() { return currentFloor.get(); } public void setCurrentFloor(int floor) { this.currentFloor.set(floor); notifyObservers(); // Notify observers on floor change } public Direction getDirection() { return state.getDirection(); } public TreeSet getUpRequests() { return upRequests; } public TreeSet getDownRequests() { return downRequests; } public boolean isRunning() { return isRunning; } public void stopElevator() { this.isRunning = false; } @Override public void run() { while (isRunning) { move(); try { Thread.sleep(1000); // Simulate movement time } catch (InterruptedException e) { Thread.currentThread().interrupt(); isRunning = false; } } } } ================================================ FILE: solutions/java/src/elevatorsystem/ElevatorSystem.java ================================================ package elevatorsystem; import elevatorsystem.enums.Direction; import elevatorsystem.enums.RequestSource; import elevatorsystem.models.Request; import elevatorsystem.observer.ElevatorDisplay; import elevatorsystem.strategy.ElevatorSelectionStrategy; import elevatorsystem.strategy.NearestElevatorStrategy; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; public class ElevatorSystem { private static ElevatorSystem instance; private final Map elevators; private final ElevatorSelectionStrategy selectionStrategy; private final ExecutorService executorService; private ElevatorSystem(int numElevators) { this.selectionStrategy = new NearestElevatorStrategy(); this.executorService = Executors.newFixedThreadPool(numElevators); List elevatorList = new ArrayList<>(); ElevatorDisplay elevatorDisplay = new ElevatorDisplay(); // Create the observer for (int i = 1; i <= numElevators; i++) { Elevator elevator = new Elevator(i); elevator.addObserver(elevatorDisplay); // Attach the observer elevatorList.add(elevator); } this.elevators = elevatorList.stream().collect(Collectors.toMap(Elevator::getId, e -> e)); } public static synchronized ElevatorSystem getInstance(int numElevators) { if (instance == null) { instance = new ElevatorSystem(numElevators); } return instance; } public void start() { for (Elevator elevator : elevators.values()) { executorService.submit(elevator); } } // --- Facade Methods --- // EXTERNAL Request (Hall Call) public void requestElevator(int floor, Direction direction) { System.out.println("\n>> EXTERNAL Request: User at floor " + floor + " wants to go " + direction); Request request = new Request(floor, direction, RequestSource.EXTERNAL); // Use strategy to find the best elevator Optional selectedElevator = selectionStrategy.selectElevator(new ArrayList<>(elevators.values()), request); if(selectedElevator.isPresent()) { selectedElevator.get().addRequest(request); } else { System.out.println("System busy, please wait."); } } // INTERNAL Request (Cabin Call) public void selectFloor(int elevatorId, int destinationFloor) { System.out.println("\n>> INTERNAL Request: User in Elevator " + elevatorId + " selected floor " + destinationFloor); Request request = new Request(destinationFloor, Direction.IDLE, RequestSource.INTERNAL); Elevator elevator = elevators.get(elevatorId); if (elevator != null) { elevator.addRequest(request); } else { System.err.println("Invalid elevator ID."); } } public void shutdown() { System.out.println("Shutting down elevator system..."); for (Elevator elevator : elevators.values()) { elevator.stopElevator(); } executorService.shutdown(); } } ================================================ FILE: solutions/java/src/elevatorsystem/ElevatorSystemDemo.java ================================================ package elevatorsystem; import elevatorsystem.enums.Direction; public class ElevatorSystemDemo { public static void main(String[] args) throws InterruptedException { // Setup: A building with 2 elevators int numElevators = 2; // The getInstance method now initializes the elevators and attaches the Display (Observer). ElevatorSystem elevatorSystem = ElevatorSystem.getInstance(numElevators); // Start the elevator system elevatorSystem.start(); System.out.println("Elevator system started. ConsoleDisplay is observing.\n"); // --- SIMULATION START --- // 1. External Request: User at floor 5 wants to go UP. // The system will dispatch this to the nearest elevator (likely E1 or E2, both at floor 1). elevatorSystem.requestElevator(5, Direction.UP); Thread.sleep(100); // Wait for the elevator to start moving // 2. Internal Request: Assume E1 took the previous request. // The user gets in at floor 5 and presses 10. // We send this request directly to E1. // Note: In a real simulation, we'd wait until E1 reaches floor 5, but for this demo, // we simulate the internal button press shortly after the external one. elevatorSystem.selectFloor(1, 10); Thread.sleep(200); // 3. External Request: User at floor 3 wants to go DOWN. // E2 (likely still idle at floor 1) might take this, or E1 if it's convenient. elevatorSystem.requestElevator(3, Direction.DOWN); Thread.sleep(300); // 4. Internal Request: User in E2 presses 1. elevatorSystem.selectFloor(2, 1); // Let the simulation run for a while to observe the display updates System.out.println("\n--- Letting simulation run for 1 second ---"); Thread.sleep(1000); // Shutdown the system elevatorSystem.shutdown(); System.out.println("\n--- SIMULATION END ---"); } } ================================================ FILE: solutions/java/src/elevatorsystem/README.md ================================================ # Elevator System (LLD) ## Problem Statement Design and implement an Elevator System that can handle multiple requests, move between floors, and manage direction and vendingMachineState efficiently. --- ## Requirements - **Multiple Elevator:** The system manages multiple elevators. - **Request Handling:** The system can handle requests to move to specific floors in a given direction (UP/DOWN). - **Direction Management:** The elevator maintains and updates its current direction (UP, DOWN, IDLE). - **State Management:** The elevator tracks its current floor, direction, and pending requests. - **Efficient Movement:** The elevator processes requests in an efficient order (e.g., all UP requests, then all DOWN requests). - **Extensibility:** Easy to add more elevators or advanced scheduling algorithms. --- ## Core Entities - **Elevator:** Represents the elevator, manages its vendingMachineState, direction, and request queue. - **ElevatorController:** Handles incoming requests and delegates them to the elevator. - **Request:** Represents a request to move to a specific floor in a given direction. - **Direction (enum):** UP, DOWN, IDLE. --- ## Class Design ### 1. Elevator - **Fields:** currentFloor, direction, List requests, isMoving, etc. - **Methods:** addRequest(Request), move(), openDoor(), closeDoor(), processNextRequest(), getCurrentFloor(), getDirection(), etc. ### 2. ElevatorController - **Fields:** Elevator elevator - **Methods:** requestElevator(int floor, Direction direction), step(), etc. ### 3. Request - **Fields:** int floor, Direction direction ### 4. Direction (enum) - Values: UP, DOWN, IDLE ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/elevatorsystem-class-diagram.png) --- ## Example Usage ```java ElevatorController controller = new ElevatorController(); controller.requestElevator(5, Direction.UP); controller.requestElevator(2, Direction.DOWN); // Simulate elevator steps for (int i = 0; i < 10; i++) { controller.step(); } ``` --- ## Demo See `ElevatorSystemDemo.java` for a sample usage and simulation of the elevator system. --- ## Extending the Framework - **Add multiple elevators:** Create a list of `Elevator` objects and update the controller logic. - **Advanced scheduling:** Implement algorithms for optimal elevator assignment. - **Add features:** Such as maintenance mode, emergency stop, or floor elevatorDisplay. --- ================================================ FILE: solutions/java/src/elevatorsystem/enums/Direction.java ================================================ package elevatorsystem.enums; public enum Direction { UP, DOWN, IDLE } ================================================ FILE: solutions/java/src/elevatorsystem/enums/RequestSource.java ================================================ package elevatorsystem.enums; public enum RequestSource { INTERNAL, // From inside the cabin EXTERNAL // From the hall/floor } ================================================ FILE: solutions/java/src/elevatorsystem/models/Request.java ================================================ package elevatorsystem.models; import elevatorsystem.enums.Direction; import elevatorsystem.enums.RequestSource; public class Request { private final int targetFloor; private final Direction direction; // Primarily for External requests private final RequestSource source; public Request(int targetFloor, Direction direction, RequestSource source) { this.targetFloor = targetFloor; this.direction = direction; this.source = source; } public int getTargetFloor() { return targetFloor; } public Direction getDirection() { return direction; } public RequestSource getSource() { return source; } @Override public String toString() { return source + " Request to floor " + targetFloor + (source == RequestSource.EXTERNAL ? " going " + direction : ""); } } ================================================ FILE: solutions/java/src/elevatorsystem/observer/ElevatorDisplay.java ================================================ package elevatorsystem.observer; import elevatorsystem.Elevator; public class ElevatorDisplay implements ElevatorObserver { @Override public void update(Elevator elevator) { System.out.println("[DISPLAY] Elevator " + elevator.getId() + " | Current Floor: " + elevator.getCurrentFloor() + " | Direction: " + elevator.getDirection()); } } ================================================ FILE: solutions/java/src/elevatorsystem/observer/ElevatorObserver.java ================================================ package elevatorsystem.observer; import elevatorsystem.Elevator; public interface ElevatorObserver { void update(Elevator elevator); } ================================================ FILE: solutions/java/src/elevatorsystem/state/ElevatorState.java ================================================ package elevatorsystem.state; import elevatorsystem.Elevator; import elevatorsystem.enums.Direction; import elevatorsystem.models.Request; public interface ElevatorState { void move(Elevator elevator); void addRequest(Elevator elevator, Request request); Direction getDirection(); } ================================================ FILE: solutions/java/src/elevatorsystem/state/IdleState.java ================================================ package elevatorsystem.state; import elevatorsystem.Elevator; import elevatorsystem.enums.Direction; import elevatorsystem.models.Request; public class IdleState implements ElevatorState { @Override public void move(Elevator elevator) { if (!elevator.getUpRequests().isEmpty()) { elevator.setState(new MovingUpState()); } else if (!elevator.getDownRequests().isEmpty()) { elevator.setState(new MovingDownState()); } // Else stay idle } @Override public void addRequest(Elevator elevator, Request request) { if (request.getTargetFloor() > elevator.getCurrentFloor()) { elevator.getUpRequests().add(request.getTargetFloor()); } else if (request.getTargetFloor() < elevator.getCurrentFloor()) { elevator.getDownRequests().add(request.getTargetFloor()); } // If request is for current floor, doors would open (handled implicitly by moving to that floor) } @Override public Direction getDirection() { return Direction.IDLE; } } ================================================ FILE: solutions/java/src/elevatorsystem/state/MovingDownState.java ================================================ package elevatorsystem.state; import elevatorsystem.Elevator; import elevatorsystem.enums.Direction; import elevatorsystem.enums.RequestSource; import elevatorsystem.models.Request; public class MovingDownState implements ElevatorState { @Override public void move(Elevator elevator) { if (elevator.getDownRequests().isEmpty()) { elevator.setState(new IdleState()); return; } Integer nextFloor = elevator.getDownRequests().first(); elevator.setCurrentFloor(elevator.getCurrentFloor() - 1); if (elevator.getCurrentFloor() == nextFloor) { System.out.println("Elevator " + elevator.getId() + " stopped at floor " + nextFloor); elevator.getDownRequests().pollFirst(); } if (elevator.getDownRequests().isEmpty()) { elevator.setState(new IdleState()); } } @Override public void addRequest(Elevator elevator, Request request) { // Internal requests always get added to the appropriate queue if (request.getSource() == RequestSource.INTERNAL) { if (request.getTargetFloor() > elevator.getCurrentFloor()) { elevator.getUpRequests().add(request.getTargetFloor()); } else { elevator.getDownRequests().add(request.getTargetFloor()); } return; } // External requests if (request.getDirection() == Direction.DOWN && request.getTargetFloor() <= elevator.getCurrentFloor()) { elevator.getDownRequests().add(request.getTargetFloor()); } else if (request.getDirection() == Direction.UP) { elevator.getUpRequests().add(request.getTargetFloor()); } } @Override public Direction getDirection() { return Direction.DOWN; } } ================================================ FILE: solutions/java/src/elevatorsystem/state/MovingUpState.java ================================================ package elevatorsystem.state; import elevatorsystem.Elevator; import elevatorsystem.enums.Direction; import elevatorsystem.enums.RequestSource; import elevatorsystem.models.Request; public class MovingUpState implements ElevatorState { @Override public void move(Elevator elevator) { if (elevator.getUpRequests().isEmpty()) { elevator.setState(new IdleState()); return; } Integer nextFloor = elevator.getUpRequests().first(); elevator.setCurrentFloor(elevator.getCurrentFloor() + 1); if (elevator.getCurrentFloor() == nextFloor) { System.out.println("Elevator " + elevator.getId() + " stopped at floor " + nextFloor); elevator.getUpRequests().pollFirst(); } if (elevator.getUpRequests().isEmpty()) { elevator.setState(new IdleState()); } } @Override public void addRequest(Elevator elevator, Request request) { // Internal requests always get added to the appropriate queue if (request.getSource() == RequestSource.INTERNAL) { if (request.getTargetFloor() > elevator.getCurrentFloor()) { elevator.getUpRequests().add(request.getTargetFloor()); } else { elevator.getDownRequests().add(request.getTargetFloor()); } return; } // External requests if (request.getDirection() == Direction.UP && request.getTargetFloor() >= elevator.getCurrentFloor()) { elevator.getUpRequests().add(request.getTargetFloor()); } else if (request.getDirection() == Direction.DOWN) { elevator.getDownRequests().add(request.getTargetFloor()); } } @Override public Direction getDirection() { return Direction.UP; } } ================================================ FILE: solutions/java/src/elevatorsystem/strategy/ElevatorSelectionStrategy.java ================================================ package elevatorsystem.strategy; import elevatorsystem.Elevator; import elevatorsystem.models.Request; import java.util.List; import java.util.Optional; public interface ElevatorSelectionStrategy { Optional selectElevator(List elevators, Request request); } ================================================ FILE: solutions/java/src/elevatorsystem/strategy/NearestElevatorStrategy.java ================================================ package elevatorsystem.strategy; import elevatorsystem.Elevator; import elevatorsystem.enums.Direction; import elevatorsystem.models.Request; import java.util.List; import java.util.Optional; public class NearestElevatorStrategy implements ElevatorSelectionStrategy { @Override public Optional selectElevator(List elevators, Request request) { Elevator bestElevator = null; int minDistance = Integer.MAX_VALUE; for (Elevator elevator : elevators) { if (isSuitable(elevator, request)) { int distance = Math.abs(elevator.getCurrentFloor() - request.getTargetFloor()); if (distance < minDistance) { minDistance = distance; bestElevator = elevator; } } } return Optional.ofNullable(bestElevator); } private boolean isSuitable(Elevator elevator, Request request) { if (elevator.getDirection() == Direction.IDLE) return true; if (elevator.getDirection() == request.getDirection()) { if (request.getDirection() == Direction.UP && elevator.getCurrentFloor() <= request.getTargetFloor()) return true; if (request.getDirection() == Direction.DOWN && elevator.getCurrentFloor() >= request.getTargetFloor()) return true; } return false; } } ================================================ FILE: solutions/java/src/filedirectory/AbstractNode.java ================================================ package filedirectory; import java.util.Date; // Abstract class for files and directories public abstract class AbstractNode { protected String name; protected Date createdAt; public AbstractNode(String name) { this.name = name; this.createdAt = new Date(); } public String getName() { return name; } public Date getCreatedAt() { return createdAt; } } ================================================ FILE: solutions/java/src/filedirectory/DirectoryNode.java ================================================ package filedirectory; import java.util.*; // Directory Node containing files and subdirectories public class DirectoryNode extends AbstractNode { private Map children; public DirectoryNode(String name) { super(name); this.children = new HashMap<>(); } public void addNode(AbstractNode node) { children.put(node.getName(), node); } public List getChildren() { return new ArrayList<>(children.values()); } public AbstractNode getNode(String name) { return children.get(name); } } ================================================ FILE: solutions/java/src/filedirectory/FileNode.java ================================================ package filedirectory; // File Node with metadata public class FileNode extends AbstractNode { private String content; private int size; public FileNode(String name) { super(name); this.content = ""; this.size = 0; } public void appendContent(String newContent) { this.content += newContent; this.size += newContent.length(); } public String readContent() { return content; } public int getSize() { return size; } } ================================================ FILE: solutions/java/src/filedirectory/FileSystem.java ================================================ package filedirectory; import filedirectory.strategy.NodeSearchStrategy; import java.util.*; public class FileSystem { private DirectoryNode root; public FileSystem() { this.root = new DirectoryNode("/"); } private DirectoryNode traverse(String path, boolean createMissingDirs) { String[] parts = path.split("/"); DirectoryNode current = root; for (int i = 1; i < parts.length; i++) { if (!(current.getNode(parts[i]) instanceof DirectoryNode)) { if (createMissingDirs) { current.addNode(new DirectoryNode(parts[i])); } else { return null; } } current = (DirectoryNode) current.getNode(parts[i]); } return current; } public void mkdir(String path) { traverse(path, true); } public void addFile(String filePath, String content) { DirectoryNode parent = traverse(filePath.substring(0, filePath.lastIndexOf("/")), true); String fileName = filePath.substring(filePath.lastIndexOf("/") + 1); FileNode file = (FileNode) parent.getNode(fileName); if (file == null) { file = new FileNode(fileName); parent.addNode(file); } file.appendContent(content); } public List searchNodes(String directoryPath, NodeSearchStrategy strategy, Map params) { DirectoryNode directory = traverse(directoryPath, false); if (directory == null) { throw new IllegalArgumentException("Directory not found: " + directoryPath); } return strategy.search(directory, params); } } ================================================ FILE: solutions/java/src/filedirectory/FileSystemDemo.java ================================================ package filedirectory; import filedirectory.strategy.*; import java.util.HashMap; import java.util.List; import java.util.Map; public class FileSystemDemo { public static void main(String[] args) { FileSystem fs = new FileSystem(); fs.mkdir("/a/b/c"); fs.addFile("/a/b/c/file1.txt", "Hello"); fs.addFile("/a/b/c/file2.log", "Data"); fs.addFile("/a/file3.txt", "Some large content to increase file size..."); fs.addFile("/a/file4.txt", "Short"); System.out.println("Searching for files and directories matching regex 'file.*\\.txt' with size between 5 and 50 bytes:"); NodeSearchStrategy strategy = new FilenameAndSizeSearchStrategy(); Map searchParams = new HashMap<>(); searchParams.put("filenameRegex", "file.*\\.txt"); searchParams.put("minSize", 5); searchParams.put("maxSize", 50); List foundNodes = fs.searchNodes("/a", strategy, searchParams); for (AbstractNode node : foundNodes) { if (node instanceof FileNode) { System.out.println("[FILE] " + node.getName() + " (Size: " + ((FileNode) node).getSize() + " bytes)"); } else { System.out.println("[DIR] " + node.getName()); } } } } ================================================ FILE: solutions/java/src/filedirectory/chainofresponsibility/FileSizeFilter.java ================================================ package filedirectory.chainofresponsibility; import filedirectory.AbstractNode; import filedirectory.FileNode; import filedirectory.chainofresponsibility.NodeFilter; import java.util.Map; public class FileSizeFilter implements NodeFilter { @Override public boolean apply(AbstractNode node, Map params) { if (!(node instanceof FileNode)) return true; if (!params.containsKey("minSize") || !params.containsKey("maxSize")) return true; int minSize = (int) params.get("minSize"); int maxSize = (int) params.get("maxSize"); int size = ((FileNode) node).getSize(); return size >= minSize && size <= maxSize; } } ================================================ FILE: solutions/java/src/filedirectory/chainofresponsibility/FilenameFilter.java ================================================ package filedirectory.chainofresponsibility; import filedirectory.AbstractNode; import java.util.Map; import java.util.regex.Pattern; // Concrete Filter: Filter by filename regex public class FilenameFilter implements NodeFilter { @Override public boolean apply(AbstractNode node, Map params) { if (!params.containsKey("filenameRegex")) return true; String regex = (String) params.get("filenameRegex"); return Pattern.matches(regex, node.getName()); } } ================================================ FILE: solutions/java/src/filedirectory/chainofresponsibility/NodeFilter.java ================================================ package filedirectory.chainofresponsibility; import filedirectory.AbstractNode; import java.util.Map; public interface NodeFilter { boolean apply(AbstractNode node, Map params); } ================================================ FILE: solutions/java/src/filedirectory/chainofresponsibility/NodeFilterChain.java ================================================ package filedirectory.chainofresponsibility; import filedirectory.AbstractNode; import java.util.*; // Chain of Responsibility: Combines multiple filters public class NodeFilterChain { private List filters; public NodeFilterChain() { this.filters = new ArrayList<>(); } public void addFilter(NodeFilter filter) { filters.add(filter); } public boolean applyFilters(AbstractNode node, Map params) { for (NodeFilter filter : filters) { if (!filter.apply(node, params)) { return false; // If any filter fails, reject the node } } return true; } } ================================================ FILE: solutions/java/src/filedirectory/strategy/FilenameAndSizeSearchStrategy.java ================================================ package filedirectory.strategy; import filedirectory.*; import filedirectory.chainofresponsibility.FileSizeFilter; import filedirectory.chainofresponsibility.FilenameFilter; import filedirectory.chainofresponsibility.NodeFilterChain; import java.util.*; public class FilenameAndSizeSearchStrategy implements NodeSearchStrategy { private NodeFilterChain filterChain; public FilenameAndSizeSearchStrategy() { this.filterChain = new NodeFilterChain(); filterChain.addFilter(new FilenameFilter()); filterChain.addFilter(new FileSizeFilter()); } @Override public List search(DirectoryNode directory, Map params) { List result = new ArrayList<>(); searchRecursive(directory, params, result); return result; } private void searchRecursive(DirectoryNode dir, Map params, List result) { for (AbstractNode node : dir.getChildren()) { if (filterChain.applyFilters(node, params)) { result.add(node); } if (node instanceof DirectoryNode) { searchRecursive((DirectoryNode) node, params, result); } } } } ================================================ FILE: solutions/java/src/filedirectory/strategy/NodeSearchStrategy.java ================================================ package filedirectory.strategy; import filedirectory.AbstractNode; import filedirectory.DirectoryNode; import java.util.*; public // Search strategy interface interface NodeSearchStrategy { List search(DirectoryNode directory, Map params); } ================================================ FILE: solutions/java/src/fooddeliveryservice/FoodDeliveryService.java ================================================ package fooddeliveryservice; import fooddeliveryservice.entity.*; import fooddeliveryservice.order.Order; import fooddeliveryservice.order.OrderItem; import fooddeliveryservice.order.OrderStatus; import fooddeliveryservice.search.RestaurantSearchStrategy; import fooddeliveryservice.strategy.DeliveryAssignmentStrategy; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; public class FoodDeliveryService { private static volatile FoodDeliveryService instance; private final Map customers = new ConcurrentHashMap<>(); private final Map restaurants = new ConcurrentHashMap<>(); private final Map deliveryAgents = new ConcurrentHashMap<>(); private final Map orders = new ConcurrentHashMap<>(); private DeliveryAssignmentStrategy assignmentStrategy; private FoodDeliveryService() {} public static FoodDeliveryService getInstance() { if (instance == null) { synchronized (FoodDeliveryService.class) { if (instance == null) instance = new FoodDeliveryService(); } } return instance; } public void setAssignmentStrategy(DeliveryAssignmentStrategy assignmentStrategy) { this.assignmentStrategy = assignmentStrategy; } // --- Registration --- public Customer registerCustomer(String name, String phone, Address address) { Customer customer = new Customer(name, phone, address); customers.put(customer.getId(), customer); return customer; } public Restaurant registerRestaurant(String name, Address address) { Restaurant restaurant = new Restaurant(name, address); restaurants.put(restaurant.getId(), restaurant); return restaurant; } public DeliveryAgent registerDeliveryAgent(String name, String phone, Address initialLocation) { DeliveryAgent deliveryAgent = new DeliveryAgent(name, phone, initialLocation); deliveryAgents.put(deliveryAgent.getId(), deliveryAgent); return deliveryAgent; } public Order placeOrder(String customerId, String restaurantId, List items) { Customer customer = customers.get(customerId); Restaurant restaurant = restaurants.get(restaurantId); if (customer == null || restaurant == null) throw new NoSuchElementException("Customer or Restaurant not found."); Order order = new Order(customer, restaurant, items); orders.put(order.getId(), order); customer.addOrderToHistory(order); System.out.printf("Order %s placed by %s at %s.\n", order.getId(), customer.getName(), restaurant.getName()); // Initial PENDING status is set in constructor and observers are notified. order.setStatus(OrderStatus.PENDING); return order; } public void updateOrderStatus(String orderId, OrderStatus newStatus) { Order order = orders.get(orderId); if (order == null) throw new NoSuchElementException("Order not found."); order.setStatus(newStatus); // If order is ready, find a delivery agent. if (newStatus == OrderStatus.READY_FOR_PICKUP) { assignDelivery(order); } } public void cancelOrder(String orderId) { Order order = orders.get(orderId); if (order == null) { System.out.println("ERROR: Order with ID " + orderId + " not found."); return; } // Delegate the cancellation logic to the Order object itself. if (order.cancel()) { System.out.println("SUCCESS: Order " + orderId + " has been successfully canceled."); } else { System.out.println("FAILED: Order " + orderId + " could not be canceled. Its status is: " + order.getStatus()); } } private void assignDelivery(Order order) { List availableAgents = new ArrayList<>(deliveryAgents.values()); assignmentStrategy.findAgent(order, availableAgents).ifPresentOrElse( agent -> { order.assignDeliveryAgent(agent); System.out.printf("Agent %s (dist: %.2f) assigned to order %s.\n", agent.getName(), agent.getCurrentLocation().distanceTo(order.getRestaurant().getAddress()), order.getId()); order.setStatus(OrderStatus.OUT_FOR_DELIVERY); }, () -> System.out.println("No available delivery agents found for order " + order.getId()) ); } public List searchRestaurants(List strategies) { // Start with the full list of restaurants List results = new ArrayList<>(restaurants.values()); // Sequentially apply each filter strategy // We can also use chain of responsibility design pattern here for (RestaurantSearchStrategy strategy : strategies) { results = strategy.filter(results); } return results; } public Menu getRestaurantMenu(String restaurantId) { Restaurant restaurant = restaurants.get(restaurantId); if (restaurant == null) { throw new NoSuchElementException("Restaurant with ID " + restaurantId + " not found."); } return restaurant.getMenu(); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/FoodDeliveryServiceDemo.java ================================================ package fooddeliveryservice; import fooddeliveryservice.entity.*; import fooddeliveryservice.order.OrderItem; import fooddeliveryservice.order.OrderStatus; import fooddeliveryservice.search.RestaurantSearchStrategy; import fooddeliveryservice.search.SearchByCityStrategy; import fooddeliveryservice.search.SearchByMenuKeywordStrategy; import fooddeliveryservice.search.SearchByProximityStrategy; import fooddeliveryservice.strategy.NearestAvailableAgentStrategy; import java.util.List; public class FoodDeliveryServiceDemo { public static void main(String[] args) { // 1. Setup the system FoodDeliveryService service = FoodDeliveryService.getInstance(); service.setAssignmentStrategy(new NearestAvailableAgentStrategy()); // 2. Define Addresses Address aliceAddress = new Address("123 Maple St", "Springfield", "12345", 40.7128, -74.0060); Address pizzaAddress = new Address("456 Oak Ave", "Springfield", "12345", 40.7138, -74.0070); Address burgerAddress = new Address("789 Pine Ln", "Springfield", "12345", 40.7108, -74.0050); Address tacoAddress = new Address("101 Elm Ct", "Shelbyville", "54321", 41.7528, -75.0160); // 3. Register entities Customer alice = service.registerCustomer("Alice", "123-4567-890", aliceAddress); Restaurant pizzaPalace = service.registerRestaurant("Pizza Palace", pizzaAddress); Restaurant burgerBarn = service.registerRestaurant("Burger Barn", burgerAddress); Restaurant tacoTown = service.registerRestaurant("Taco Town", tacoAddress); service.registerDeliveryAgent("Bob", "321-4567-880", new Address("1 B", "Springfield", "12345", 40.71, -74.00)); // 4. Setup menus pizzaPalace.addToMenu(new MenuItem("P001", "Margherita Pizza", 12.99)); pizzaPalace.addToMenu(new MenuItem("P002", "Veggie Pizza", 11.99)); burgerBarn.addToMenu(new MenuItem("B001", "Classic Burger", 8.99)); tacoTown.addToMenu(new MenuItem("T001", "Crunchy Taco", 3.50)); // 5. Demonstrate Search Functionality System.out.println("\n--- 1. Searching for Restaurants ---"); // (A) Search by City System.out.println("\n(A) Restaurants in 'Springfield':"); List citySearch = List.of(new SearchByCityStrategy("Springfield")); List springfieldRestaurants = service.searchRestaurants(citySearch); springfieldRestaurants.forEach(r -> System.out.println(" - " + r.getName())); // (B) Search for restaurants near Alice System.out.println("\n(B) Restaurants near Alice (within 0.01 distance units):"); List proximitySearch = List.of(new SearchByProximityStrategy(aliceAddress, 0.01)); List nearbyRestaurants = service.searchRestaurants(proximitySearch); nearbyRestaurants.forEach(r -> System.out.printf(" - %s (Distance: %.4f)\n", r.getName(), aliceAddress.distanceTo(r.getAddress()))); // (C) Search for restaurants that serve 'Pizza' System.out.println("\n(C) Restaurants that serve 'Pizza':"); List menuSearch = List.of(new SearchByMenuKeywordStrategy("Pizza")); List pizzaRestaurants = service.searchRestaurants(menuSearch); pizzaRestaurants.forEach(r -> System.out.println(" - " + r.getName())); // (D) Combined Search: Find restaurants near Alice that serve 'Burger' System.out.println("\n(D) Burger joints near Alice:"); List combinedSearch = List.of( new SearchByProximityStrategy(aliceAddress, 0.01), new SearchByMenuKeywordStrategy("Burger") ); List burgerJointsNearAlice = service.searchRestaurants(combinedSearch); burgerJointsNearAlice.forEach(r -> System.out.println(" - " + r.getName())); // 6. Demonstrate Browsing a Menu System.out.println("\n--- 2. Browsing a Menu ---"); System.out.println("\nMenu for 'Pizza Palace':"); Menu pizzaMenu = service.getRestaurantMenu(pizzaPalace.getId()); pizzaMenu.getItems().values().forEach(item -> System.out.printf(" - %s: $%.2f\n", item.getName(), item.getPrice()) ); // 7. Alice places an order from a searched restaurant System.out.println("\n--- 3. Placing an Order ---"); if (!pizzaRestaurants.isEmpty()) { Restaurant chosenRestaurant = pizzaRestaurants.get(0); MenuItem chosenItem = chosenRestaurant.getMenu().getItem("P001"); System.out.printf("\nAlice is ordering '%s' from '%s'.\n", chosenItem.getName(), chosenRestaurant.getName()); var order = service.placeOrder(alice.getId(), chosenRestaurant.getId(), List.of(new OrderItem(chosenItem, 1))); System.out.println("\n--- Restaurant starts preparing the order ---"); service.updateOrderStatus(order.getId(), OrderStatus.PREPARING); System.out.println("\n--- Order is ready for pickup ---"); System.out.println("System will now find the nearest available delivery agent..."); service.updateOrderStatus(order.getId(), OrderStatus.READY_FOR_PICKUP); System.out.println("\n--- Agent delivers the order ---"); service.updateOrderStatus(order.getId(), OrderStatus.DELIVERED); } } } ================================================ FILE: solutions/java/src/fooddeliveryservice/README.md ================================================ # Food Delivery Service (LLD) ## Problem Statement Design and implement a Food Delivery Service system that allows customers to place orders from restaurants, manages menu items, assigns delivery agents, and tracks order status from placement to delivery. --- ## Requirements - **Customer Registration:** Customers can register and place orders. - **Restaurant Management:** The system manages multiple restaurants, each with its own menu. - **Menu Management:** Restaurants can add and update menu items. - **Order Placement:** Customers can place orders for menu items from a restaurantManagementSystem. - **Order Tracking:** The system tracks the status of each order (e.g., PLACED, PREPARING, OUT_FOR_DELIVERY, DELIVERED). - **Delivery Assignment:** Orders are assigned to available delivery agents. - **Delivery Agent Management:** The system manages delivery agents and their availability. - **Extensibility:** Easy to add new features such as ratings, reviews, or payment integration. --- ## Core Entities - **FoodDeliveryService:** Main class that manages customers, restaurants, orders, and delivery agents. - **Customer:** Represents a customer who can place orders. - **Restaurant:** Represents a restaurantManagementSystem with a menu of items. - **MenuItem:** Represents an item on a restaurantManagementSystem's menu. - **Order:** Represents a customer's order, including items, status, and assigned delivery agent. - **DeliveryAgent:** Represents a delivery agent who delivers orders. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/fooddeliveryservice-class-diagram.png) ### 1. FoodDeliveryService - **Fields:** List customers, List restaurants, List agents, List orders - **Methods:** registerCustomer(Customer), addRestaurant(Restaurant), addMenuItem(Restaurant, MenuItem), placeOrder(Customer, Restaurant, List), assignDeliveryAgent(Order), updateOrderStatus(Order, Status), etc. ### 2. Customer - **Fields:** int id, String name, List orders ### 3. Restaurant - **Fields:** int id, String name, List menu ### 4. MenuItem - **Fields:** int id, String name, double price ### 5. Order - **Fields:** int id, Customer customer, Restaurant restaurantManagementSystem, List items, OrderStatus status, DeliveryAgent agent ### 6. DeliveryAgent - **Fields:** int id, String name, boolean available, List assignedOrders --- ## Example Usage ```java FoodDeliveryService service = new FoodDeliveryService(); Customer alice = new Customer(1, "Alice"); Restaurant pizzaPlace = new Restaurant(1, "Pizza Place"); MenuItem pizza = new MenuItem(1, "Margherita Pizza", 10.0); service.registerCustomer(alice); service.addRestaurant(pizzaPlace); service.addMenuItem(pizzaPlace, pizza); service.placeOrder(alice, pizzaPlace, List.of(pizza)); ``` --- ## Demo See `FoodDeliveryServiceDemo.java` for a sample usage and simulation of the food delivery service. --- ## Extending the Framework - **Add ratings and reviews:** Allow customers to rate restaurants and delivery agents. - **Add payment integration:** Support online payments. - **Add order cancellation or modification:** Allow customers to cancel or modify orders before delivery. --- ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/Address.java ================================================ package fooddeliveryservice.entity; public class Address { private String street; private String city; private String zipCode; private double latitude; private double longitude; public Address(String street, String city, String zipCode, double latitude, double longitude) { this.street = street; this.city = city; this.zipCode = zipCode; this.latitude = latitude; this.longitude = longitude; } public String getCity() { return city; } public double distanceTo(Address other) { double latDiff = this.latitude - other.latitude; double lonDiff = this.longitude - other.longitude; return Math.sqrt(latDiff * latDiff + lonDiff * lonDiff); } @Override public String toString() { return street + ", " + city + ", " + zipCode + " @(" + latitude + ", " + longitude + ")"; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/Customer.java ================================================ package fooddeliveryservice.entity; import fooddeliveryservice.order.Order; import java.util.ArrayList; import java.util.List; public class Customer extends User { private Address address; private final List orderHistory = new ArrayList<>(); public Customer(String name, String phone, Address address) { super(name, phone); this.address = address; } public void addOrderToHistory(Order order) { this.orderHistory.add(order); } public Address getAddress() { return address; } @Override public void onUpdate(Order order) { System.out.printf("--- Notification for Customer %s ---\n", getName()); System.out.printf(" Order %s is now %s.\n", order.getId(), order.getStatus()); System.out.println("-------------------------------------\n"); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/DeliveryAgent.java ================================================ package fooddeliveryservice.entity; import fooddeliveryservice.order.Order; import java.util.concurrent.atomic.AtomicBoolean; public class DeliveryAgent extends User { private final AtomicBoolean isAvailable = new AtomicBoolean(true); private Address currentLocation; public DeliveryAgent(String name, String phone, Address currentLocation) { super(name, phone); this.currentLocation = currentLocation; } public void setAvailable(boolean available) { this.isAvailable.set(available); } public synchronized boolean isAvailable() { return isAvailable.get(); } public void setCurrentLocation(Address currentLocation) { this.currentLocation = currentLocation; } public Address getCurrentLocation() { return currentLocation; } @Override public void onUpdate(Order order) { System.out.printf("--- Notification for Delivery Agent %s ---\n", getName()); System.out.printf(" Order %s update: Status is %s.\n", order.getId(), order.getStatus()); System.out.println("-------------------------------------------\n"); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/Menu.java ================================================ package fooddeliveryservice.entity; import java.util.HashMap; import java.util.Map; public class Menu { private final Map items = new HashMap<>(); public void addItem(MenuItem item) { items.put(item.getId(), item); } public MenuItem getItem(String id) { return items.get(id); } public Map getItems() { return items; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/MenuItem.java ================================================ package fooddeliveryservice.entity; public class MenuItem { private final String id; private final String name; private final double price; private boolean available; public MenuItem(String id, String name, double price) { this.id = id; this.name = name; this.price = price; this.available = true; } public String getId() { return id; } public void setAvailable(boolean available) { this.available = available; } public String getName() { return name; } public double getPrice() { return price; } public String getMenuItem() { return "Name: " + name + ", Price: " + price; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/Restaurant.java ================================================ package fooddeliveryservice.entity; import fooddeliveryservice.observer.OrderObserver; import fooddeliveryservice.order.Order; import java.util.UUID; public class Restaurant implements OrderObserver { private final String id; private final String name; private final Address address; private final Menu menu; public Restaurant(String name, Address address) { this.id = UUID.randomUUID().toString(); this.name = name; this.address = address; this.menu = new Menu(); } public void addToMenu(MenuItem item) { this.menu.addItem(item); } public String getId() { return id; } public String getName() { return name; } public Address getAddress() { return address; } public Menu getMenu() { return menu; } @Override public void onUpdate(Order order) { System.out.printf("--- Notification for Restaurant %s ---\n", getName()); System.out.printf(" Order %s has been updated to %s.\n", order.getId(), order.getStatus()); System.out.println("---------------------------------------\n"); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/entity/User.java ================================================ package fooddeliveryservice.entity; import fooddeliveryservice.observer.OrderObserver; import java.util.UUID; public abstract class User implements OrderObserver { private final String id; private String name; private String phone; public User(String name, String phone) { this.id = UUID.randomUUID().toString(); this.name = name; this.phone = phone; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/observer/OrderObserver.java ================================================ package fooddeliveryservice.observer; import fooddeliveryservice.order.Order; public interface OrderObserver { void onUpdate(Order order); } ================================================ FILE: solutions/java/src/fooddeliveryservice/order/Order.java ================================================ package fooddeliveryservice.order; import fooddeliveryservice.entity.Customer; import fooddeliveryservice.entity.DeliveryAgent; import fooddeliveryservice.entity.Restaurant; import fooddeliveryservice.observer.OrderObserver; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class Order { private final String id; private final Customer customer; private final Restaurant restaurant; private final List items; private OrderStatus status; private DeliveryAgent deliveryAgent; private final List observers = new ArrayList<>(); public Order(Customer customer, Restaurant restaurant, List items) { this.id = UUID.randomUUID().toString(); this.customer = customer; this.restaurant = restaurant; this.items = items; this.status = OrderStatus.PENDING; addObserver(customer); addObserver(restaurant); } public void addObserver(OrderObserver observer) { observers.add(observer); } private void notifyObservers() { observers.forEach(o -> o.onUpdate(this)); } public void setStatus(OrderStatus newStatus) { if (this.status != newStatus) { this.status = newStatus; notifyObservers(); } } public boolean cancel() { // Only allow cancellation if the order is still in the PENDING state. if (this.status == OrderStatus.PENDING) { setStatus(OrderStatus.CANCELLED); return true; } return false; } public void assignDeliveryAgent(DeliveryAgent agent) { this.deliveryAgent = agent; addObserver(agent); agent.setAvailable(false); // Mark agent as busy } // Getters public String getId() { return id; } public OrderStatus getStatus() { return status; } public Customer getCustomer() { return customer; } public Restaurant getRestaurant() { return restaurant; } public DeliveryAgent getDeliveryAgent() { return deliveryAgent; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/order/OrderItem.java ================================================ package fooddeliveryservice.order; import fooddeliveryservice.entity.MenuItem; public class OrderItem { private final MenuItem item; private final int quantity; public OrderItem(MenuItem item, int quantity) { this.item = item; this.quantity = quantity; } public MenuItem getItem() { return item; } public int getQuantity() { return quantity; } } ================================================ FILE: solutions/java/src/fooddeliveryservice/order/OrderStatus.java ================================================ package fooddeliveryservice.order; public enum OrderStatus { PENDING, CONFIRMED, PREPARING, READY_FOR_PICKUP, OUT_FOR_DELIVERY, DELIVERED, CANCELLED } ================================================ FILE: solutions/java/src/fooddeliveryservice/search/RestaurantSearchStrategy.java ================================================ package fooddeliveryservice.search; import fooddeliveryservice.entity.Restaurant; import java.util.List; public interface RestaurantSearchStrategy { List filter(List allRestaurants); } ================================================ FILE: solutions/java/src/fooddeliveryservice/search/SearchByCityStrategy.java ================================================ package fooddeliveryservice.search; import fooddeliveryservice.entity.Restaurant; import java.util.List; import java.util.stream.Collectors; public class SearchByCityStrategy implements RestaurantSearchStrategy { private final String city; public SearchByCityStrategy(String city) { this.city = city; } @Override public List filter(List allRestaurants) { return allRestaurants.stream() .filter(r -> r.getAddress().getCity().equalsIgnoreCase(city)) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/search/SearchByMenuKeywordStrategy.java ================================================ package fooddeliveryservice.search; import fooddeliveryservice.entity.Restaurant; import java.util.List; import java.util.stream.Collectors; public class SearchByMenuKeywordStrategy implements RestaurantSearchStrategy { private final String keyword; public SearchByMenuKeywordStrategy(String keyword) { this.keyword = keyword.toLowerCase(); } @Override public List filter(List allRestaurants) { return allRestaurants.stream() .filter(r -> r.getMenu().getItems().values().stream() .anyMatch(item -> item.getName().toLowerCase().contains(keyword))) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/search/SearchByProximityStrategy.java ================================================ package fooddeliveryservice.search; import fooddeliveryservice.entity.Address; import fooddeliveryservice.entity.Restaurant; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class SearchByProximityStrategy implements RestaurantSearchStrategy { private final Address userLocation; private final double maxDistance; public SearchByProximityStrategy(Address userLocation, double maxDistance) { this.userLocation = userLocation; this.maxDistance = maxDistance; } @Override public List filter(List allRestaurants) { return allRestaurants.stream() // Filter restaurants within the max distance .filter(r -> userLocation.distanceTo(r.getAddress()) <= maxDistance) // Sort the filtered list by distance (nearest first) .sorted(Comparator.comparingDouble(r -> userLocation.distanceTo(r.getAddress()))) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/fooddeliveryservice/strategy/DeliveryAssignmentStrategy.java ================================================ package fooddeliveryservice.strategy; import fooddeliveryservice.entity.DeliveryAgent; import fooddeliveryservice.order.Order; import java.util.List; import java.util.Optional; public interface DeliveryAssignmentStrategy { Optional findAgent(Order order, List agents); } ================================================ FILE: solutions/java/src/fooddeliveryservice/strategy/NearestAvailableAgentStrategy.java ================================================ package fooddeliveryservice.strategy; import fooddeliveryservice.entity.Address; import fooddeliveryservice.entity.DeliveryAgent; import fooddeliveryservice.order.Order; import java.util.Comparator; import java.util.List; import java.util.Optional; public class NearestAvailableAgentStrategy implements DeliveryAssignmentStrategy { @Override public Optional findAgent(Order order, List availableAgents) { Address restaurantAddress = order.getRestaurant().getAddress(); Address customerAddress = order.getCustomer().getAddress(); // Find the agent with the minimum total travel distance (Agent -> Restaurant -> Customer) return availableAgents.stream() .filter(DeliveryAgent::isAvailable) .min(Comparator.comparingDouble(agent -> calculateTotalDistance(agent, restaurantAddress, customerAddress))); } private double calculateTotalDistance(DeliveryAgent agent, Address restaurantAddress, Address customerAddress) { double agentToRestaurantDist = agent.getCurrentLocation().distanceTo(restaurantAddress); double restaurantToCustomerDist = restaurantAddress.distanceTo(customerAddress); return agentToRestaurantDist + restaurantToCustomerDist; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/BookingService.java ================================================ package hotelmanagementsystem; import hotelmanagementsystem.model.Booking; import hotelmanagementsystem.model.Guest; import hotelmanagementsystem.model.Room; import hotelmanagementsystem.observer.BookingObserver; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class BookingService { private final List bookings = new ArrayList<>(); private final List observers = new ArrayList<>(); public void addObserver(BookingObserver observer) { observers.add(observer); } public void removeObserver(BookingObserver observer) { observers.remove(observer); } public Booking createBooking(Guest guest, Room room, LocalDate startDate, LocalDate endDate) { String bookingId = UUID.randomUUID().toString(); Booking booking = new Booking(bookingId, guest, room, startDate, endDate); // Use the State pattern to book the room room.book(); bookings.add(booking); notifyObservers(booking); return booking; } private void notifyObservers(Booking booking) { for (BookingObserver observer : observers) { observer.update(booking); } } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/HotelManagementDemo.java ================================================ package hotelmanagementsystem; import hotelmanagementsystem.enums.RoomStyle; import hotelmanagementsystem.enums.RoomType; import hotelmanagementsystem.factory.RoomFactory; import hotelmanagementsystem.model.Guest; import hotelmanagementsystem.observer.EmailNotifier; import hotelmanagementsystem.observer.SmsNotifier; import java.time.LocalDate; import java.util.List; public class HotelManagementDemo { public static void main(String[] args) { // 1. Setup Services and Facade RoomService roomService = new RoomService(); BookingService bookingService = new BookingService(); PaymentService paymentService = new PaymentService(); // Register observers for the booking service bookingService.addObserver(new EmailNotifier()); bookingService.addObserver(new SmsNotifier()); HotelManagerFacade hotelManager = new HotelManagerFacade(roomService, bookingService, paymentService); // 2. Populate hotel with rooms using the Factory roomService.addRoom(RoomFactory.createRoom("101", "SINGLE", "STANDARD", 100)); roomService.addRoom(RoomFactory.createRoom("102", "SINGLE", "DELUXE", 120)); roomService.addRoom(RoomFactory.createRoom("201", "DOUBLE", "STANDARD", 150)); roomService.addRoom(RoomFactory.createRoom("202", "DOUBLE", "DELUXE", 180)); roomService.addRoom(RoomFactory.createRoom("301", "SUITE", "OCEAN_VIEW", 300)); System.out.println("----------- SCENARIO 1: Successful Booking with Amenities -----------"); Guest guest1 = new Guest("G123", "John Doe", "john.doe@example.com"); hotelManager.bookRoom( guest1, RoomType.DOUBLE, RoomStyle.DELUXE, LocalDate.now(), LocalDate.now().plusDays(3), List.of("Breakfast", "Spa") ); System.out.println("\n----------- SCENARIO 2: Attempt to book the same room (State Pattern) -----------"); Guest guest2 = new Guest("G456", "Jane Smith", "jane.smith@example.com"); hotelManager.bookRoom( guest2, RoomType.DOUBLE, RoomStyle.DELUXE, LocalDate.now(), LocalDate.now().plusDays(2), List.of() ); System.out.println("\n----------- SCENARIO 3: Check-out and make room available again (State Pattern) -----------"); // Room 202 was booked by John Doe System.out.println("Initial state of Room 202: " + roomService.findRoomByNumber("202")); hotelManager.checkOut("202"); System.out.println("State of Room 202 after checkout: " + roomService.findRoomByNumber("202")); System.out.println("\n----------- SCENARIO 4: Book the now available room -----------"); hotelManager.bookRoom( guest2, RoomType.DOUBLE, RoomStyle.DELUXE, LocalDate.now(), LocalDate.now().plusDays(2), List.of() ); System.out.println("\n----------- SCENARIO 5: Room under maintenance (State Pattern) -----------"); System.out.println("State of Room 101: " + roomService.findRoomByNumber("101")); roomService.findRoomByNumber("101").markForMaintenance(); System.out.println("State of Room 101 after marking for maintenance: " + roomService.findRoomByNumber("101")); Guest guest3 = new Guest("G789", "Peter Jones", "peter.jones@example.com"); hotelManager.bookRoom(guest3, RoomType.SINGLE, RoomStyle.STANDARD, LocalDate.now(), LocalDate.now().plusDays(1), List.of()); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/HotelManagerFacade.java ================================================ package hotelmanagementsystem; import hotelmanagementsystem.decorator.Bookable; import hotelmanagementsystem.decorator.BreakfastDecorator; import hotelmanagementsystem.decorator.RoomBooking; import hotelmanagementsystem.decorator.SpaDecorator; import hotelmanagementsystem.enums.RoomStyle; import hotelmanagementsystem.enums.RoomType; import hotelmanagementsystem.model.Booking; import hotelmanagementsystem.model.Guest; import hotelmanagementsystem.model.Room; import hotelmanagementsystem.specification.RoomAvailableSpecification; import hotelmanagementsystem.specification.RoomStyleSpecification; import hotelmanagementsystem.specification.RoomTypeSpecification; import hotelmanagementsystem.specification.Specification; import java.time.LocalDate; import java.util.List; import java.util.Optional; public class HotelManagerFacade { private final RoomService roomService; private final BookingService bookingService; private final PaymentService paymentService; public HotelManagerFacade(RoomService roomService, BookingService bookingService, PaymentService paymentService) { this.roomService = roomService; this.bookingService = bookingService; this.paymentService = paymentService; } public Booking bookRoom(Guest guest, RoomType type, RoomStyle style, LocalDate start, LocalDate end, List amenities) { // 1. Find an available room using the Specification pattern Specification searchSpec = new RoomAvailableSpecification() .and(new RoomTypeSpecification(type)) .and(new RoomStyleSpecification(style)); Optional availableRoom = roomService.findRooms(searchSpec).stream().findFirst(); if (availableRoom.isPresent()) { Room room = availableRoom.get(); // 2. Create a booking Booking booking = bookingService.createBooking(guest, room, start, end); // 3. Use Decorator pattern to calculate total cost with amenities Bookable bookable = new RoomBooking(room); for (String amenity : amenities) { if ("breakfast".equalsIgnoreCase(amenity)) { bookable = new BreakfastDecorator(bookable); } else if ("spa".equalsIgnoreCase(amenity)) { bookable = new SpaDecorator(bookable); } } System.out.println("Total Cost: " + bookable.getDescription() + " = $" + String.format("%.2f", bookable.getCost())); // 4. Process payment paymentService.processPayment(bookable.getCost()); return booking; } else { System.out.println("Sorry, no rooms available matching your criteria."); return null; } } public void checkIn(String bookingId) { // In a real system, you'd fetch the booking by ID // For this demo, we'll find a room and check it in System.out.println("Check-in process for booking ID (not implemented for demo): " + bookingId); } public void checkOut(String roomNumber) { Room room = roomService.findRoomByNumber(roomNumber); if(room != null) { room.checkOut(); } else { System.out.println("Room " + roomNumber + " not found."); } } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/PaymentService.java ================================================ package hotelmanagementsystem; public class PaymentService { public boolean processPayment(double amount) { System.out.println("Processing payment of $" + String.format("%.2f", amount) + "..."); // In a real system, this would interact with a payment gateway System.out.println("Payment successful."); return true; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/README.md ================================================ # Hotel Management System (LLD) ## Problem Statement Design and implement a Hotel Management System that manages hotel rooms, reservations, and guest information. The system should handle room bookings, check-ins, check-outs, and maintain room status. --- ## Requirements 1. **Room Management:** - Track different types of rooms (STANDARD, DELUXE, SUITE) - Manage room availability and status - Handle room pricing and features 2. **Reservation Management:** - Create and manage reservations - Handle check-in and check-out processes - Track reservation status (CONFIRMED, CANCELLED, CHECKED_IN, CHECKED_OUT) 3. **Guest Management:** - Store guest information - Track guest history - Handle guest preferences 4. **Room Status Tracking:** - Monitor room availability (AVAILABLE, OCCUPIED, MAINTENANCE) - Update room status based on reservations - Handle room maintenance requests 5. **Payment Integration:** - Process room payments - Handle different payment methods - Generate invoices --- ## Core Entities ### 1. HotelManagementSystem - **Fields:** List rooms, List reservations, List guests - **Methods:** - addRoom() - makeReservation() - checkIn() - checkOut() - getAvailableRooms() - cancelReservation() ### 2. Room - **Fields:** String roomNumber, RoomType type, double price, RoomStatus status - **Methods:** - isAvailable() - updateStatus() - getPrice() ### 3. Guest - **Fields:** String id, String name, String email, String phoneNumber - **Methods:** - updateProfile() - getReservations() ### 4. Reservation - **Fields:** String id, Guest guest, Room room, Date checkInDate, Date checkOutDate, ReservationStatus status - **Methods:** - confirm() - cancel() - checkIn() - checkOut() ### 5. RoomType (Enum) - **Values:** STANDARD, DELUXE, SUITE ### 6. RoomStatus (Enum) - **Values:** AVAILABLE, OCCUPIED, MAINTENANCE ### 7. ReservationStatus (Enum) - **Values:** CONFIRMED, CANCELLED, CHECKED_IN, CHECKED_OUT ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/HotelManagementSystem-class-diagram.png) --- ## Example Usage ```java HotelManagementSystem system = new HotelManagementSystem(); // Add a room Room room = system.addRoom("101", RoomType.DELUXE, 150.0); // Create a guest Guest guest = new Guest("John Doe", "john@example.com", "1234567890"); // Make a reservation Reservation reservation = system.makeReservation(guest, room, checkInDate, checkOutDate); // Check in system.checkIn(reservation); // Check out system.checkOut(reservation); ``` --- ## Demo See `HotelManagementSystemDemo.java` for a sample usage and simulation of the hotel management system. --- ## Extending the Framework - **Add room service:** Track room service requests and delivery - **Add housekeeping:** Manage housekeeping schedules and tasks - **Add loyalty program:** Implement guest loyalty points and rewards - **Add inventory management:** Track hotel supplies and amenities - **Add reporting system:** Generate occupancy and revenue reports - **Add notification system:** Send booking confirmations and reminders --- ## Design Patterns Used - **Singleton Pattern:** For the hotel management system instance - **Factory Pattern:** For creating different types of rooms - **Observer Pattern:** For room status updates and notifications - **Strategy Pattern:** For different pricing strategies --- ## Exception Handling - **RoomNotAvailableException:** Thrown when trying to book an unavailable room - **InvalidReservationException:** Thrown when reservation details are invalid - **CheckInException:** Thrown when check-in process fails - **CheckOutException:** Thrown when check-out process fails --- ================================================ FILE: solutions/java/src/hotelmanagementsystem/RoomService.java ================================================ package hotelmanagementsystem; import hotelmanagementsystem.model.Room; import hotelmanagementsystem.specification.Specification; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class RoomService { private final List rooms = new ArrayList<>(); public void addRoom(Room room) { rooms.add(room); } public List findRooms(Specification spec) { return rooms.stream() .filter(spec::isSatisfiedBy) .collect(Collectors.toList()); } public Room findRoomByNumber(String roomNumber) { return rooms.stream() .filter(r -> r.getRoomNumber().equals(roomNumber)) .findFirst() .orElse(null); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/decorator/AmenityDecorator.java ================================================ package hotelmanagementsystem.decorator; public abstract class AmenityDecorator implements Bookable { protected Bookable bookable; public AmenityDecorator(Bookable bookable) { this.bookable = bookable; } @Override public double getCost() { return bookable.getCost(); } @Override public String getDescription() { return bookable.getDescription(); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/decorator/Bookable.java ================================================ package hotelmanagementsystem.decorator; public interface Bookable { double getCost(); String getDescription(); } ================================================ FILE: solutions/java/src/hotelmanagementsystem/decorator/BreakfastDecorator.java ================================================ package hotelmanagementsystem.decorator; public class BreakfastDecorator extends AmenityDecorator { private static final double BREAKFAST_COST = 25.0; public BreakfastDecorator(Bookable bookable) { super(bookable); } @Override public double getCost() { return super.getCost() + BREAKFAST_COST; } @Override public String getDescription() { return super.getDescription() + " with Breakfast"; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/decorator/RoomBooking.java ================================================ package hotelmanagementsystem.decorator; import hotelmanagementsystem.model.Room; public class RoomBooking implements Bookable { private final Room room; public RoomBooking(Room room) { this.room = room; } @Override public double getCost() { return room.getPrice(); } @Override public String getDescription() { return room.getStyle() + " " + room.getType() + " Room"; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/decorator/SpaDecorator.java ================================================ package hotelmanagementsystem.decorator; public class SpaDecorator extends AmenityDecorator { private static final double SPA_COST = 50.0; public SpaDecorator(Bookable bookable) { super(bookable); } @Override public double getCost() { return super.getCost() + SPA_COST; } @Override public String getDescription() { return super.getDescription() + " with Spa Access"; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/enums/BookingStatus.java ================================================ package hotelmanagementsystem.enums; public enum BookingStatus { REQUESTED, CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED } ================================================ FILE: solutions/java/src/hotelmanagementsystem/enums/RoomStyle.java ================================================ package hotelmanagementsystem.enums; public enum RoomStyle { STANDARD, DELUXE, OCEAN_VIEW } ================================================ FILE: solutions/java/src/hotelmanagementsystem/enums/RoomType.java ================================================ package hotelmanagementsystem.enums; public enum RoomType { SINGLE, DOUBLE, SUITE } ================================================ FILE: solutions/java/src/hotelmanagementsystem/factory/RoomFactory.java ================================================ package hotelmanagementsystem.factory; import hotelmanagementsystem.enums.RoomStyle; import hotelmanagementsystem.enums.RoomType; import hotelmanagementsystem.model.Room; public class RoomFactory { public static Room createRoom(String roomNumber, String type, String style, double price) { RoomType roomType = RoomType.valueOf(type.toUpperCase()); RoomStyle roomStyle = RoomStyle.valueOf(style.toUpperCase()); return new Room(roomNumber, roomType, roomStyle, price); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/model/Booking.java ================================================ package hotelmanagementsystem.model; import hotelmanagementsystem.enums.BookingStatus; import java.time.LocalDate; public class Booking { private final String bookingId; private final Guest guest; private final Room room; private final LocalDate startDate; private final LocalDate endDate; private BookingStatus status; public Booking(String bookingId, Guest guest, Room room, LocalDate startDate, LocalDate endDate) { this.bookingId = bookingId; this.guest = guest; this.room = room; this.startDate = startDate; this.endDate = endDate; this.status = BookingStatus.CONFIRMED; } public void checkIn() { this.status = BookingStatus.CHECKED_IN; } public void checkOut() { this.status = BookingStatus.CHECKED_OUT; } public void cancel() { this.status = BookingStatus.CANCELLED; } public String getBookingId() { return bookingId; } public Guest getGuest() { return guest; } public Room getRoom() { return room; } public LocalDate getStartDate() { return startDate; } public LocalDate getEndDate() { return endDate; } public BookingStatus getStatus() { return status; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/model/Guest.java ================================================ package hotelmanagementsystem.model; public class Guest { private final String id; private final String name; private final String email; public Guest(String id, String name, String email) { this.id = id; this.name = name; this.email = email; } public String getId() { return id; } public String getName() { return name; } public String getEmail() { return email; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/model/Room.java ================================================ package hotelmanagementsystem.model; import hotelmanagementsystem.enums.RoomStyle; import hotelmanagementsystem.enums.RoomType; import hotelmanagementsystem.state.AvailableState; import hotelmanagementsystem.state.RoomState; public class Room { private final String roomNumber; private final RoomType type; private final RoomStyle style; private final double price; private RoomState state; public Room(String roomNumber, RoomType type, RoomStyle style, double price) { this.roomNumber = roomNumber; this.type = type; this.style = style; this.price = price; this.state = new AvailableState(); // Initial state } public void setState(RoomState state) { this.state = state; } public void book() { state.book(this); } public void checkIn() { state.checkIn(this); } public void checkOut() { state.checkOut(this); } public void markForMaintenance() { state.markForMaintenance(this); } public String getRoomNumber() { return roomNumber; } public RoomType getType() { return type; } public RoomStyle getStyle() { return style; } public double getPrice() { return price; } public RoomState getState() { return state; } @Override public String toString() { return "Room [Number=" + roomNumber + ", Type=" + type + ", Style=" + style + ", Price=$" + price + ", State=" + state.getClass().getSimpleName() + "]"; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/observer/BookingObserver.java ================================================ package hotelmanagementsystem.observer; import hotelmanagementsystem.model.Booking; public interface BookingObserver { void update(Booking booking); } ================================================ FILE: solutions/java/src/hotelmanagementsystem/observer/EmailNotifier.java ================================================ package hotelmanagementsystem.observer; import hotelmanagementsystem.model.Booking; public class EmailNotifier implements BookingObserver { @Override public void update(Booking booking) { System.out.println("--- Email Notification ---"); System.out.println("To: " + booking.getGuest().getEmail()); System.out.println("Subject: Booking Confirmation " + booking.getBookingId()); System.out.println("Dear " + booking.getGuest().getName() + ","); System.out.println("Your booking for Room " + booking.getRoom().getRoomNumber() + " is confirmed."); System.out.println("--------------------------"); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/observer/SmsNotifier.java ================================================ package hotelmanagementsystem.observer; import hotelmanagementsystem.model.Booking; public class SmsNotifier implements BookingObserver { @Override public void update(Booking booking) { System.out.println("--- SMS Notification ---"); System.out.println("To: [Guest's Phone Number]"); // Assuming guest has a phone number System.out.println("Message: Booking " + booking.getBookingId() + " for Room " + booking.getRoom().getRoomNumber() + " confirmed!"); System.out.println("------------------------"); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/payment/CashPayment.java ================================================ package hotelmanagementsystem.payment; public class CashPayment implements Payment { @Override public boolean processPayment(double amount) { // Process cash payment return true; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/payment/CreditCardPayment.java ================================================ package hotelmanagementsystem.payment; public class CreditCardPayment implements Payment { @Override public boolean processPayment(double amount) { // Process credit card payment return true; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/payment/Payment.java ================================================ package hotelmanagementsystem.payment; public interface Payment { boolean processPayment(double amount); } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/AbstractSpecification.java ================================================ package hotelmanagementsystem.specification; public abstract class AbstractSpecification implements Specification { public Specification and(Specification other) { return new AndSpecification<>(this, other); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/AndSpecification.java ================================================ package hotelmanagementsystem.specification; public class AndSpecification extends AbstractSpecification { private final Specification spec1; private final Specification spec2; public AndSpecification(Specification spec1, Specification spec2) { this.spec1 = spec1; this.spec2 = spec2; } @Override public boolean isSatisfiedBy(T item) { return spec1.isSatisfiedBy(item) && spec2.isSatisfiedBy(item); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/RoomAvailableSpecification.java ================================================ package hotelmanagementsystem.specification; import hotelmanagementsystem.model.Room; import hotelmanagementsystem.state.AvailableState; public class RoomAvailableSpecification extends AbstractSpecification { @Override public boolean isSatisfiedBy(Room item) { return item.getState() instanceof AvailableState; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/RoomStyleSpecification.java ================================================ package hotelmanagementsystem.specification; import hotelmanagementsystem.enums.RoomStyle; import hotelmanagementsystem.model.Room; public class RoomStyleSpecification extends AbstractSpecification { private final RoomStyle style; public RoomStyleSpecification(RoomStyle style) { this.style = style; } @Override public boolean isSatisfiedBy(Room item) { return item.getStyle() == style; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/RoomTypeSpecification.java ================================================ package hotelmanagementsystem.specification; import hotelmanagementsystem.enums.RoomType; import hotelmanagementsystem.model.Room; public class RoomTypeSpecification extends AbstractSpecification { private final RoomType type; public RoomTypeSpecification(RoomType type) { this.type = type; } @Override public boolean isSatisfiedBy(Room item) { return item.getType() == type; } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/specification/Specification.java ================================================ package hotelmanagementsystem.specification; public interface Specification { boolean isSatisfiedBy(T item); Specification and(Specification other); } ================================================ FILE: solutions/java/src/hotelmanagementsystem/state/AvailableState.java ================================================ package hotelmanagementsystem.state; import hotelmanagementsystem.model.Room; public class AvailableState implements RoomState { @Override public void book(Room room) { System.out.println("Booking room " + room.getRoomNumber() + "."); room.setState(new OccupiedState()); } @Override public void checkIn(Room room) { System.out.println("Checking into room " + room.getRoomNumber() + "."); room.setState(new OccupiedState()); } @Override public void checkOut(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is not occupied."); } @Override public void markForMaintenance(Room room) { System.out.println("Marking room " + room.getRoomNumber() + " for maintenance."); room.setState(new MaintenanceState()); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/state/MaintenanceState.java ================================================ package hotelmanagementsystem.state; import hotelmanagementsystem.model.Room; public class MaintenanceState implements RoomState { @Override public void book(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is under maintenance."); } @Override public void checkIn(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is under maintenance."); } @Override public void checkOut(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is under maintenance."); } @Override public void markForMaintenance(Room room) { System.out.println("Room " + room.getRoomNumber() + " is already under maintenance. Marking it as available now."); room.setState(new AvailableState()); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/state/OccupiedState.java ================================================ package hotelmanagementsystem.state; import hotelmanagementsystem.model.Room; public class OccupiedState implements RoomState { @Override public void book(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is already occupied."); } @Override public void checkIn(Room room) { System.out.println("Error: Room " + room.getRoomNumber() + " is already checked in."); } @Override public void checkOut(Room room) { System.out.println("Checking out of room " + room.getRoomNumber() + "."); room.setState(new AvailableState()); } @Override public void markForMaintenance(Room room) { System.out.println("Error: Cannot mark an occupied room for maintenance. Please check out first."); } } ================================================ FILE: solutions/java/src/hotelmanagementsystem/state/RoomState.java ================================================ package hotelmanagementsystem.state; import hotelmanagementsystem.model.Room; public interface RoomState { void book(Room room); void checkIn(Room room); void checkOut(Room room); void markForMaintenance(Room room); } ================================================ FILE: solutions/java/src/librarymanagementsystem/LibraryManagementDemo.java ================================================ package librarymanagementsystem; import librarymanagementsystem.enums.ItemType; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Member; import librarymanagementsystem.strategy.SearchByAuthorStrategy; import librarymanagementsystem.strategy.SearchByTitleStrategy; import java.util.List; public class LibraryManagementDemo { public static void main(String[] args) { LibraryManagementSystem library = LibraryManagementSystem.getInstance(); // --- Setup: Add items and members using the Facade --- System.out.println("=== Setting up the Library ==="); List hobbitCopies = library.addItem(ItemType.BOOK, "B001", "The Hobbit", "J.R.R. Tolkien", 2); List duneCopies = library.addItem(ItemType.BOOK, "B002", "Dune", "Frank Herbert", 1); List natGeoCopies = library.addItem(ItemType.MAGAZINE, "M001", "National Geographic", "NatGeo Society", 3); Member alice = library.addMember("MEM01", "Alice"); Member bob = library.addMember("MEM02", "Bob"); Member charlie = library.addMember("MEM03", "Charlie"); library.printCatalog(); // --- Scenario 1: Searching (Strategy Pattern) --- System.out.println("\n=== Scenario 1: Searching for Items ==="); System.out.println("Searching for title 'Dune':"); library.search("Dune", new SearchByTitleStrategy()) .forEach(item -> System.out.println("Found: " + item.getTitle())); System.out.println("\nSearching for author 'Tolkien':"); library.search("Tolkien", new SearchByAuthorStrategy()) .forEach(item -> System.out.println("Found: " + item.getTitle())); // --- Scenario 2: Checkout and Return (State Pattern) --- System.out.println("\n\n=== Scenario 2: Checkout and Return ==="); library.checkout(alice.getId(), hobbitCopies.get(0).getId()); // Alice checks out The Hobbit copy 1 library.checkout(bob.getId(), duneCopies.get(0).getId()); // Bob checks out Dune copy 1 library.printCatalog(); System.out.println("Attempting to checkout an already checked-out book:"); library.checkout(charlie.getId(), hobbitCopies.get(0).getId()); // Charlie fails to check out The Hobbit copy 1 System.out.println("\nAlice returns The Hobbit:"); library.returnItem(hobbitCopies.get(0).getId()); library.printCatalog(); // --- Scenario 3: Holds and Notifications (Observer Pattern) --- System.out.println("\n\n=== Scenario 3: Placing a Hold ==="); System.out.println("Dune is checked out by Bob. Charlie places a hold."); library.placeHold(charlie.getId(), "B002"); // Charlie places a hold on Dune System.out.println("\nBob returns Dune. Charlie should be notified."); library.returnItem(duneCopies.get(0).getId()); // Bob returns Dune System.out.println("\nCharlie checks out the book that was on hold for him."); library.checkout(charlie.getId(), duneCopies.get(0).getId()); System.out.println("\nTrying to check out the same on-hold item by another member (Alice):"); library.checkout(alice.getId(), duneCopies.get(0).getId()); // Alice fails, it's checked out by Charlie now. library.printCatalog(); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/LibraryManagementSystem.java ================================================ package librarymanagementsystem; import librarymanagementsystem.enums.ItemType; import librarymanagementsystem.factory.ItemFactory; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.LibraryItem; import librarymanagementsystem.models.Member; import librarymanagementsystem.strategy.SearchStrategy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class LibraryManagementSystem { private static final LibraryManagementSystem INSTANCE = new LibraryManagementSystem(); private final Map catalog = new HashMap<>(); private final Map members = new HashMap<>(); private final Map copies = new HashMap<>(); private LibraryManagementSystem() {} public static LibraryManagementSystem getInstance() { return INSTANCE; } // --- Item Management --- public List addItem(ItemType type, String id, String title, String author, int numCopies) { List bookCopies = new ArrayList<>(); LibraryItem item = ItemFactory.createItem(type, id, title, author); catalog.put(id, item); for (int i = 0; i < numCopies; i++) { String copyId = id + "-c" + (i + 1); BookCopy copy = new BookCopy(copyId, item); copies.put(copyId, new BookCopy(copyId, item)); bookCopies.add(copy); } System.out.println("Added " + numCopies + " copies of '" + title + "'"); return bookCopies; } // --- User Management --- public Member addMember(String id, String name) { Member member = new Member(id, name); members.put(id, member); return member; } // --- Core Actions --- public void checkout(String memberId, String copyId) { Member member = members.get(memberId); BookCopy copy = copies.get(copyId); if (member != null && copy != null) { copy.checkout(member); } else { System.out.println("Error: Invalid member or copy ID."); } } public void returnItem(String copyId) { BookCopy copy = copies.get(copyId); if (copy != null) { copy.returnItem(); } else { System.out.println("Error: Invalid copy ID."); } } public void placeHold(String memberId, String itemId) { Member member = members.get(memberId); LibraryItem item = catalog.get(itemId); if (member != null && item != null) { // Place hold on any copy that is checked out item.getCopies().stream() .filter(c -> !c.isAvailable()) .findFirst() .ifPresent(copy -> copy.placeHold(member)); } } // --- Search (Using Strategy Pattern) --- public List search(String query, SearchStrategy strategy) { return strategy.search(query, new ArrayList<>(catalog.values())); } public void printCatalog() { System.out.println("\n--- Library Catalog ---"); catalog.values().forEach(item -> System.out.printf("ID: %s, Title: %s, Author/Publisher: %s, Available: %d\n", item.getId(), item.getTitle(), item.getAuthorOrPublisher(), item.getAvailableCopyCount())); System.out.println("-----------------------\n"); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/README.md ================================================ # Library Management System (LLD) ## Problem Statement Design and implement a Library Management System that allows members to borrow and return books, manages book inventory, tracks loans, and supports catalog search. --- ## Requirements - **Book Management:** The system manages a catalog of books, each with multiple copies. - **Member Management:** The system manages library members who can borrow and return books. - **Loan Management:** The system tracks which member has borrowed which book copy and when. - **Borrowing and Returning:** Members can borrow available book copies and return them. - **Catalog Search:** Members can search for books by title, author, or ISBN. - **Extensibility:** Easy to add new features such as reservations, fines, or notifications. --- ## Core Entities - **LibraryManagementSystem:** Main class that manages books, members, loans, and the catalog. - **Book:** Represents a book with title, author, ISBN, and other metadata. - **BookCopy:** Represents a physical copy of a book, with a unique copy ID and availability status. - **Member:** Represents a library member with a unique ID and name. - **Loan:** Represents a loan record for a book copy borrowed by a member. - **Catalog:** Manages the collection of books and supports search functionality. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/LibraryManagementSystem-class-diagram.png) ### 1. LibraryManagementSystem - **Fields:** List books, List members, List loans, Catalog catalog - **Methods:** addBook(Book), addMember(Member), borrowBook(Member, Book), returnBook(Member, BookCopy), getLoans(Member), searchBooks(String query), etc. ### 2. Book - **Fields:** String title, String author, String isbn, List copies ### 3. BookCopy - **Fields:** int copyId, Book book, boolean isAvailable ### 4. Member - **Fields:** int id, String name, List loans ### 5. Loan - **Fields:** int id, Member member, BookCopy bookCopy, Date loanDate, Date returnDate ### 6. Catalog - **Fields:** List books - **Methods:** searchByTitle(String), searchByAuthor(String), searchByISBN(String) --- ## Example Usage ```java LibraryManagementSystem system = new LibraryManagementSystem(); Book book = new Book("Effective Java", "Joshua Bloch", "978-0134685991"); system.addBook(book); Member alice = new Member(1, "Alice"); system.addMember(alice); system.borrowBook(alice, book); system.returnBook(alice, book.getCopies().get(0)); ``` --- ## Demo See `LibraryManagementSystemDemo.java` for a sample usage and simulation of the library management system. --- ## Extending the Framework - **Add reservations:** Allow members to reserve books that are currently checked out. - **Add fines:** Track overdue books and calculate fines. - **Add notifications:** Notify members about due dates, reservations, or new arrivals. --- ================================================ FILE: solutions/java/src/librarymanagementsystem/TransactionService.java ================================================ package librarymanagementsystem; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Loan; import librarymanagementsystem.models.Member; import java.util.HashMap; import java.util.Map; public class TransactionService { private static final TransactionService INSTANCE = new TransactionService(); private final Map activeLoans = new HashMap<>(); // Key: BookCopy ID private TransactionService() {} public static TransactionService getInstance() { return INSTANCE; } public void createLoan(BookCopy copy, Member member) { if (activeLoans.containsKey(copy.getId())) { throw new IllegalStateException("This copy is already on loan."); } Loan loan = new Loan(copy, member); activeLoans.put(copy.getId(), loan); member.addLoan(loan); } public void endLoan(BookCopy copy) { Loan loan = activeLoans.remove(copy.getId()); if (loan != null) { loan.getMember().removeLoan(loan); } } } ================================================ FILE: solutions/java/src/librarymanagementsystem/enums/ItemType.java ================================================ package librarymanagementsystem.enums; public enum ItemType { BOOK, MAGAZINE } ================================================ FILE: solutions/java/src/librarymanagementsystem/factory/ItemFactory.java ================================================ package librarymanagementsystem.factory; import librarymanagementsystem.enums.ItemType; import librarymanagementsystem.models.Book; import librarymanagementsystem.models.LibraryItem; import librarymanagementsystem.models.Magazine; public class ItemFactory { public static LibraryItem createItem(ItemType type, String id, String title, String author) { switch (type) { case BOOK: return new Book(id, title, author); case MAGAZINE: return new Magazine(id, title, author); // Author might be publisher here default: throw new IllegalArgumentException("Unknown item type."); } } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/Book.java ================================================ package librarymanagementsystem.models; public class Book extends LibraryItem { private final String author; public Book(String id, String title, String author) { super(id, title); this.author = author; } @Override public String getAuthorOrPublisher() { return author; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/BookCopy.java ================================================ package librarymanagementsystem.models; import librarymanagementsystem.state.AvailableState; import librarymanagementsystem.state.ItemState; public class BookCopy { private final String id; private final LibraryItem item; private ItemState currentState; public BookCopy(String id, LibraryItem item) { this.id = id; this.item = item; this.currentState = new AvailableState(); item.addCopy(this); } public void checkout(Member member) { currentState.checkout(this, member); } public void returnItem() { currentState.returnItem(this); } public void placeHold(Member member) { currentState.placeHold(this, member); } public void setState(ItemState state) { this.currentState = state; } public String getId() { return id; } public LibraryItem getItem() { return item; } public boolean isAvailable() { return currentState instanceof AvailableState; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/LibraryItem.java ================================================ package librarymanagementsystem.models; import java.util.ArrayList; import java.util.List; public abstract class LibraryItem { private final String id; private final String title; protected final List copies = new ArrayList<>(); // Observer Pattern: List of members waiting for this item private final List observers = new ArrayList<>(); public LibraryItem(String id, String title) { this.id = id; this.title = title; } public void addCopy(BookCopy copy) { this.copies.add(copy); } public void addObserver(Member member) { observers.add(member); } public void removeObserver(Member member) { observers.remove(member); } public void notifyObservers() { System.out.println("Notifying " + observers.size() + " observers for '" + title + "'..."); // Use a copy to avoid ConcurrentModificationException if observer unsubscribes new ArrayList<>(observers).forEach(observer -> observer.update(this)); } public BookCopy getAvailableCopy() { return copies.stream() .filter(BookCopy::isAvailable) .findFirst() .orElse(null); } // Getters public String getId() { return id; } public String getTitle() { return title; } public List getCopies() { return copies; } public abstract String getAuthorOrPublisher(); public long getAvailableCopyCount() { return copies.stream().filter(BookCopy::isAvailable).count(); } public boolean hasObservers() { return !observers.isEmpty(); } public boolean isObserver(Member member) { return observers.contains(member); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/Loan.java ================================================ package librarymanagementsystem.models; import java.time.LocalDate; public class Loan { private final BookCopy copy; private final Member member; private final LocalDate checkoutDate; public Loan(BookCopy copy, Member member) { this.copy = copy; this.member = member; this.checkoutDate = LocalDate.now(); } public BookCopy getCopy() { return copy; } public Member getMember() { return member; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/Magazine.java ================================================ package librarymanagementsystem.models; public class Magazine extends LibraryItem { private final String publisher; public Magazine(String id, String title, String publisher) { super(id, title); this.publisher = publisher; } @Override public String getAuthorOrPublisher() { return publisher; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/models/Member.java ================================================ package librarymanagementsystem.models; import java.util.ArrayList; import java.util.List; public class Member { private final String id; private final String name; private final List loans = new ArrayList<>(); public Member(String id, String name) { this.id = id; this.name = name; } // Observer update method public void update(LibraryItem item) { System.out.println("NOTIFICATION for " + name + ": The book '" + item.getTitle() + "' you placed a hold on is now available!"); } public void addLoan(Loan loan) { loans.add(loan); } public void removeLoan(Loan loan) { loans.remove(loan); } public String getId() { return id; } public String getName() { return name; } public List getLoans() { return loans; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/state/AvailableState.java ================================================ package librarymanagementsystem.state; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Member; import librarymanagementsystem.TransactionService; public class AvailableState implements ItemState { @Override public void checkout(BookCopy copy, Member member) { TransactionService.getInstance().createLoan(copy, member); copy.setState(new CheckedOutState()); System.out.println(copy.getId() + " checked out by " + member.getName()); } @Override public void returnItem(BookCopy c) { System.out.println("Cannot return an item that is already available."); } @Override public void placeHold(BookCopy c, Member m) { System.out.println("Cannot place hold on an available item. Please check it out."); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/state/CheckedOutState.java ================================================ package librarymanagementsystem.state; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Member; import librarymanagementsystem.TransactionService; public class CheckedOutState implements ItemState { @Override public void checkout(BookCopy c, Member m) { System.out.println(c.getId() + " is already checked out."); } @Override public void returnItem(BookCopy copy) { TransactionService.getInstance().endLoan(copy); System.out.println(copy.getId() + " returned."); // If there are holds, move to OnHold state. Otherwise, become Available. if (copy.getItem().hasObservers()) { copy.setState(new OnHoldState()); copy.getItem().notifyObservers(); // Notify members that item is back but on hold } else { copy.setState(new AvailableState()); } } @Override public void placeHold(BookCopy copy, Member member) { copy.getItem().addObserver(member); System.out.println(member.getName() + " placed a hold on '" + copy.getItem().getTitle() + "'"); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/state/ItemState.java ================================================ package librarymanagementsystem.state; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Member; public interface ItemState { void checkout(BookCopy copy, Member member); void returnItem(BookCopy copy); void placeHold(BookCopy copy, Member member); } ================================================ FILE: solutions/java/src/librarymanagementsystem/state/OnHoldState.java ================================================ package librarymanagementsystem.state; import librarymanagementsystem.models.BookCopy; import librarymanagementsystem.models.Member; import librarymanagementsystem.TransactionService; public class OnHoldState implements ItemState { @Override public void checkout(BookCopy copy, Member member) { // Only a member who placed the hold can check it out. if (copy.getItem().isObserver(member)) { TransactionService.getInstance().createLoan(copy, member); copy.getItem().removeObserver(member); // Remove from waiting list copy.setState(new CheckedOutState()); System.out.println("Hold fulfilled. " + copy.getId() + " checked out by " + member.getName()); } else { System.out.println("This item is on hold for another member."); } } @Override public void returnItem(BookCopy c) { System.out.println("Invalid action. Item is on hold, not checked out."); } @Override public void placeHold(BookCopy c, Member m) { System.out.println("Item is already on hold."); } } ================================================ FILE: solutions/java/src/librarymanagementsystem/strategy/SearchByAuthorStrategy.java ================================================ package librarymanagementsystem.strategy; import librarymanagementsystem.models.LibraryItem; import java.util.ArrayList; import java.util.List; public class SearchByAuthorStrategy implements SearchStrategy { @Override public List search(String query, List items) { List result = new ArrayList<>(); items.stream() .filter(item -> item.getAuthorOrPublisher().toLowerCase().contains(query.toLowerCase())) .forEach(result::add); return result; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/strategy/SearchByTitleStrategy.java ================================================ package librarymanagementsystem.strategy; import librarymanagementsystem.models.LibraryItem; import java.util.ArrayList; import java.util.List; public class SearchByTitleStrategy implements SearchStrategy { @Override public List search(String query, List items) { List result = new ArrayList<>(); items.stream() .filter(item -> item.getTitle().toLowerCase().contains(query.toLowerCase())) .forEach(result::add); return result; } } ================================================ FILE: solutions/java/src/librarymanagementsystem/strategy/SearchStrategy.java ================================================ package librarymanagementsystem.strategy; import librarymanagementsystem.models.LibraryItem; import java.util.List; public interface SearchStrategy { List search(String query, List items); } ================================================ FILE: solutions/java/src/linkedin/LinkedInDemo.java ================================================ package linkedin; import linkedin.entities.Education; import linkedin.entities.Experience; import linkedin.entities.Member; import linkedin.entities.Post; import java.time.LocalDate; import java.util.List; public class LinkedInDemo { public static void main(String[] args) { LinkedInSystem system = LinkedInSystem.getInstance(); // --- 1. Create Members using the Builder Pattern --- System.out.println("--- 1. Member Registration ---"); Member alice = new Member.Builder("Alice", "alice@example.com") .withSummary("Senior Software Engineer with 10 years of experience.") .addExperience(new Experience("Sr. Software Engineer", "Google", LocalDate.of(2018, 1, 1), null)) .addExperience(new Experience("Software Engineer", "Microsoft", LocalDate.of(2014, 6, 1), LocalDate.of(2017, 12, 31))) .addEducation(new Education("Princeton University", "M.S. in Computer Science", 2012, 2014)) .build(); Member bob = new Member.Builder("Bob", "bob@example.com") .withSummary("Product Manager at Stripe.") .addExperience(new Experience("Product Manager", "Stripe", LocalDate.of(2020, 2, 1), null)) .addEducation(new Education("MIT", "B.S. in Business Analytics", 2015, 2019)) .build(); Member charlie = new Member.Builder("Charlie", "charlie@example.com").build(); system.registerMember(alice); system.registerMember(bob); system.registerMember(charlie); alice.displayProfile(); // --- 2. Connection Management --- System.out.println("\n--- 2. Connection Management ---"); // Alice sends requests to Bob and Charlie String requestId1 = system.sendConnectionRequest(alice, bob); String requestId2 = system.sendConnectionRequest(alice, charlie); bob.viewNotifications(); // Bob sees Alice's request. System.out.println("\nBob accepts Alice's request."); system.acceptConnectionRequest(requestId1); System.out.println("Alice and Bob are now connected."); // --- 3. Posting and News Feed --- System.out.println("\n--- 3. Posting & News Feed ---"); bob.displayProfile(); // Bob has 1 connection system.createPost(bob.getId(), "Excited to share we've launched our new feature! #productmanagement"); // Alice views her news feed. She should see Bob's post. system.viewNewsFeed(alice.getId()); // Charlie views his feed. It should be empty as he is not connected to anyone. system.viewNewsFeed(charlie.getId()); // --- 4. Interacting with a Post (Observer Pattern in action) --- System.out.println("\n--- 4. Post Interaction & Notifications ---"); Post bobsPost = system.getLatestPostByMember(bob.getId()); if (bobsPost != null) { bobsPost.addLike(alice); bobsPost.addComment(alice, "This looks amazing! Great work!"); } // Bob checks his notifications. He should see a like and a comment from Alice. bob.viewNotifications(); // --- 5. Searching for Members --- System.out.println("\n--- 5. Member Search ---"); List searchResults = system.searchMemberByName("ali"); System.out.println("Search results for 'ali':"); searchResults.forEach(m -> System.out.println(" - " + m.getName())); } } ================================================ FILE: solutions/java/src/linkedin/LinkedInSystem.java ================================================ package linkedin; import linkedin.entities.Member; import linkedin.entities.Post; import linkedin.services.ConnectionService; import linkedin.services.NewsFeedService; import linkedin.services.NotificationService; import linkedin.services.SearchService; import linkedin.strategy.ChronologicalSortStrategy; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class LinkedInSystem { private static volatile LinkedInSystem instance; // Data stores (simulating databases) private final Map members = new ConcurrentHashMap<>(); // Services private final ConnectionService connectionService; private final NewsFeedService newsFeedService; private final SearchService searchService; private LinkedInSystem() { // Initialize services this.connectionService = new ConnectionService(new NotificationService()); this.newsFeedService = new NewsFeedService(); this.searchService = new SearchService(members.values()); } public static LinkedInSystem getInstance() { if (instance == null) { synchronized (LinkedInSystem.class) { if (instance == null) { instance = new LinkedInSystem(); } } } return instance; } public void registerMember(Member member) { members.put(member.getId(), member); System.out.println("New member registered: " + member.getName()); } public Member getMember(String name) { return members.values().stream().filter(m -> m.getName().equals(name)).findFirst().orElse(null); } public String sendConnectionRequest(Member from, Member to) { return connectionService.sendRequest(from, to); } public void acceptConnectionRequest(String requestId) { connectionService.acceptRequest(requestId); } public void createPost(String memberId, String content) { Member author = members.get(memberId); Post post = new Post(author, content); newsFeedService.addPost(author, post); System.out.printf("%s created a new post.%n", author.getName()); } public Post getLatestPostByMember(String memberId) { List memberPosts = newsFeedService.getMemberPosts(members.get(memberId)); if (memberPosts == null || memberPosts.isEmpty()) return null; return memberPosts.get(memberPosts.size() - 1); } public void viewNewsFeed(String memberId) { Member member = members.get(memberId); System.out.println("\n--- News Feed for " + member.getName() + " ---"); // Using the default chronological strategy newsFeedService.displayFeedForMember(member, new ChronologicalSortStrategy()); } public List searchMemberByName(String name) { return searchService.searchByName(name); } } ================================================ FILE: solutions/java/src/linkedin/README.md ================================================ # LinkedIn (LLD) ## Problem Statement Design and implement a LinkedIn-like professional networking platform that allows users to create profiles, connect with others, post jobs, send messages, and receive notifications. --- ## Requirements - **User Management:** Users can register, log in, and manage their profiles. - **Profile Management:** Users can add education, experience, and skills to their profiles. - **Connections:** Users can send and accept connection requests. - **Job Posting:** Users (or companies) can post job openings. - **Messaging:** Users can send direct messages to their connections. - **Notifications:** The system notifies users of connection requests, job matches, messages, and other events. - **Extensibility:** Easy to add new features such as endorsements, recommendations, or company pages. --- ## Core Entities - **LinkedInService:** Main class that manages users, connections, job postings, messages, and notifications. - **User:** Represents a user with profile, connections, messages, and notifications. - **Profile:** Represents a user's professional profile, including education, experience, and skills. - **Connection:** Represents a connection between two users. - **JobPosting:** Represents a job posted by a user or company. - **Message:** Represents a direct message between users. - **Notification:** Represents a notification sent to a user. - **NotificationType (enum):** Types of notifications (e.g., CONNECTION_REQUEST, JOB_MATCH, MESSAGE). - **Skill:** Represents a skill in a user's profile. - **Education:** Represents an education entry in a user's profile. - **Experience:** Represents a work experience entry in a user's profile. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/linkedin-class-diagram.png) ### 1. LinkedInService - **Fields:** List users, List jobPostings, List connections, List notifications - **Methods:** registerUser(User), addConnection(User, User), postJob(JobPosting), sendMessage(User, User, String), sendNotification(Notification), searchUsers(String), searchJobs(String), etc. ### 2. User - **Fields:** int id, String name, Profile profile, List connections, List messages, List notifications - **Methods:** sendConnectionRequest(User), acceptConnection(Connection), sendMessage(User, String), addSkill(Skill), addEducation(Education), addExperience(Experience), etc. ### 3. Profile - **Fields:** List skills, List education, List experience ### 4. Connection - **Fields:** int id, User user1, User user2, boolean isAccepted ### 5. JobPosting - **Fields:** int id, String title, String description, User postedBy ### 6. Message - **Fields:** int id, User sender, User receiver, String content ### 7. Notification - **Fields:** int id, User recipient, String message, NotificationType type ### 8. NotificationType (enum) - Values: CONNECTION_REQUEST, JOB_MATCH, MESSAGE, etc. ### 9. Skill - **Fields:** String name ### 10. Education - **Fields:** String institution, String degree, String fieldOfStudy, int startYear, int endYear ### 11. Experience - **Fields:** String company, String title, int startYear, int endYear --- ## Example Usage ```java LinkedInService service = new LinkedInService(); User alice = new User(1, "Alice"); User bob = new User(2, "Bob"); service.registerUser(alice); service.registerUser(bob); alice.sendConnectionRequest(bob); service.addConnection(alice, bob); Profile profile = alice.getProfile(); profile.addSkill(new Skill("Java")); profile.addEducation(new Education("MIT", "BSc", "CS", 2010, 2014)); profile.addExperience(new Experience("Google", "Software Engineer", 2014, 2018)); JobPosting job = new JobPosting(1, "Backend Developer", "Work on scalable systems", alice); service.postJob(job); service.sendMessage(alice, bob, "Hi Bob, let's connect!"); ``` --- ## Demo See `LinkedInDemo.java` for a sample usage and simulation of the LinkedIn system. --- ## Extending the Framework - **Add endorsements:** Allow users to endorse each other's skills. - **Add recommendations:** Support written recommendations for users. - **Add company pages:** Allow companies to create and manage their own pages. --- ================================================ FILE: solutions/java/src/linkedin/entities/Comment.java ================================================ package linkedin.entities; import java.time.LocalDateTime; public class Comment { private final Member author; private final String text; private final LocalDateTime createdAt; public Comment(Member author, String text) { this.author = author; this.text = text; this.createdAt = LocalDateTime.now(); } public Member getAuthor() { return author; } public String getText() { return text; } } ================================================ FILE: solutions/java/src/linkedin/entities/Connection.java ================================================ package linkedin.entities; import linkedin.enums.ConnectionStatus; import java.time.LocalDateTime; public class Connection { private final Member fromMember; private final Member toMember; private ConnectionStatus status; private final LocalDateTime requestedAt; private LocalDateTime acceptedAt; public Connection(Member fromMember, Member toMember) { this.fromMember = fromMember; this.toMember = toMember; this.status = ConnectionStatus.PENDING; this.requestedAt = LocalDateTime.now(); } public Member getFromMember() { return fromMember; } public Member getToMember() { return toMember; } public ConnectionStatus getStatus() { return status; } public void setStatus(ConnectionStatus status) { this.status = status; if (status == ConnectionStatus.ACCEPTED) { this.acceptedAt = LocalDateTime.now(); } } } ================================================ FILE: solutions/java/src/linkedin/entities/Education.java ================================================ package linkedin.entities; public class Education { private final String school; private final String degree; private final int startYear; private final int endYear; public Education(String school, String degree, int startYear, int endYear) { this.school = school; this.degree = degree; this.startYear = startYear; this.endYear = endYear; } @Override public String toString() { return String.format("%s, %s (%d - %d)", degree, school, startYear, endYear); } } ================================================ FILE: solutions/java/src/linkedin/entities/Experience.java ================================================ package linkedin.entities; import java.time.LocalDate; public class Experience { private final String title; private final String company; private final LocalDate startDate; private final LocalDate endDate; // Can be null for current job public Experience(String title, String company, LocalDate startDate, LocalDate endDate) { this.title = title; this.company = company; this.startDate = startDate; this.endDate = endDate; } @Override public String toString() { return String.format("%s at %s (%s to %s)", title, company, startDate, endDate == null ? "Present" : endDate); } } ================================================ FILE: solutions/java/src/linkedin/entities/Like.java ================================================ package linkedin.entities; import java.time.LocalDateTime; public class Like { private final Member member; private final LocalDateTime createdAt; public Like(Member member) { this.member = member; this.createdAt = LocalDateTime.now(); } public Member getMember() { return member; } } ================================================ FILE: solutions/java/src/linkedin/entities/Member.java ================================================ package linkedin.entities; import linkedin.observer.NotificationObserver; import java.util.*; public class Member implements NotificationObserver { private final String id; private final String name; private final String email; private final Profile profile; private final Set connections = new HashSet<>(); private final List notifications = new ArrayList<>(); private Member(String id, String name, String email, Profile profile) { this.id = id; this.name = name; this.email = email; this.profile = profile; } public String getId() { return id; } public String getName() { return name; } public String getEmail() { return email; } public Set getConnections() { return connections; } public Profile getProfile() { return profile; } public void addConnection(Member member) { connections.add(member); } public void displayProfile() { System.out.println("\n--- Profile for " + name + " (" + email + ") ---"); profile.display(); System.out.println(" Connections: " + connections.size()); } public void viewNotifications() { System.out.println("\n--- Notifications for " + name + " ---"); if (notifications.isEmpty()) { System.out.println(" No new notifications."); return; } notifications.stream() .filter(n -> !n.isRead()) .forEach(n -> { System.out.println(" - " + n.getContent()); n.markAsRead(); // Mark as read after viewing }); } @Override public void update(Notification notification) { this.notifications.add(notification); System.out.printf("Notification pushed to %s: %s%n", this.name, notification.getContent()); } // Builder Class public static class Builder { private final String id; private final String name; private final String email; private final Profile profile = new Profile(); public Builder(String name, String email) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; } public Builder withSummary(String summary) { this.profile.setSummary(summary); return this; } public Builder addExperience(Experience experience) { this.profile.addExperience(experience); return this; } public Builder addEducation(Education education) { this.profile.addEducation(education); return this; } public Member build() { return new Member(id, name, email, profile); } } } ================================================ FILE: solutions/java/src/linkedin/entities/NewsFeed.java ================================================ package linkedin.entities; import linkedin.strategy.FeedSortingStrategy; import java.util.List; public class NewsFeed { private final List posts; public NewsFeed(List posts) { this.posts = posts; } public void display(FeedSortingStrategy strategy) { List sortedPosts = strategy.sort(posts); if (sortedPosts.isEmpty()) { System.out.println(" Your news feed is empty."); return; } sortedPosts.forEach(post -> { System.out.println("----------------------------------------"); System.out.printf("Post by: %s (at %s)%n", post.getAuthor().getName(), post.getCreatedAt().toLocalDate()); System.out.println("Content: " + post.getContent()); System.out.printf("Likes: %d, Comments: %d%n", post.getLikes().size(), post.getComments().size()); System.out.println("----------------------------------------"); }); } } ================================================ FILE: solutions/java/src/linkedin/entities/Notification.java ================================================ package linkedin.entities; import linkedin.enums.NotificationType; import java.time.LocalDateTime; import java.util.UUID; public class Notification { private final String id; private final String memberId; // The ID of the member to notify private final NotificationType type; private final String content; private final LocalDateTime createdAt; private boolean isRead = false; public Notification(String memberId, NotificationType type, String content) { this.id = UUID.randomUUID().toString(); this.memberId = memberId; this.type = type; this.content = content; this.createdAt = LocalDateTime.now(); } public String getContent() { return content; } public void markAsRead() { this.isRead = true; } public boolean isRead() { return isRead; } } ================================================ FILE: solutions/java/src/linkedin/entities/Post.java ================================================ package linkedin.entities; import linkedin.enums.NotificationType; import linkedin.observer.Subject; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class Post extends Subject { private final String id; private final Member author; private final String content; private final LocalDateTime createdAt; private final List likes = new ArrayList<>(); private final List comments = new ArrayList<>(); public Post(Member author, String content) { this.id = UUID.randomUUID().toString(); this.author = author; this.content = content; this.createdAt = LocalDateTime.now(); // The author should be notified of interactions with their own post this.addObserver(author); } public void addLike(Member member) { likes.add(new Like(member)); String notificationContent = member.getName() + " liked your post."; Notification notification = new Notification(author.getId(), NotificationType.POST_LIKE, notificationContent); notifyObservers(notification); } public void addComment(Member member, String text) { comments.add(new Comment(member, text)); String notificationContent = member.getName() + " commented on your post: \"" + text + "\""; Notification notification = new Notification(author.getId(), NotificationType.POST_COMMENT, notificationContent); notifyObservers(notification); } public String getId() { return id; } public Member getAuthor() { return author; } public String getContent() { return content; } public LocalDateTime getCreatedAt() { return createdAt; } public List getLikes() { return likes; } public List getComments() { return comments; } } ================================================ FILE: solutions/java/src/linkedin/entities/Profile.java ================================================ package linkedin.entities; import java.util.ArrayList; import java.util.List; public class Profile { private String summary; private final List experiences = new ArrayList<>(); private final List educations = new ArrayList<>(); public void setSummary(String summary) { this.summary = summary; } public void addExperience(Experience experience) { experiences.add(experience); } public void addEducation(Education education) { educations.add(education); } public void display() { System.out.println(" Summary: " + (summary != null ? summary : "N/A")); System.out.println(" Experience:"); if (experiences.isEmpty()) System.out.println(" - None"); else experiences.forEach(exp -> System.out.println(" - " + exp)); System.out.println(" Education:"); if (educations.isEmpty()) System.out.println(" - None"); else educations.forEach(edu -> System.out.println(" - " + edu)); } } ================================================ FILE: solutions/java/src/linkedin/enums/ConnectionStatus.java ================================================ package linkedin.enums; public enum ConnectionStatus { PENDING, ACCEPTED, REJECTED, WITHDRAWN } ================================================ FILE: solutions/java/src/linkedin/enums/NotificationType.java ================================================ package linkedin.enums; public enum NotificationType { CONNECTION_REQUEST, POST_LIKE, POST_COMMENT } ================================================ FILE: solutions/java/src/linkedin/observer/NotificationObserver.java ================================================ package linkedin.observer; import linkedin.entities.Notification; public interface NotificationObserver { void update(Notification notification); } ================================================ FILE: solutions/java/src/linkedin/observer/Subject.java ================================================ package linkedin.observer; import linkedin.entities.Notification; import java.util.ArrayList; import java.util.List; public abstract class Subject { private final List observers = new ArrayList<>(); public void addObserver(NotificationObserver observer) { observers.add(observer); } public void removeObserver(NotificationObserver observer) { observers.remove(observer); } public void notifyObservers(Notification notification) { for (NotificationObserver observer : observers) { observer.update(notification); } } } ================================================ FILE: solutions/java/src/linkedin/services/ConnectionService.java ================================================ package linkedin.services; import linkedin.enums.ConnectionStatus; import linkedin.enums.NotificationType; import linkedin.entities.Connection; import linkedin.entities.Member; import linkedin.entities.Notification; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class ConnectionService { private final NotificationService notificationService; // Simulates a DB table for connection requests private final Map connectionRequests = new ConcurrentHashMap<>(); public ConnectionService(NotificationService notificationService) { this.notificationService = notificationService; } public String sendRequest(Member from, Member to) { Connection connection = new Connection(from, to); String requestId = UUID.randomUUID().toString(); connectionRequests.put(requestId, connection); System.out.printf("%s sent a connection request to %s.%n", from.getName(), to.getName()); Notification notification = new Notification( to.getId(), NotificationType.CONNECTION_REQUEST, from.getName() + " wants to connect with you. Request ID: " + requestId ); notificationService.sendNotification(to, notification); return requestId; } public void acceptRequest(String requestId) { Connection request = connectionRequests.get(requestId); if (request != null && request.getStatus() == ConnectionStatus.PENDING) { request.setStatus(ConnectionStatus.ACCEPTED); Member from = request.getFromMember(); Member to = request.getToMember(); from.addConnection(to); to.addConnection(from); System.out.printf("%s accepted the connection request from %s.%n", to.getName(), from.getName()); connectionRequests.remove(requestId); // Clean up } else { System.out.println("Invalid or already handled request ID."); } } } ================================================ FILE: solutions/java/src/linkedin/services/NewsFeedService.java ================================================ package linkedin.services; import linkedin.entities.Member; import linkedin.entities.NewsFeed; import linkedin.entities.Post; import linkedin.strategy.FeedSortingStrategy; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class NewsFeedService { private final Map> allPosts; // A map of memberId -> list of their posts public NewsFeedService() { this.allPosts = new ConcurrentHashMap<>(); } public void addPost(Member member, Post post) { String memberId = member.getId(); if(!allPosts.containsKey(memberId)) { allPosts.put(memberId, new ArrayList<>()); } allPosts.get(memberId).add(post); } public List getMemberPosts(Member member) { return allPosts.getOrDefault(member.getId(), new ArrayList<>()); } public void displayFeedForMember(Member member, FeedSortingStrategy feedSortingStrategy) { List feedPosts = new ArrayList<>(); // Add posts from the member's connections for (Member connection : member.getConnections()) { List connectionPosts = allPosts.get(connection.getId()); if (connectionPosts != null) { feedPosts.addAll(connectionPosts); } } NewsFeed feed = new NewsFeed(feedPosts); feed.display(feedSortingStrategy); } } ================================================ FILE: solutions/java/src/linkedin/services/NotificationService.java ================================================ package linkedin.services; import linkedin.entities.Member; import linkedin.entities.Notification; public class NotificationService { public void sendNotification(Member member, Notification notification) { // In a real system, this would push to a queue or a websocket. // Here, we directly call the member's update method. member.update(notification); } } ================================================ FILE: solutions/java/src/linkedin/services/SearchService.java ================================================ package linkedin.services; import linkedin.entities.Member; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class SearchService { private final Collection members; public SearchService(Collection members) { this.members = members; } public List searchByName(String name) { List result = new ArrayList<>(); members.stream() .filter(member -> member.getName().toLowerCase().contains(name.toLowerCase())) // substring search .forEach(result::add); return result; } } ================================================ FILE: solutions/java/src/linkedin/strategy/ChronologicalSortStrategy.java ================================================ package linkedin.strategy; import linkedin.entities.Post; import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class ChronologicalSortStrategy implements FeedSortingStrategy { @Override public List sort(List posts) { List result = new ArrayList<>(); posts.stream() .sorted(Comparator.comparing(Post::getCreatedAt).reversed()) .forEach(result::add); return result; } } ================================================ FILE: solutions/java/src/linkedin/strategy/FeedSortingStrategy.java ================================================ package linkedin.strategy; import linkedin.entities.Post; import java.util.List; public interface FeedSortingStrategy { List sort(List posts); } ================================================ FILE: solutions/java/src/loggingframework/AsyncLogProcessor.java ================================================ package loggingframework; import loggingframework.entities.LogMessage; import loggingframework.strategies.appender.LogAppender; import java.util.List; import java.util.concurrent.*; class AsyncLogProcessor { private final ExecutorService executor; public AsyncLogProcessor() { this.executor = Executors.newSingleThreadExecutor(runnable -> { Thread thread = new Thread(runnable, "AsyncLogProcessor"); thread.setDaemon(true); // Don't prevent JVM exit return thread; }); } public void process(LogMessage logMessage, List appenders) { if (executor.isShutdown()) { System.err.println("Logger is shut down. Cannot process log message."); return; } // Submit a new task to the executor. executor.submit(() -> { for (LogAppender appender : appenders) { appender.append(logMessage); } }); } public void stop() { // Disable new tasks from being submitted executor.shutdown(); try { if (!executor.awaitTermination(2, TimeUnit.SECONDS)) { System.err.println("Logger executor did not terminate in the specified time."); // Forcibly shut down any still-running tasks. executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } } ================================================ FILE: solutions/java/src/loggingframework/LogManager.java ================================================ package loggingframework; import loggingframework.strategies.appender.LogAppender; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class LogManager { private static final LogManager INSTANCE = new LogManager(); private final Map loggers = new ConcurrentHashMap<>(); private final Logger rootLogger; private final AsyncLogProcessor processor; private LogManager() { this.rootLogger = new Logger("root", null); this.loggers.put("root", rootLogger); this.processor = new AsyncLogProcessor(); } public static LogManager getInstance() { return INSTANCE; } public Logger getLogger(String name) { return loggers.computeIfAbsent(name, this::createLogger); } private Logger createLogger(String name) { if (name.equals("root")) { return rootLogger; } int lastDot = name.lastIndexOf('.'); String parentName = (lastDot == -1) ? "root" : name.substring(0, lastDot); Logger parent = getLogger(parentName); return new Logger(name, parent); } public Logger getRootLogger() { return rootLogger; } AsyncLogProcessor getProcessor() { return processor; } public void shutdown() { // Stop the processor first to ensure all logs are written. processor.stop(); // Then, close all appenders. loggers.values().stream() .flatMap(logger -> logger.getAppenders().stream()) .distinct() .forEach(LogAppender::close); System.out.println("Logging framework shut down gracefully."); } } ================================================ FILE: solutions/java/src/loggingframework/Logger.java ================================================ package loggingframework; import loggingframework.entities.LogMessage; import loggingframework.enums.LogLevel; import loggingframework.strategies.appender.LogAppender; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class Logger { private final String name; private LogLevel level; private final Logger parent; private final List appenders; private boolean additivity = true; Logger(String name, Logger parent) { this.name = name; this.parent = parent; this.appenders = new CopyOnWriteArrayList<>(); } public void addAppender(LogAppender appender) { appenders.add(appender); } public List getAppenders() { return appenders; } public void setLevel(LogLevel minLevel) { this.level = minLevel; } public void setAdditivity(boolean additivity) { this.additivity = additivity; } public LogLevel getEffectiveLevel() { for (Logger logger = this; logger != null; logger = logger.parent) { LogLevel currentLevel = logger.level; if (currentLevel != null) { return currentLevel; } } return LogLevel.DEBUG; // Default root level } public void log(LogLevel messageLevel, String message) { if (messageLevel.isGreaterOrEqual(getEffectiveLevel())) { LogMessage logMessage = new LogMessage(messageLevel, this.name, message); callAppenders(logMessage); } } private void callAppenders(LogMessage logMessage) { if (!appenders.isEmpty()) { LogManager.getInstance().getProcessor().process(logMessage, this.appenders); } if (additivity && parent != null) { parent.callAppenders(logMessage); } } public void debug(String message) { log(LogLevel.DEBUG, message); } public void info(String message) { log(LogLevel.INFO, message); } public void warn(String message) { log(LogLevel.WARN, message); } public void error(String message) { log(LogLevel.ERROR, message); } public void fatal(String message) { log(LogLevel.FATAL, message); } } ================================================ FILE: solutions/java/src/loggingframework/LoggingFrameworkDemo.java ================================================ package loggingframework; import loggingframework.enums.LogLevel; import loggingframework.strategies.appender.ConsoleAppender; public class LoggingFrameworkDemo { public static void main(String[] args) { // --- 1. Initial Configuration --- LogManager logManager = LogManager.getInstance(); Logger rootLogger = logManager.getRootLogger(); rootLogger.setLevel(LogLevel.INFO); // Set global minimum level to INFO // Add a console appender to the root logger rootLogger.addAppender(new ConsoleAppender()); System.out.println("--- Initial Logging Demo ---"); Logger mainLogger = logManager.getLogger("com.example.Main"); mainLogger.info("Application starting up."); mainLogger.debug("This is a debug message, it should NOT appear."); // Below root level mainLogger.warn("This is a warning message."); // --- 2. Hierarchy and Additivity Demo --- System.out.println("\n--- Logger Hierarchy Demo ---"); Logger dbLogger = logManager.getLogger("com.example.db"); // dbLogger inherits level and appenders from root dbLogger.info("Database connection pool initializing."); // Let's create a more specific logger and override its level Logger serviceLogger = logManager.getLogger("com.example.service.UserService"); serviceLogger.setLevel(LogLevel.DEBUG); // More verbose logging for this specific service serviceLogger.info("User service starting."); serviceLogger.debug("This debug message SHOULD now appear for the service logger."); // --- 3. Dynamic Configuration Change --- System.out.println("\n--- Dynamic Configuration Demo ---"); System.out.println("Changing root log level to DEBUG..."); rootLogger.setLevel(LogLevel.DEBUG); mainLogger.debug("This debug message should now be visible."); try { Thread.sleep(500); logManager.shutdown(); } catch (Exception e) { System.out.println("Caught exception"); } } } ================================================ FILE: solutions/java/src/loggingframework/README.md ================================================ # Logging Framework (LLD) ## Problem Statement Design and implement a flexible and extensible logging framework that can be used by applications to log messages at different levels (INFO, DEBUG, ERROR, etc.), support multiple output destinations (console, file, etc.), and allow for custom formatting of log messages. --- ## Requirements - **Log Levels:** Support for multiple log levels (INFO, DEBUG, ERROR, etc.). - **Multiple Appenders:** Ability to log to different destinations (console, file, etc.). - **Custom Formatting:** Support for custom log message formatting. - **Configuration:** Ability to configure loggers and appenders. - **Thread Safety:** Should be thread-safe for concurrent logging. - **Extensibility:** Easy to add new log levels, appenders, or formatters. --- ## Core Entities - **Logger:** Main class used by clients to log messages. - **LogLevel:** Enum representing different log levels. - **LogMessage:** Encapsulates the details of a log event. - **LogFormatter:** Interface for formatting log messages. - **DefaultFormatter:** Default implementation of `LogFormatter`. - **LoggerConfig:** Holds configuration for the logger (appenders, formatters, etc.). - **LogAppender (in `logappender/`):** Interface and implementations for output destinations (e.g., ConsoleAppender, FileAppender). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/loggingframework-class-diagram.png) ### 1. Logger - **Methods:** - `log(LogLevel level, String message)` - `info(String message)` - `debug(String message)` - `error(String message)` - `setConfig(LoggerConfig config)` ### 2. LogLevel - Enum for log levels (INFO, DEBUG, ERROR, etc.) ### 3. LogMessage - Fields: `level`, `message`, `timestamp`, etc. ### 4. LogFormatter (Interface) - `String format(LogMessage message)` ### 5. DefaultFormatter - Implements `LogFormatter` with a default format. ### 6. LoggerConfig - Holds configuration for loggers (appenders, formatters, log level). ### 7. LogAppender (in `logappender/`) - Interface for appenders. - Implementations: `ConsoleAppender`, `FileAppender`, etc. --- ## Design Patterns Used - **Strategy Pattern:** For interchangeable log formatters and appenders. - **Singleton Pattern:** (If used) For global logger instance. - **Factory Pattern:** (Optional) For creating appenders/formatters based on config. - **Observer Pattern:** (Conceptually, for notifying multiple appenders.) --- ## Example Usage ```java Logger logger = new Logger(); logger.setConfig(new LoggerConfig(...)); logger.info("Application started"); logger.error("An error occurred"); ``` --- ## Demo See `LoggingFrameworkDemo.java` for a sample usage of the logging framework. --- ## Extending the Framework - **Add a new log level:** Update `LogLevel.java`. - **Add a new appender:** Implement the `LogAppender` interface in `logappender/`. - **Add a new formatter:** Implement the `LogFormatter` interface. --- ================================================ FILE: solutions/java/src/loggingframework/entities/LogMessage.java ================================================ package loggingframework.entities; import loggingframework.enums.LogLevel; import java.time.LocalDateTime; public final class LogMessage { private final LocalDateTime timestamp; private final LogLevel level; private final String loggerName; private final String threadName; private final String message; public LogMessage(LogLevel level, String loggerName, String message) { this.timestamp = LocalDateTime.now(); this.level = level; this.loggerName = loggerName; this.message = message; this.threadName = Thread.currentThread().getName(); } // Getters for all fields public LocalDateTime getTimestamp() { return timestamp; } public LogLevel getLevel() { return level; } public String getLoggerName() { return loggerName; } public String getThreadName() { return threadName; } public String getMessage() { return message; } } ================================================ FILE: solutions/java/src/loggingframework/enums/LogLevel.java ================================================ package loggingframework.enums; public enum LogLevel { DEBUG(1), INFO(2), WARN(3), ERROR(4), FATAL(5); private final int level; LogLevel(int level) { this.level = level; } public boolean isGreaterOrEqual(LogLevel other) { return this.level >= other.level; } } ================================================ FILE: solutions/java/src/loggingframework/strategies/appender/ConsoleAppender.java ================================================ package loggingframework.strategies.appender; import loggingframework.strategies.formatter.LogFormatter; import loggingframework.entities.LogMessage; import loggingframework.strategies.formatter.SimpleTextFormatter; public class ConsoleAppender implements LogAppender { private LogFormatter formatter; public ConsoleAppender() { this.formatter = new SimpleTextFormatter(); } @Override public void append(LogMessage logMessage) { System.out.println(formatter.format(logMessage)); } @Override public void close() {} @Override public void setFormatter(LogFormatter formatter) { this.formatter = formatter; } @Override public LogFormatter getFormatter() { return formatter; } } ================================================ FILE: solutions/java/src/loggingframework/strategies/appender/FileAppender.java ================================================ package loggingframework.strategies.appender; import loggingframework.strategies.formatter.LogFormatter; import loggingframework.entities.LogMessage; import loggingframework.strategies.formatter.SimpleTextFormatter; import java.io.FileWriter; import java.io.IOException; public class FileAppender implements LogAppender { private FileWriter writer; private LogFormatter formatter; public FileAppender(String filePath) { this.formatter = new SimpleTextFormatter(); try { this.writer = new FileWriter(filePath, true); } catch (Exception e) { System.out.println("Failed to create writer for file logs, exception: " + e.getMessage()); } } @Override public synchronized void append(LogMessage logMessage) { try { writer.write(formatter.format(logMessage) + "\n"); writer.flush(); } catch (IOException e) { System.out.println("Failed to write logs to file, exception: " + e.getMessage()); } } @Override public void close() { try { writer.close(); } catch (IOException e) { System.out.println("Failed to close logs file, exception: " + e.getMessage()); } } @Override public void setFormatter(LogFormatter formatter) { this.formatter = formatter; } @Override public LogFormatter getFormatter() { return formatter; } } ================================================ FILE: solutions/java/src/loggingframework/strategies/appender/LogAppender.java ================================================ package loggingframework.strategies.appender; import loggingframework.entities.LogMessage; import loggingframework.strategies.formatter.LogFormatter; public interface LogAppender { void append(LogMessage logMessage); void close(); LogFormatter getFormatter(); void setFormatter(LogFormatter formatter); } ================================================ FILE: solutions/java/src/loggingframework/strategies/formatter/LogFormatter.java ================================================ package loggingframework.strategies.formatter; import loggingframework.entities.LogMessage; public interface LogFormatter { String format(LogMessage logMessage); } ================================================ FILE: solutions/java/src/loggingframework/strategies/formatter/SimpleTextFormatter.java ================================================ package loggingframework.strategies.formatter; import loggingframework.entities.LogMessage; import java.time.format.DateTimeFormatter; public class SimpleTextFormatter implements LogFormatter { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); @Override public String format(LogMessage logMessage) { return String.format("%s [%s] %s - %s: %s\n", logMessage.getTimestamp().format(DATE_TIME_FORMATTER), logMessage.getThreadName(), logMessage.getLevel(), logMessage.getLoggerName(), logMessage.getMessage()); } } ================================================ FILE: solutions/java/src/lrucache/DoublyLinkedList.java ================================================ package lrucache; class DoublyLinkedList { private final Node head; private final Node tail; public DoublyLinkedList() { head = new Node<>(null, null); // Dummy head tail = new Node<>(null, null); // Dummy tail head.next = tail; tail.prev = head; } public void addFirst(Node node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } public void remove(Node node) { node.prev.next = node.next; node.next.prev = node.prev; } public void moveToFront(Node node) { remove(node); addFirst(node); } public Node removeLast() { if (tail.prev == head) return null; Node last = tail.prev; remove(last); return last; } } ================================================ FILE: solutions/java/src/lrucache/LRUCache.java ================================================ package lrucache; import java.util.HashMap; import java.util.Map; public class LRUCache { private final int capacity; private final Map> map; private final DoublyLinkedList dll; public LRUCache(int capacity) { this.capacity = capacity; this.map = new HashMap<>(); this.dll = new DoublyLinkedList<>(); } public synchronized V get(K key) { if (!map.containsKey(key)) return null; Node node = map.get(key); dll.moveToFront(node); return node.value; } public synchronized void put(K key, V value) { if (map.containsKey(key)) { Node node = map.get(key); node.value = value; dll.moveToFront(node); } else { if (map.size() == capacity) { Node lru = dll.removeLast(); if (lru != null) map.remove(lru.key); } Node newNode = new Node<>(key, value); dll.addFirst(newNode); map.put(key, newNode); } } public synchronized void remove(K key) { if (!map.containsKey(key)) return; Node node = map.get(key); dll.remove(node); map.remove(key); } } ================================================ FILE: solutions/java/src/lrucache/LRUCacheDemo.java ================================================ package lrucache; public class LRUCacheDemo { public static void run() { LRUCache cache = new LRUCache<>(3); cache.put("a", 1); cache.put("b", 2); cache.put("c", 3); System.out.println(cache.get("a")); // 1 cache.put("d", 4); System.out.println(cache.get("b")); // null } } ================================================ FILE: solutions/java/src/lrucache/Node.java ================================================ package lrucache; class Node { K key; V value; Node prev, next; public Node(K key, V value) { this.key = key; this.value = value; } } ================================================ FILE: solutions/java/src/lrucache/README.md ================================================ # LRU Cache (LLD) ## Problem Statement Design and implement an LRU (Least Recently Used) Cache with a fixed capacity. The cache should support fast retrieval and insertion, and automatically evict the least recently used item when the capacity is exceeded. --- ## Requirements - **Fixed Capacity:** The cache has a maximum size. When full, the least recently used item is evicted on insertion. - **Fast Operations:** Both `get(key)` and `put(key, value)` operations should be O(1). - **Eviction Policy:** The least recently used item is removed when the cache exceeds its capacity. - **Extensibility:** Easy to change the eviction policy or underlying data structures. --- ## Core Entities - **LRUCache:** Main class implementing the cache logic, manages storage and eviction. - **Node:** Represents a doubly-linked list node for fast removal and insertion. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/lrucache-class-diagram.png) ### 1. LRUCache - **Fields:** capacity, Map>, head/tail pointers for the doubly-linked list - **Methods:** - `get(K key)`: Returns the value for the key if present, else -1/null. Moves the node to the front (most recently used). - `put(K key, V value)`: Inserts or updates the value for the key. Moves the node to the front. If the cache exceeds capacity, evicts the least recently used node. - `removeNode(Node)`, `addToFront(Node)`, `moveToFront(Node)`, `evictLRU()`: Helper methods for list management. ### 2. Node - **Fields:** key, value, prev, next --- ## Design Patterns Used - **Doubly Linked List:** For O(1) removal and insertion of nodes. - **Hash Map:** For O(1) access to nodes by key. - **Separation of Concerns:** Node and cache logic are separated. --- ## Example Usage ```java LRUCache cache = new LRUCache(2); cache.put(1, 1); // cache: {1=1} cache.put(2, 2); // cache: {1=1, 2=2} cache.get(1); // returns 1, cache: {2=2, 1=1} cache.put(3, 3); // evicts key 2, cache: {1=1, 3=3} cache.get(2); // returns -1 (not found) ``` --- ## Demo See `LRUCacheDemo.java` for a sample usage and simulation of the LRU cache. --- ## Extending the Framework - **Change eviction policy:** Implement a different policy (e.g., LFU) by modifying the eviction logic. - **Change data structures:** Use other structures for different performance characteristics. --- ================================================ FILE: solutions/java/src/movieticketbookingsystem/BookingManager.java ================================================ package movieticketbookingsystem; import movieticketbookingsystem.enums.PaymentStatus; import movieticketbookingsystem.entities.*; import movieticketbookingsystem.strategy.payment.PaymentStrategy; import java.util.List; import java.util.Optional; public class BookingManager { private final SeatLockManager seatLockManager; public BookingManager(SeatLockManager seatLockManager) { this.seatLockManager = seatLockManager; } public Optional createBooking(User user, Show show, List seats, PaymentStrategy paymentStrategy) { // 1. Lock the seats seatLockManager.lockSeats(show, seats, user.getId()); // 2. Calculate the total price double totalAmount = show.getPricingStrategy().calculatePrice(seats); // 3. Process Payment Payment payment = paymentStrategy.pay(totalAmount); // 4. If payment is successful, create the booking if (payment.getStatus() == PaymentStatus.SUCCESS) { Booking booking = new Booking.BookingBuilder() .setUser(user) .setShow(show) .setSeats(seats) .setTotalAmount(totalAmount) .setPayment(payment) .build(); // 5. Confirm the booking (mark seats as BOOKED) booking.confirmBooking(); // Clean up the lock map seatLockManager.unlockSeats(show, seats, user.getId()); return Optional.of(booking); } else { System.out.println("Payment failed. Please try again."); return Optional.empty(); } } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/MovieBookingDemo.java ================================================ package movieticketbookingsystem; import movieticketbookingsystem.enums.SeatStatus; import movieticketbookingsystem.enums.SeatType; import movieticketbookingsystem.entities.*; import movieticketbookingsystem.observer.UserObserver; import movieticketbookingsystem.strategy.payment.CreditCardPaymentStrategy; import movieticketbookingsystem.strategy.pricing.WeekdayPricingStrategy; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; public class MovieBookingDemo { public static void main (String[]args){ // Setup MovieBookingService service = MovieBookingService.getInstance(); City nyc = service.addCity("city1", "New York"); City la = service.addCity("city2", "Los Angeles"); // 2. Add movies Movie matrix = new Movie("M1", "The Matrix", 120); Movie avengers = new Movie("M2", "Avengers: Endgame", 170); service.addMovie(matrix); service.addMovie(avengers); // Add Seats for a Screen Screen screen1 = new Screen("S1"); for (int i = 1; i <= 10; i++) { screen1.addSeat(new Seat("A" + i, 1, i, i <= 5 ? SeatType.REGULAR : SeatType.PREMIUM)); screen1.addSeat(new Seat("B" + i, 2, i, i <= 5 ? SeatType.REGULAR : SeatType.PREMIUM)); } // Add Cinemas Cinema amcNYC = service.addCinema("cinema1", "AMC Times Square", nyc.getId(), List.of(screen1)); // Add Shows Show matrixShow = service.addShow("show1", matrix, screen1, LocalDateTime.now().plusHours(2), new WeekdayPricingStrategy()); Show avengersShow = service.addShow("show2", avengers, screen1, LocalDateTime.now().plusHours(5), new WeekdayPricingStrategy()); // --- User and Observer Setup --- User alice = service.createUser("Alice", "alice@example.com"); UserObserver aliceObserver = new UserObserver(alice); avengers.addObserver(aliceObserver); // Simulate movie release System.out.println("\n--- Notifying Observers about Movie Release ---"); avengers.notifyObservers(); // --- User Story: Alice books tickets --- System.out.println("\n--- Alice's Booking Flow ---"); String cityName = "New York"; String movieTitle = "Avengers: Endgame"; // 1. Search for shows List availableShows = service.findShows(movieTitle, cityName); if (availableShows.isEmpty()) { System.out.println("No shows found for " + movieTitle + " in " + cityName); return; } Show selectedShow = availableShows.get(0); // Alice selects the first show // 2. View available seats List availableSeats = selectedShow.getScreen().getSeats().stream() .filter(seat -> seat.getStatus() == SeatStatus.AVAILABLE) .toList(); System.out.printf("Available seats for '%s' at %s: %s%n", selectedShow.getMovie().getTitle(), selectedShow.getStartTime(), availableSeats.stream().map(Seat::getId).collect(Collectors.toList())); // 3. Select seats List desiredSeats = List.of(availableSeats.get(2), availableSeats.get(3)); System.out.println("Alice selects seats: " + desiredSeats.stream().map(Seat::getId).toList()); // 4. Book Tickets Optional bookingOpt = service.bookTickets( alice.getId(), selectedShow.getId(), desiredSeats, new CreditCardPaymentStrategy("1234-5678-9876-5432", "123") ); if (bookingOpt.isPresent()) { Booking booking = bookingOpt.get(); System.out.println("\n--- Booking Successful! ---"); System.out.println("Booking ID: " + booking.getId()); System.out.println("User: " + booking.getUser().getName()); System.out.println("Movie: " + booking.getShow().getMovie().getTitle()); System.out.println("Seats: " + booking.getSeats().stream().map(Seat::getId).toList()); System.out.println("Total Amount: $" + booking.getTotalAmount()); System.out.println("Payment Status: " + booking.getPayment().getStatus()); } else { System.out.println("Booking failed."); } // 5. Verify seat status after booking System.out.println("\nSeat status after Alice's booking:"); desiredSeats.forEach(seat -> System.out.printf("Seat %s status: %s%n", seat.getId(), seat.getStatus())); // 6. Shut down the system to release resources like the scheduler. service.shutdown(); } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/MovieBookingService.java ================================================ package movieticketbookingsystem; import movieticketbookingsystem.entities.*; import movieticketbookingsystem.strategy.payment.PaymentStrategy; import movieticketbookingsystem.strategy.pricing.PricingStrategy; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; public class MovieBookingService { private static volatile MovieBookingService instance; private final Map cities; private final Map cinemas; private final Map movies; private final Map users; private final Map shows; // Core services - managed by the system private final SeatLockManager seatLockManager; private final BookingManager bookingManager; private MovieBookingService() { this.cities = new ConcurrentHashMap<>(); this.cinemas = new ConcurrentHashMap<>(); this.movies = new ConcurrentHashMap<>(); this.users = new ConcurrentHashMap<>(); this.shows = new ConcurrentHashMap<>(); this.seatLockManager = new SeatLockManager(); this.bookingManager = new BookingManager(seatLockManager); } public static MovieBookingService getInstance() { if (instance == null) { synchronized (MovieBookingService.class) { if (instance == null) { instance = new MovieBookingService(); } } } return instance; } public BookingManager getBookingManager() { return bookingManager; } // --- Data Management Methods --- public City addCity(String id, String name) { City city = new City(id, name); cities.put(city.getId(), city); return city; } public Cinema addCinema(String id, String name, String cityId, List screens) { City city = cities.get(cityId); Cinema cinema = new Cinema(id, name, city, screens); cinemas.put(cinema.getId(), cinema); return cinema; } public void addMovie(Movie movie) { this.movies.put(movie.getId(), movie); } public Show addShow(String id, Movie movie, Screen screen, LocalDateTime startTime, PricingStrategy pricingStrategy) { Show show = new Show(id, movie, screen, startTime, pricingStrategy); shows.put(show.getId(), show); return show; } public User createUser(String name, String email) { User user = new User(name, email); users.put(user.getId(), user); return user; } public Optional bookTickets(String userId, String showId, List desiredSeats, PaymentStrategy paymentStrategy) { return bookingManager.createBooking( users.get(userId), shows.get(showId), desiredSeats, paymentStrategy ); } // --- Search Functionality --- public List findShows(String movieTitle, String cityName) { List result = new ArrayList<>(); shows.values().stream() .filter(show -> show.getMovie().getTitle().equalsIgnoreCase(movieTitle)) .filter(show -> { Cinema cinema = findCinemaForShow(show); return cinema != null && cinema.getCity().getName().equalsIgnoreCase(cityName); }) .forEach(result::add); return result; } private Cinema findCinemaForShow(Show show) { // This is inefficient. In a real system, shows would have a direct link to the cinema. // For this example, we traverse the cinema list. return cinemas.values().stream() .filter(cinema -> cinema.getScreens().contains(show.getScreen())) .findFirst() .orElse(null); } public void shutdown() { this.seatLockManager.shutdown(); System.out.println("MovieTicketBookingSystem has been shut down."); } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/README.md ================================================ # Movie Ticket Booking System (LLD) ## Problem Statement Design and implement a Movie Ticket Booking System that allows users to book movie tickets, select seats, and manage shows. The system should handle movie schedules, theater management, and seat reservations. --- ## Requirements 1. **Movie Management:** - Store movie information (title, duration, language) - Manage movie schedules and shows - Track movie availability 2. **Theater Management:** - Manage theater information - Handle multiple shows per theater - Track theater capacity 3. **Show Management:** - Schedule shows for movies - Manage show timings - Handle show availability 4. **Seat Management:** - Track seat availability - Handle seat selection - Manage different seat types 5. **Booking Management:** - Process parkingTicket bookings - Handle booking cancellations - Manage booking status --- ## Core Entities ### 1. MovieTicketBookingSystem - **Fields:** List movies, List theaters, List shows - **Methods:** - addMovie() - addTheater() - addShow() - bookTicket() - cancelBooking() - getAvailableShows() ### 2. Movie - **Fields:** String id, String title, int duration, String language - **Methods:** - getShows() - isAvailable() ### 3. Theater - **Fields:** String id, String name, String location - **Methods:** - addShow() - getShows() - getCapacity() ### 4. Show - **Fields:** String id, Movie movie, Theater theater, Date showTime, List seats - **Methods:** - getAvailableSeats() - bookSeat() - cancelSeat() ### 5. User - **Fields:** String id, String name, String email - **Methods:** - getBookings() - updateProfile() ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/MovieTicketBookingSystem-class-diagram.png) --- ## Example Usage ```java MovieTicketBookingSystem system = new MovieTicketBookingSystem(); // Add a movie Movie movie = system.addMovie("Inception", 150, "English"); // Add a theater Theater theater = system.addTheater("Cineplex", "Downtown"); // Add a show Show show = system.addShow(movie, theater, showTime); // Book tickets User user = new User("John Doe", "john@example.com"); Booking booking = system.bookTicket(user, show, seats); ``` --- ## Demo See `MovieTicketBookingDemo.java` for a sample usage and simulation of the movie parkingTicket booking system. --- ## Extending the Framework - **Add payment processing:** Integrate payment gateway for parkingTicket purchases - **Add seat selection UI:** Implement interactive seat selection interface - **Add pricing tiers:** Support different pricing for different seat types - **Add show scheduling:** Implement advanced show scheduling algorithms - **Add notification system:** Send booking confirmations and reminders - **Add user reviews:** Allow users to rate and review movies --- ## Design Patterns Used - **Singleton Pattern:** For the booking system instance - **Factory Pattern:** For creating different types of seats - **Observer Pattern:** For seat availability updates - **Strategy Pattern:** For different pricing strategies --- ## Exception Handling - **SeatNotAvailableException:** Thrown when trying to book an unavailable seat - **InvalidShowException:** Thrown when show details are invalid - **BookingFailedException:** Thrown when booking process fails - **CancellationFailedException:** Thrown when cancellation process fails --- ================================================ FILE: solutions/java/src/movieticketbookingsystem/SeatLockManager.java ================================================ package movieticketbookingsystem; import movieticketbookingsystem.enums.SeatStatus; import movieticketbookingsystem.entities.Show; import movieticketbookingsystem.entities.Seat; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class SeatLockManager { private final Map> lockedSeats = new ConcurrentHashMap<>(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private static final long LOCK_TIMEOUT_MS = 500; // 0.5 seconds. In real world, timeout would be in minutes public void lockSeats(Show show, List seats, String userId) { synchronized (show) { // Synchronize on the show to ensure atomicity for that specific show // Check if any of the requested seats are already locked or booked for (Seat seat : seats) { if (seat.getStatus() != SeatStatus.AVAILABLE) { System.out.println("Seat " + seat.getId() + " is not available."); return; } } // Lock the seats for (Seat seat : seats) { seat.setStatus(SeatStatus.LOCKED); } lockedSeats.computeIfAbsent(show, k -> new ConcurrentHashMap<>()); for (Seat seat : seats) { lockedSeats.get(show).put(seat, userId); } // Schedule a task to unlock the seats after a timeout scheduler.schedule(() -> unlockSeats(show, seats, userId), LOCK_TIMEOUT_MS, TimeUnit.MILLISECONDS); System.out.println("Locked seats: " + seats.stream().map(Seat::getId).toList() + " for user " + userId); } } public void unlockSeats(Show show, List seats, String userId) { synchronized (show) { Map showLocks = lockedSeats.get(show); if (showLocks != null) { for (Seat seat : seats) { // Only unlock if it's still locked by the same user (prevents race conditions) if (showLocks.containsKey(seat) && showLocks.get(seat).equals(userId)) { showLocks.remove(seat); if(seat.getStatus() == SeatStatus.LOCKED) { seat.setStatus(SeatStatus.AVAILABLE); System.out.println("Unlocked seat: " + seat.getId() + " due to timeout."); } else { showLocks.remove(seat); System.out.println("Unlocked seat: " + seat.getId() + " due to booking completion."); } } } if (showLocks.isEmpty()) { lockedSeats.remove(show); } } } } public void shutdown() { System.out.println("Shutting down SeatLockProvider scheduler."); scheduler.shutdown(); try { if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { scheduler.shutdownNow(); } } catch (InterruptedException e) { scheduler.shutdownNow(); Thread.currentThread().interrupt(); } } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Booking.java ================================================ package movieticketbookingsystem.entities; import movieticketbookingsystem.enums.SeatStatus; import java.util.List; public class Booking { private final String id; private final User user; private final Show show; private final List seats; private final double totalAmount; private final Payment payment; // Private constructor to be used by the Builder private Booking(String id, User user, Show show, List seats, double totalAmount, Payment payment) { this.id = id; this.user = user; this.show = show; this.seats = seats; this.totalAmount = totalAmount; this.payment = payment; } // Marks seats as BOOKED upon successful booking creation public void confirmBooking() { for (Seat seat : seats) { seat.setStatus(SeatStatus.BOOKED); } } public String getId() { return id; } public User getUser() { return user; } public Show getShow() { return show; } public List getSeats() { return seats; } public double getTotalAmount() { return totalAmount; } public Payment getPayment() { return payment; } // Static inner Builder class public static class BookingBuilder { private String id; private User user; private Show show; private List seats; private double totalAmount; private Payment payment; public BookingBuilder setId(String id) { this.id = id; return this; } public BookingBuilder setUser(User user) { this.user = user; return this; } public BookingBuilder setShow(Show show) { this.show = show; return this; } public BookingBuilder setSeats(List seats) { this.seats = seats; return this; } public BookingBuilder setTotalAmount(double totalAmount) { this.totalAmount = totalAmount; return this; } public BookingBuilder setPayment(Payment payment) { this.payment = payment; return this; } public Booking build() { // Validations can be added here return new Booking(id, user, show, seats, totalAmount, payment); } } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Cinema.java ================================================ package movieticketbookingsystem.entities; import java.util.List; public class Cinema { private final String id; private final String name; private final City city; private final List screens; public Cinema(String id, String name, City city, List screens) { this.id = id; this.name = name; this.city = city; this.screens = screens; } public String getId() { return id; } public String getName() { return name; } public City getCity() { return city; } public List getScreens() { return screens; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/City.java ================================================ package movieticketbookingsystem.entities; public class City { private final String id; private final String name; public City(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Movie.java ================================================ package movieticketbookingsystem.entities; import movieticketbookingsystem.observer.MovieSubject; public class Movie extends MovieSubject { private final String id; private final String title; private final int durationInMinutes; public Movie(String id, String title, int durationInMinutes) { this.id = id; this.title = title; this.durationInMinutes = durationInMinutes; } public String getId() { return id; } public String getTitle() { return title; } // Additional movie details like genre, language etc. can be added here } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Payment.java ================================================ package movieticketbookingsystem.entities; import movieticketbookingsystem.enums.PaymentStatus; import java.util.UUID; public class Payment { private final String id; private final double amount; private final PaymentStatus status; private final String transactionId; public Payment(double amount, PaymentStatus status, String transactionId) { this.id = UUID.randomUUID().toString(); this.amount = amount; this.status = status; this.transactionId = transactionId; } public PaymentStatus getStatus() { return status; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Screen.java ================================================ package movieticketbookingsystem.entities; import java.util.ArrayList; import java.util.List; public class Screen { private final String id; private final List seats; public Screen(String id) { this.id = id; this.seats = new ArrayList<>(); } public void addSeat(Seat seat) { seats.add(seat); } public String getId() { return id; } public List getSeats() { return seats; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Seat.java ================================================ package movieticketbookingsystem.entities; import movieticketbookingsystem.enums.SeatStatus; import movieticketbookingsystem.enums.SeatType; public class Seat { private final String id; private final int row; private final int col; private final SeatType type; private SeatStatus status; public Seat(String id, int row, int col, SeatType type) { this.id = id; this.row = row; this.col = col; this.type = type; this.status = SeatStatus.AVAILABLE; } // Getters and a setter for status public String getId() { return id; } public int getRow() { return row; } public int getCol() { return col; } public SeatType getType() { return type; } public SeatStatus getStatus() { return status; } public void setStatus(SeatStatus status) { this.status = status; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/Show.java ================================================ package movieticketbookingsystem.entities; import movieticketbookingsystem.strategy.pricing.PricingStrategy; import java.time.LocalDateTime; public class Show { private final String id; private final Movie movie; private final Screen screen; private final LocalDateTime startTime; private final PricingStrategy pricingStrategy; public Show(String id, Movie movie, Screen screen, LocalDateTime startTime, PricingStrategy pricingStrategy) { this.id = id; this.movie = movie; this.screen = screen; this.startTime = startTime; this.pricingStrategy = pricingStrategy; } public String getId() { return id; } public Movie getMovie() { return movie; } public Screen getScreen() { return screen; } public LocalDateTime getStartTime() { return startTime; } public PricingStrategy getPricingStrategy() { return pricingStrategy; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/entities/User.java ================================================ package movieticketbookingsystem.entities; import java.util.UUID; public class User { private final String id; private final String name; private final String email; public User(String name, String email) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/enums/PaymentStatus.java ================================================ package movieticketbookingsystem.enums; public enum PaymentStatus { SUCCESS, FAILURE, PENDING } ================================================ FILE: solutions/java/src/movieticketbookingsystem/enums/SeatStatus.java ================================================ package movieticketbookingsystem.enums; public enum SeatStatus { AVAILABLE, BOOKED, LOCKED // Temporarily held during booking process } ================================================ FILE: solutions/java/src/movieticketbookingsystem/enums/SeatType.java ================================================ package movieticketbookingsystem.enums; public enum SeatType { REGULAR(50.0), PREMIUM(80.0), RECLINER(120.0); private final double price; SeatType(double price) { this.price = price; } public double getPrice() { return price; } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/observer/MovieObserver.java ================================================ package movieticketbookingsystem.observer; import movieticketbookingsystem.entities.Movie; public interface MovieObserver { void update(Movie movie); } ================================================ FILE: solutions/java/src/movieticketbookingsystem/observer/MovieSubject.java ================================================ package movieticketbookingsystem.observer; import movieticketbookingsystem.entities.Movie; import java.util.ArrayList; import java.util.List; public abstract class MovieSubject { private final List observers = new ArrayList<>(); public void addObserver(MovieObserver observer) { observers.add(observer); } public void removeObserver(MovieObserver observer) { observers.remove(observer); } public void notifyObservers() { for (MovieObserver observer : observers) { observer.update((Movie) this); } } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/observer/UserObserver.java ================================================ package movieticketbookingsystem.observer; import movieticketbookingsystem.entities.Movie; import movieticketbookingsystem.entities.User; public class UserObserver implements MovieObserver { private final User user; public UserObserver(User user) { this.user = user; } @Override public void update(Movie movie) { System.out.printf("Notification for %s (%s): Movie '%s' is now available for booking!%n", user.getName(), user.getId(), movie.getTitle()); } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/strategy/payment/CreditCardPaymentStrategy.java ================================================ package movieticketbookingsystem.strategy.payment; import movieticketbookingsystem.enums.PaymentStatus; import movieticketbookingsystem.entities.Payment; import java.util.UUID; public class CreditCardPaymentStrategy implements PaymentStrategy { private final String cardNumber; private final String cvv; public CreditCardPaymentStrategy(String cardNumber, String cvv) { this.cardNumber = cardNumber; this.cvv = cvv; } @Override public Payment pay(double amount) { System.out.printf("Processing credit card payment of $%.2f%n", amount); // Simulate payment gateway interaction boolean paymentSuccess = Math.random() > 0.05; // 95% success rate return new Payment( amount, paymentSuccess ? PaymentStatus.SUCCESS : PaymentStatus.FAILURE, "TXN_" + UUID.randomUUID() ); } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/strategy/payment/PaymentStrategy.java ================================================ package movieticketbookingsystem.strategy.payment; import movieticketbookingsystem.entities.Payment; public interface PaymentStrategy { Payment pay(double amount); } ================================================ FILE: solutions/java/src/movieticketbookingsystem/strategy/pricing/PricingStrategy.java ================================================ package movieticketbookingsystem.strategy.pricing; import movieticketbookingsystem.entities.Seat; import java.util.List; public interface PricingStrategy { double calculatePrice(List seats); } ================================================ FILE: solutions/java/src/movieticketbookingsystem/strategy/pricing/WeekdayPricingStrategy.java ================================================ package movieticketbookingsystem.strategy.pricing; import movieticketbookingsystem.entities.Seat; import java.util.List; public class WeekdayPricingStrategy implements PricingStrategy { @Override public double calculatePrice(List seats) { return seats.stream().mapToDouble(seat -> seat.getType().getPrice()).sum(); } } ================================================ FILE: solutions/java/src/movieticketbookingsystem/strategy/pricing/WeekendPricingStrategy.java ================================================ package movieticketbookingsystem.strategy.pricing; import movieticketbookingsystem.entities.Seat; import java.util.List; public class WeekendPricingStrategy implements PricingStrategy { private static final double WEEKEND_SURCHARGE = 1.2; // 20% surcharge @Override public double calculatePrice(List seats) { double basePrice = seats.stream().mapToDouble(seat -> seat.getType().getPrice()).sum(); return basePrice * WEEKEND_SURCHARGE; } } ================================================ FILE: solutions/java/src/musicstreamingservice/MusicStreamingDemo.java ================================================ package musicstreamingservice; import musicstreamingservice.command.NextTrackCommand; import musicstreamingservice.command.PauseCommand; import musicstreamingservice.command.PlayCommand; import musicstreamingservice.enums.SubscriptionTier; import musicstreamingservice.entities.*; import java.util.List; public class MusicStreamingDemo { public static void main(String[] args) throws InterruptedException { MusicStreamingSystem system = MusicStreamingSystem.getInstance(); // --- Setup Catalog --- Artist daftPunk = new Artist("art1", "Daft Punk"); system.addArtist(daftPunk); Album discovery = new Album("Discovery"); Song s1 = system.addSong("s1", "One More Time", daftPunk.getId(), 320); Song s2 = system.addSong("s2", "Aerodynamic", daftPunk.getId(), 212); Song s3 = system.addSong("s3", "Digital Love", daftPunk.getId(), 301); Song s4 = system.addSong("s4", "Radioactive", daftPunk.getId(), 311); discovery.addTrack(s1); discovery.addTrack(s2); discovery.addTrack(s3); discovery.addTrack(s4); // --- Register Users (Builder Pattern) --- User freeUser = new User.Builder("Alice").withSubscription(SubscriptionTier.FREE, 0).build(); User premiumUser = new User.Builder("Bob").withSubscription(SubscriptionTier.PREMIUM, 0).build(); system.registerUser(freeUser); system.registerUser(premiumUser); // --- Observer Pattern: User follows artist --- System.out.println("--- Observer Pattern Demo ---"); premiumUser.followArtist(daftPunk); daftPunk.releaseAlbum(discovery); // This will notify Bob System.out.println(); // --- Strategy Pattern: Playback behavior --- System.out.println("--- Strategy Pattern (Free vs Premium) & State Pattern (Player) Demo ---"); Player player = system.getPlayer(); player.load(discovery, freeUser); // --- Command Pattern: Controlling the player --- PlayCommand play = new PlayCommand(player); PauseCommand pause = new PauseCommand(player); NextTrackCommand next = new NextTrackCommand(player); play.execute(); // Plays song 1 next.execute(); // Plays song 2 pause.execute(); // Pauses song 2 play.execute(); // Resumes song 2 next.execute(); // Plays song 3 next.execute(); // Plays song 4 (ad for free user) System.out.println(); // --- Premium user experience (no ads) --- System.out.println("--- Premium User Experience ---"); player.load(discovery, premiumUser); play.execute(); next.execute(); System.out.println(); // --- Composite Pattern: Play a playlist --- System.out.println("--- Composite Pattern Demo ---"); Playlist myPlaylist = new Playlist("My Awesome Mix"); myPlaylist.addTrack(s3); // Digital Love myPlaylist.addTrack(s1); // One More Time player.load(myPlaylist, premiumUser); play.execute(); next.execute(); System.out.println(); // --- Search and Recommendation --- System.out.println("--- Search and Recommendation Service Demo ---"); List searchResults = system.searchSongsByTitle("love"); System.out.println("Search results for 'love': " + searchResults); List recommendations = system.getSongRecommendations(); System.out.println("Your daily recommendations: " + recommendations); } } ================================================ FILE: solutions/java/src/musicstreamingservice/MusicStreamingSystem.java ================================================ package musicstreamingservice; import musicstreamingservice.entities.Artist; import musicstreamingservice.entities.Player; import musicstreamingservice.entities.Song; import musicstreamingservice.entities.User; import musicstreamingservice.services.RecommendationService; import musicstreamingservice.services.SearchService; import musicstreamingservice.strategies.recommendation.GenreBasedRecommendationStrategy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MusicStreamingSystem { private static volatile MusicStreamingSystem instance; private final Map users = new HashMap<>(); private final Map songs = new HashMap<>(); private final Map artists = new HashMap<>(); private final Player player; private final SearchService searchService; private final RecommendationService recommendationService; private MusicStreamingSystem() { this.player = new Player(); this.searchService = new SearchService(); this.recommendationService = new RecommendationService(new GenreBasedRecommendationStrategy()); } public static MusicStreamingSystem getInstance() { if (instance == null) { synchronized (MusicStreamingSystem.class) { if (instance == null) { instance = new MusicStreamingSystem(); } } } return instance; } public void registerUser(User user) { users.put(user.getId(), user); } public Song addSong(String id, String title, String artistId, int duration) { Song song = new Song(id, title, artists.get(artistId), duration); songs.put(song.getId(), song); return song; } public void addArtist(Artist artist) { artists.put(artist.getId(), artist); } public List searchSongsByTitle(String title) { return searchService.searchSongsByTitle(new ArrayList<>(songs.values()), title); } public List getSongRecommendations() { return recommendationService.generateRecommendations(new ArrayList<>(songs.values())); } public Player getPlayer() { return player; } } ================================================ FILE: solutions/java/src/musicstreamingservice/README.md ================================================ # Music Streaming Service (LLD) ## Problem Statement Design and implement an online music streaming service (like Spotify) that allows users to browse, search, and play songs, manage playlists, follow artists, and receive recommendations. --- ## Requirements - **User Management:** Users can register, log in, and manage their profiles. - **Browse & Search:** Users can browse and search for songs, albums, and artists. - **Playlists:** Users can create, update, and manage playlists. - **Playback Controls:** Users can play, pause, skip, and seek within songs. - **Recommendations:** The system recommends songs and playlists based on user preferences and listening history. - **Follow Artists:** Users can follow artists to get updates and recommendations. - **Concurrency:** The system handles concurrent requests and smooth streaming for multiple users. - **Scalability:** The system is scalable to handle a large volume of songs and users. - **Extensibility:** Easy to add features like social sharing, offline playback, or collaborative playlists. --- ## Core Entities - **Song:** Represents a song with properties like ID, title, artist, album, and duration. - **Album:** Represents an album containing multiple songs and associated with an artist. - **Artist:** Represents a music artist, with a list of albums and songs. - **User:** Represents a user with ID, username, password, playlists, and listening history. - **Playlist:** Represents a user-created playlist containing a list of songs. - **MusicLibrary:** Central repository for storing and managing songs, albums, and artists (Singleton). - **UserManager:** Handles user registration, login, and user-related operations (Singleton). - **MusicPlayer:** Handles music playback (play, pause, skip, seek). - **MusicRecommender:** Generates song and playlist recommendations based on user preferences and history (Singleton). - **MusicStreamingService:** Main entry point, initializes components, handles user requests, and manages overall functionality. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/musicstreamingservice-class-diagram.png) ### 1. Song - **Fields:** int id, String title, Artist artist, Album album, int duration - **Methods:** getId(), getTitle(), getArtist(), getAlbum(), getDuration() ### 2. Album - **Fields:** int id, String title, Artist artist, List songs - **Methods:** getId(), getTitle(), getArtist(), getSongs() ### 3. Artist - **Fields:** int id, String name, List albums, List songs - **Methods:** getId(), getName(), getAlbums(), getSongs() ### 4. User - **Fields:** int id, String username, String password, List playlists, List listeningHistory, List followedArtists - **Methods:** getId(), getUsername(), getPlaylists(), followArtist(Artist), etc. ### 5. Playlist - **Fields:** int id, String name, List songs - **Methods:** addSong(Song), removeSong(Song), getSongs() ### 6. MusicLibrary (Singleton) - **Fields:** Map songs, Map albums, Map artists - **Methods:** addSong(Song), addAlbum(Album), addArtist(Artist), searchSongs(String), searchAlbums(String), searchArtists(String) ### 7. UserManager (Singleton) - **Fields:** Map users - **Methods:** registerUser(...), login(...), getUser(int id) ### 8. MusicPlayer - **Fields:** Song currentSong, int currentPosition, boolean isPlaying - **Methods:** play(Song), pause(), skip(), seek(int position) ### 9. MusicRecommender (Singleton) - **Methods:** recommendSongs(User), recommendPlaylists(User) ### 10. MusicStreamingService - **Fields:** MusicLibrary library, UserManager userManager, MusicPlayer player, MusicRecommender recommender - **Methods:** initialize(), handleUserRequest(...), etc. --- ## Design Patterns Used - **Singleton Pattern:** For `MusicLibrary`, `UserManager`, and `MusicRecommender` to ensure a single instance. --- ## Example Usage ```java MusicStreamingService service = new MusicStreamingService(); service.initialize(); User alice = service.getUserManager().registerUser("alice", "password"); Artist artist = new Artist(1, "The Beatles"); Album album = new Album(1, "Abbey Road", artist); Song song = new Song(1, "Come Together", artist, album, 259); service.getLibrary().addArtist(artist); service.getLibrary().addAlbum(album); service.getLibrary().addSong(song); alice.getPlaylists().add(new Playlist(1, "Favorites")); alice.getPlaylists().get(0).addSong(song); service.getPlayer().play(song); ``` --- ## Demo See `MusicStreamingServiceDemo.java` for a sample usage and simulation of the music streaming service. --- ## Extending the Framework - **Add social features:** Allow users to share playlists or follow each other. - **Add offline playback:** Support downloading songs for offline listening. - **Add collaborative playlists:** Allow multiple users to edit a playlist. --- ================================================ FILE: solutions/java/src/musicstreamingservice/command/Command.java ================================================ package musicstreamingservice.command; public interface Command { void execute(); } ================================================ FILE: solutions/java/src/musicstreamingservice/command/NextTrackCommand.java ================================================ package musicstreamingservice.command; import musicstreamingservice.entities.Player; public class NextTrackCommand implements Command { private final Player player; public NextTrackCommand(Player player) { this.player = player; } @Override public void execute() { player.clickNext(); } } ================================================ FILE: solutions/java/src/musicstreamingservice/command/PauseCommand.java ================================================ package musicstreamingservice.command; import musicstreamingservice.entities.Player; public class PauseCommand implements Command { private final Player player; public PauseCommand(Player player) { this.player = player; } @Override public void execute() { player.clickPause(); } } ================================================ FILE: solutions/java/src/musicstreamingservice/command/PlayCommand.java ================================================ package musicstreamingservice.command; import musicstreamingservice.entities.Player; public class PlayCommand implements Command { private final Player player; public PlayCommand(Player player) { this.player = player; } @Override public void execute() { player.clickPlay(); } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Album.java ================================================ package musicstreamingservice.entities; import java.util.ArrayList; import java.util.List; public class Album implements Playable { private final String title; private final List tracks = new ArrayList<>(); public Album(String title) { this.title = title; } public void addTrack(Song song) { tracks.add(song); } @Override public List getTracks() { return List.copyOf(tracks); } public String getTitle() { return title; } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Artist.java ================================================ package musicstreamingservice.entities; import musicstreamingservice.observer.Subject; import java.util.ArrayList; import java.util.List; public class Artist extends Subject { private final String id; private final String name; private final List discography = new ArrayList<>(); public Artist(String id, String name) { this.id = id; this.name = name; } public void releaseAlbum(Album album) { discography.add(album); System.out.printf("[System] Artist %s has released a new album: %s%n", name, album.getTitle()); notifyObservers(this, album); } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Playable.java ================================================ package musicstreamingservice.entities; import java.util.List; public interface Playable { List getTracks(); } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Player.java ================================================ package musicstreamingservice.entities; import musicstreamingservice.enums.PlayerStatus; import musicstreamingservice.state.PlayerState; import musicstreamingservice.state.StoppedState; import java.util.ArrayList; import java.util.List; public class Player { private PlayerState state; private PlayerStatus status; private List queue = new ArrayList<>(); private int currentIndex = -1; private Song currentSong; private User currentUser; public Player() { this.state = new StoppedState(); this.status = PlayerStatus.STOPPED; } public void load(Playable playable, User user) { this.currentUser = user; this.queue = playable.getTracks(); this.currentIndex = 0; System.out.printf("Loaded %d tracks for user %s.%n", queue.size(), user.getName()); this.state = new StoppedState(); } public void playCurrentSongInQueue() { if (currentIndex >= 0 && currentIndex < queue.size()) { Song songToPlay = queue.get(currentIndex); currentUser.getPlaybackStrategy().play(songToPlay, this); } } // Methods for state transitions public void clickPlay() { state.play(this); } public void clickPause() { state.pause(this); } public void clickNext() { if (currentIndex < queue.size() - 1) { currentIndex++; playCurrentSongInQueue(); } else { System.out.println("End of queue."); state.stop(this); } } // Getters and Setters used by States public void changeState(PlayerState state) { this.state = state; } public void setStatus(PlayerStatus status) { this.status = status; } public void setCurrentSong(Song song) { this.currentSong = song; } public boolean hasQueue() { return !queue.isEmpty(); } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Playlist.java ================================================ package musicstreamingservice.entities; import java.util.ArrayList; import java.util.List; public class Playlist implements Playable { private final String name; private final List tracks = new ArrayList<>(); public Playlist(String name) { this.name = name; } public void addTrack(Song song) { tracks.add(song); } @Override public List getTracks() { return List.copyOf(tracks); } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/Song.java ================================================ package musicstreamingservice.entities; import java.util.Collections; import java.util.List; public class Song implements Playable { private final String id; private final String title; private final Artist artist; private final int durationInSeconds; public Song(String id, String title, Artist artist, int durationInSeconds) { this.id = id; this.title = title; this.artist = artist; this.durationInSeconds = durationInSeconds; } @Override public List getTracks() { return Collections.singletonList(this); } @Override public String toString() { return String.format("'%s' by %s", title, artist.getName()); } public String getId() { return id; } public String getTitle() { return title; } public Artist getArtist() { return artist; } } ================================================ FILE: solutions/java/src/musicstreamingservice/entities/User.java ================================================ package musicstreamingservice.entities; import musicstreamingservice.enums.SubscriptionTier; import musicstreamingservice.observer.ArtistObserver; import musicstreamingservice.strategies.playback.PlaybackStrategy; import java.util.HashSet; import java.util.Set; import java.util.UUID; public class User implements ArtistObserver { private final String id; private final String name; private final PlaybackStrategy playbackStrategy; private final Set followedArtists = new HashSet<>(); private User(String id, String name, PlaybackStrategy strategy) { this.id = id; this.name = name; this.playbackStrategy = strategy; } public void followArtist(Artist artist) { followedArtists.add(artist); artist.addObserver(this); } @Override public void update(Artist artist, Album newAlbum) { System.out.printf("[Notification for %s] Your followed artist %s just released a new album: %s!%n", this.name, artist.getName(), newAlbum.getTitle()); } public PlaybackStrategy getPlaybackStrategy() { return playbackStrategy; } public String getId() { return id; } public String getName() { return name; } // Builder Pattern public static class Builder { private final String id; private final String name; private PlaybackStrategy playbackStrategy; public Builder(String name) { this.id = UUID.randomUUID().toString(); this.name = name; } public Builder withSubscription(SubscriptionTier tier, int songsPlayed) { this.playbackStrategy = PlaybackStrategy.getStrategy(tier, songsPlayed); return this; } public User build() { return new User(id, name, playbackStrategy); } } } ================================================ FILE: solutions/java/src/musicstreamingservice/enums/PlayerStatus.java ================================================ package musicstreamingservice.enums; public enum PlayerStatus { PLAYING, PAUSED, STOPPED } ================================================ FILE: solutions/java/src/musicstreamingservice/enums/SubscriptionTier.java ================================================ package musicstreamingservice.enums; public enum SubscriptionTier { FREE, PREMIUM } ================================================ FILE: solutions/java/src/musicstreamingservice/observer/ArtistObserver.java ================================================ package musicstreamingservice.observer; import musicstreamingservice.entities.Album; import musicstreamingservice.entities.Artist; public interface ArtistObserver { void update(Artist artist, Album newAlbum); } ================================================ FILE: solutions/java/src/musicstreamingservice/observer/Subject.java ================================================ package musicstreamingservice.observer; import musicstreamingservice.entities.Album; import musicstreamingservice.entities.Artist; import java.util.ArrayList; import java.util.List; public abstract class Subject { private final List observers = new ArrayList<>(); public void addObserver(ArtistObserver observer) { observers.add(observer); } public void removeObserver(ArtistObserver observer) { observers.remove(observer); } public void notifyObservers(Artist artist, Album album) { for (ArtistObserver observer : observers) { observer.update(artist, album); } } } ================================================ FILE: solutions/java/src/musicstreamingservice/services/RecommendationService.java ================================================ package musicstreamingservice.services; import musicstreamingservice.entities.Song; import musicstreamingservice.strategies.recommendation.RecommendationStrategy; import java.util.List; public class RecommendationService { private RecommendationStrategy strategy; public RecommendationService(RecommendationStrategy strategy) { this.strategy = strategy; } public void setStrategy(RecommendationStrategy strategy) { this.strategy = strategy; } public List generateRecommendations(List allSongs) { return strategy.recommend(allSongs); } } ================================================ FILE: solutions/java/src/musicstreamingservice/services/SearchService.java ================================================ package musicstreamingservice.services; import musicstreamingservice.entities.Artist; import musicstreamingservice.entities.Song; import java.util.List; import java.util.stream.Collectors; public class SearchService { public List searchSongsByTitle(List songs, String query) { return songs.stream() .filter(s -> s.getTitle().toLowerCase().contains(query.toLowerCase())) .collect(Collectors.toList()); } public List searchArtistsByName(List artists, String query) { return artists.stream() .filter(a -> a.getName().toLowerCase().contains(query.toLowerCase())) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/musicstreamingservice/state/PausedState.java ================================================ package musicstreamingservice.state; import musicstreamingservice.enums.PlayerStatus; import musicstreamingservice.entities.Player; public class PausedState implements PlayerState { @Override public void play(Player player) { System.out.println("Resuming playback."); player.changeState(new PlayingState()); player.setStatus(PlayerStatus.PLAYING); } @Override public void pause(Player player) { System.out.println("Already paused."); } @Override public void stop(Player player) { System.out.println("Stopping playback from paused state."); player.changeState(new StoppedState()); player.setStatus(PlayerStatus.STOPPED); } } ================================================ FILE: solutions/java/src/musicstreamingservice/state/PlayerState.java ================================================ package musicstreamingservice.state; import musicstreamingservice.entities.Player; public interface PlayerState { void play(Player player); void pause(Player player); void stop(Player player); } ================================================ FILE: solutions/java/src/musicstreamingservice/state/PlayingState.java ================================================ package musicstreamingservice.state; import musicstreamingservice.enums.PlayerStatus; import musicstreamingservice.entities.Player; public class PlayingState implements PlayerState { @Override public void play(Player player) { System.out.println("Already playing."); } @Override public void pause(Player player) { System.out.println("Pausing playback." + player); player.changeState(new PausedState()); player.setStatus(PlayerStatus.PAUSED); } @Override public void stop(Player player) { System.out.println("Stopping playback."); player.changeState(new StoppedState()); player.setStatus(PlayerStatus.STOPPED); } } ================================================ FILE: solutions/java/src/musicstreamingservice/state/StoppedState.java ================================================ package musicstreamingservice.state; import musicstreamingservice.enums.PlayerStatus; import musicstreamingservice.entities.Player; public class StoppedState implements PlayerState { @Override public void play(Player player) { if (player.hasQueue()) { System.out.println("Starting playback."); player.changeState(new PlayingState()); player.setStatus(PlayerStatus.PLAYING); player.playCurrentSongInQueue(); } else { System.out.println("Queue is empty. Load songs to play."); } } @Override public void pause(Player player) { System.out.println("Cannot pause. Player is stopped."); } @Override public void stop(Player player) { System.out.println("Already stopped."); } } ================================================ FILE: solutions/java/src/musicstreamingservice/strategies/playback/FreePlaybackStrategy.java ================================================ package musicstreamingservice.strategies.playback; import musicstreamingservice.entities.Player; import musicstreamingservice.entities.Song; public class FreePlaybackStrategy implements PlaybackStrategy { private int songsPlayed; private static final int SONGS_BEFORE_AD = 3; public FreePlaybackStrategy(int initialSongsPlayed) { this.songsPlayed = initialSongsPlayed; } @Override public void play(Song song, Player player) { if (songsPlayed > 0 && songsPlayed % SONGS_BEFORE_AD == 0) { System.out.println("\n>>> Playing Advertisement: 'Buy Spotify Premium for ad-free music!' <<<\n"); } player.setCurrentSong(song); System.out.printf("Free User is now playing: %s%n", song); songsPlayed++; } } ================================================ FILE: solutions/java/src/musicstreamingservice/strategies/playback/PlaybackStrategy.java ================================================ package musicstreamingservice.strategies.playback; import musicstreamingservice.enums.SubscriptionTier; import musicstreamingservice.entities.Player; import musicstreamingservice.entities.Song; public interface PlaybackStrategy { void play(Song song, Player player); // Simple Factory method to get the correct strategy static PlaybackStrategy getStrategy(SubscriptionTier tier, int songsPlayed) { return tier == SubscriptionTier.PREMIUM ? new PremiumPlaybackStrategy() : new FreePlaybackStrategy(songsPlayed); } } ================================================ FILE: solutions/java/src/musicstreamingservice/strategies/playback/PremiumPlaybackStrategy.java ================================================ package musicstreamingservice.strategies.playback; import musicstreamingservice.entities.Player; import musicstreamingservice.entities.Song; public class PremiumPlaybackStrategy implements PlaybackStrategy { @Override public void play(Song song, Player player) { player.setCurrentSong(song); System.out.printf("Premium User is now playing: %s%n", song); } } ================================================ FILE: solutions/java/src/musicstreamingservice/strategies/recommendation/GenreBasedRecommendationStrategy.java ================================================ package musicstreamingservice.strategies.recommendation; import musicstreamingservice.entities.Song; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class GenreBasedRecommendationStrategy implements RecommendationStrategy { // In a real system, songs would have genres. We simulate this. @Override public List recommend(List allSongs) { System.out.println("Generating genre-based recommendations (simulated)..."); List shuffled = new java.util.ArrayList<>(allSongs); Collections.shuffle(shuffled); return shuffled.stream().limit(5).collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/musicstreamingservice/strategies/recommendation/RecommendationStrategy.java ================================================ package musicstreamingservice.strategies.recommendation; import musicstreamingservice.entities.Song; import java.util.List; public interface RecommendationStrategy { List recommend(List allSongs); } ================================================ FILE: solutions/java/src/onlineauctionsystem/AuctionService.java ================================================ package onlineauctionsystem; import onlineauctionsystem.entities.Auction; import onlineauctionsystem.entities.User; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class AuctionService { private static AuctionService instance; private final Map users; private final Map auctions; private final ScheduledExecutorService scheduler; private AuctionService() { users = new ConcurrentHashMap<>(); auctions = new ConcurrentHashMap<>(); this.scheduler = Executors.newScheduledThreadPool(1); } public static synchronized AuctionService getInstance() { if (instance == null) { instance = new AuctionService(); } return instance; } public User createUser(String name) { User user = new User(name); users.put(user.getId(), user); return user; } public User getUser(String userId) { return users.get(userId); } public Auction createAuction(String itemName, String description, BigDecimal startingPrice, LocalDateTime endTime) { Auction auction = new Auction(itemName, description, startingPrice, endTime); auctions.put(auction.getId(), auction); // In a real system, you'd use a scheduler to automatically end auctions. // This demonstrates how it would be done. long delay = java.time.Duration.between(LocalDateTime.now(), endTime).toMillis(); scheduler.schedule(() -> endAuction(auction.getId()), delay, TimeUnit.MILLISECONDS); System.out.printf("New auction created for '%s' (ID: %s), ending at %s.\n", itemName, auction.getId(), endTime); return auction; } public List viewActiveAuctions() { return auctions.values().stream().filter(Auction::isActive).toList(); } public void placeBid(String auctionId, String bidderId, BigDecimal amount) { Auction auction = getAuction(auctionId); auction.placeBid(users.get(bidderId), amount); } public void endAuction(String auctionId) { Auction auction = getAuction(auctionId); auction.endAuction(); } public Auction getAuction(String auctionId) { Auction auction = auctions.get(auctionId); if (auction == null) { throw new NoSuchElementException("Auction with ID " + auctionId + " not found."); } return auction; } public void shutdown() { scheduler.shutdown(); } } ================================================ FILE: solutions/java/src/onlineauctionsystem/AuctionSystemDemo.java ================================================ package onlineauctionsystem; import onlineauctionsystem.entities.Auction; import onlineauctionsystem.entities.User; import java.math.BigDecimal; import java.time.LocalDateTime; public class AuctionSystemDemo { public static void main(String[] args) { AuctionService auctionService = AuctionService.getInstance(); // Create users User alice = auctionService.createUser("Alice"); User bob = auctionService.createUser("Bob"); User carol = auctionService.createUser("Carol"); System.out.println("============================================="); System.out.println(" Online Auction System Demo "); System.out.println("============================================="); // 2. Create an auction that will last for a short duration LocalDateTime endTime = LocalDateTime.now().plusSeconds(10); Auction laptopAuction = auctionService.createAuction( "Vintage Laptop", "A rare 1990s laptop, in working condition.", new BigDecimal("100.00"), endTime ); System.out.println(); // 3. Bidding war starts try { auctionService.placeBid(laptopAuction.getId(), alice.getId(), new BigDecimal("110.00")); Thread.sleep(500); // Simulate time passing auctionService.placeBid(laptopAuction.getId(), bob.getId(), new BigDecimal("120.00")); // Alice gets an outbid notification Thread.sleep(500); auctionService.placeBid(laptopAuction.getId(), carol.getId(), new BigDecimal("125.00")); // Bob gets an outbid notification Thread.sleep(500); // (Charlie's bid is earlier for the same amount, making him the highest bidder) auctionService.placeBid(laptopAuction.getId(), alice.getId(), new BigDecimal("150.00")); // Charlie gets an outbid notification // 4. Wait for the auction to end automatically via the scheduler System.out.println("\n--- Waiting for auction to end automatically... ---"); Thread.sleep(2 * 1000); // Wait longer than the auction duration } catch (Exception e) { System.err.println("An error occurred during bidding: " + e.getMessage()); } // 5. Post-auction actions System.out.println("\n--- Post-Auction Information ---"); Auction endedAuction = auctionService.getAuction(laptopAuction.getId()); // Display winner if (endedAuction.getWinningBid() != null) { System.out.printf("Final Winner: %s\n", endedAuction.getWinningBid().getBidder().getName()); System.out.printf("Winning Price: $%.2f\n", endedAuction.getWinningBid().getAmount()); } else { System.out.println("The auction ended with no winner."); } // Display bid history System.out.println("\nFull Bid History:"); endedAuction.getBidHistory().forEach(System.out::println); // 6. Try to bid on an ended auction System.out.println("\n--- Attempting to bid on an ended auction ---"); try { auctionService.placeBid(laptopAuction.getId(), bob.getId(), new BigDecimal("200.00")); } catch (IllegalStateException e) { System.out.println("CAUGHT EXPECTED ERROR: " + e.getMessage()); } // 7. Shutdown the scheduler auctionService.shutdown(); } } ================================================ FILE: solutions/java/src/onlineauctionsystem/README.md ================================================ # Online Auction System (LLD) ## Problem Statement Design and implement an Online Auction System that allows users to create auctions, place bids on items, track auction status, and determine winners. --- ## Requirements - **User Management:** Users can register and participate in auctions. - **Item Management:** The system manages items that can be auctioned. - **Auction Creation:** Users can create auctions for items, specifying start and end times. - **Bidding:** Users can place bids on active auctions. - **Auction Status Tracking:** The system tracks the status of each auction (e.g., ACTIVE, ENDED). - **Winner Determination:** The system determines the winning bid and user when an auction ends. - **Extensibility:** Easy to add new features such as reserve prices, buy-now options, or notifications. --- ## Core Entities - **AuctionSystem:** Main class that manages users, items, auctions, and bidding. - **User:** Represents a user who can create auctions and place bids. - **Item:** Represents an item to be auctioned. - **Auction:** Represents an auction for an item, including bids, status, and winner. - **Bid:** Represents a bid placed by a user on an auction. - **AuctionStatus:** Enum for auction status (ACTIVE, ENDED). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/onlineauctionsystem-class-diagram.png) ### 1. AuctionSystem - **Fields:** List users, List items, List auctions - **Methods:** registerUser(User), addItem(Item), createAuction(Item, User, Date startTime, Date endTime), placeBid(Auction, User, double amount), endAuction(Auction), getActiveAuctions(), getEndedAuctions(), etc. ### 2. User - **Fields:** int id, String name ### 3. Item - **Fields:** int id, String name, String description ### 4. Auction - **Fields:** int id, Item item, User seller, List bids, AuctionStatus status, User winner, Date startTime, Date endTime - **Methods:** addBid(Bid), endAuction(), getHighestBid(), getWinner() ### 5. Bid - **Fields:** int id, User bidder, double amount, Date bidTime ### 6. AuctionStatus (enum) - Values: ACTIVE, ENDED --- ## Example Usage ```java AuctionSystem system = new AuctionSystem(); User alice = new User(1, "Alice"); User bob = new User(2, "Bob"); system.registerUser(alice); system.registerUser(bob); Item painting = new Item(1, "Painting", "Beautiful landscape painting"); system.addItem(painting); Auction auction = system.createAuction(painting, alice, new Date(), new Date(System.currentTimeMillis() + 3600000)); system.placeBid(auction, bob, 100.0); system.placeBid(auction, alice, 120.0); system.endAuction(auction); User winner = auction.getWinner(); System.out.println("Winner: " + (winner != null ? winner.getName() : "No winner")); ``` --- ## Demo See `AuctionSystemDemo.java` for a sample usage and simulation of the online auction system. --- ## Extending the Framework - **Add reserve prices:** Only sell if the highest bid meets the minimum price. - **Add buy-now options:** Allow instant purchase at a set price. - **Add notifications:** Notify users of auction events or outbids. --- ================================================ FILE: solutions/java/src/onlineauctionsystem/entities/Auction.java ================================================ package onlineauctionsystem.entities; import onlineauctionsystem.enums.AuctionStatus; import onlineauctionsystem.observer.AuctionObserver; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class Auction { private final String id; private final String itemName; private final String description; private final BigDecimal startingPrice; private final LocalDateTime endTime; private final List bids; private final Set observers; private AuctionStatus state; private Bid winningBid; public Auction(String itemName, String description, BigDecimal startingPrice, LocalDateTime endTime) { this.id = UUID.randomUUID().toString(); this.itemName = itemName; this.description = description; this.startingPrice = startingPrice; this.endTime = endTime; this.bids = new ArrayList<>(); this.observers = ConcurrentHashMap.newKeySet(); // Thread-safe set this.state = AuctionStatus.ACTIVE; } // --- Core Bidding and Auction Logic --- public synchronized void placeBid(User bidder, BigDecimal amount) { if (state != AuctionStatus.ACTIVE) { throw new IllegalStateException("Auction is not active."); } if (LocalDateTime.now().isAfter(endTime)) { endAuction(); throw new IllegalStateException("Auction has already ended."); } Bid highestBid = getHighestBid(); BigDecimal currentMaxAmount = (highestBid == null) ? startingPrice : highestBid.getAmount(); if (amount.compareTo(currentMaxAmount) <= 0) { throw new IllegalArgumentException("Bid must be higher than the current highest bid."); } User previousHighestBidder = (highestBid != null) ? highestBid.getBidder() : null; Bid newBid = new Bid(bidder, amount); bids.add(newBid); addObserver(bidder); // The new bidder is now an observer System.out.printf("SUCCESS: %s placed a bid of $%.2f on '%s'.\n", bidder.getName(), amount, itemName); // Notify the previous highest bidder that they have been outbid if (previousHighestBidder != null && !previousHighestBidder.equals(bidder)) { notifyObserver(previousHighestBidder, String.format("You have been outbid on '%s'! The new highest bid is $%.2f.", itemName, amount)); } } public synchronized void endAuction() { if (state != AuctionStatus.ACTIVE) { return; // Already ended } this.state = AuctionStatus.CLOSED; this.winningBid = getHighestBid(); String endMessage; if (winningBid != null) { endMessage = String.format("Auction for '%s' has ended. Winner is %s with a bid of $%.2f!", itemName, winningBid.getBidder().getName(), winningBid.getAmount()); } else { endMessage = String.format("Auction for '%s' has ended. There were no bids.", itemName); } System.out.println("\n" + endMessage.toUpperCase()); notifyAllObservers(endMessage); } public Bid getHighestBid() { if (bids.isEmpty()) { return null; } return Collections.max(bids); } public boolean isActive() { return state == AuctionStatus.ACTIVE; } // --- Observer Pattern Methods --- private void addObserver(AuctionObserver observer) { observers.add(observer); } private void notifyAllObservers(String message) { for (AuctionObserver observer : observers) { observer.onUpdate(this, message); } } private void notifyObserver(AuctionObserver observer, String message) { observer.onUpdate(this, message); } // --- Getters --- public String getId() { return id; } public String getItemName() { return itemName; } public List getBidHistory() { return Collections.unmodifiableList(bids); } public AuctionStatus getState() { return state; } public Bid getWinningBid() { return winningBid; } } ================================================ FILE: solutions/java/src/onlineauctionsystem/entities/Bid.java ================================================ package onlineauctionsystem.entities; import java.math.BigDecimal; import java.time.LocalDateTime; public class Bid implements Comparable { private final User bidder; private final BigDecimal amount; private final LocalDateTime timestamp; public Bid(User bidder, BigDecimal amount) { this.bidder = bidder; this.amount = amount; this.timestamp = LocalDateTime.now(); } public User getBidder() { return bidder; } public BigDecimal getAmount() { return amount; } public LocalDateTime getTimestamp() { return timestamp; } @Override public int compareTo(Bid other) { int amountComparison = this.amount.compareTo(other.amount); if (amountComparison != 0) { return amountComparison; } return other.timestamp.compareTo(this.timestamp); } @Override public String toString() { return String.format("Bidder: %s, Amount: %.2f, Time: %s", bidder.getName(), amount, timestamp); } } ================================================ FILE: solutions/java/src/onlineauctionsystem/entities/User.java ================================================ package onlineauctionsystem.entities; import onlineauctionsystem.observer.AuctionObserver; import java.util.UUID; public class User implements AuctionObserver { private final String id; private final String name; public User(String name) { this.id = UUID.randomUUID().toString(); this.name = name; } public String getId() { return id; } public String getName() { return name; } @Override public void onUpdate(Auction auction, String message) { System.out.printf("--- Notification for %s ---\n", this.name); System.out.printf("Auction: %s\n", auction.getItemName()); System.out.printf("Message: %s\n", message); System.out.println("---------------------------\n"); } } ================================================ FILE: solutions/java/src/onlineauctionsystem/enums/AuctionStatus.java ================================================ package onlineauctionsystem.enums; public enum AuctionStatus { PENDING, ACTIVE, CLOSED } ================================================ FILE: solutions/java/src/onlineauctionsystem/observer/AuctionObserver.java ================================================ package onlineauctionsystem.observer; import onlineauctionsystem.entities.Auction; public interface AuctionObserver { void onUpdate(Auction auction, String message); } ================================================ FILE: solutions/java/src/onlinelearningplatform/README.md ================================================ ================================================ FILE: solutions/java/src/onlineshoppingservice/OnlineShoppingDemo.java ================================================ package onlineshoppingservice; import onlineshoppingservice.decorator.GiftWrapDecorator; import onlineshoppingservice.enums.ProductCategory; import onlineshoppingservice.models.*; import onlineshoppingservice.strategy.CreditCardPaymentStrategy; import onlineshoppingservice.strategy.UPIPaymentStrategy; public class OnlineShoppingDemo { public static void main(String[] args) { // --- System Setup (Singleton and Services) --- OnlineShoppingSystem system = OnlineShoppingSystem.getInstance(); // --- Create and Add Products to Catalog (Builder Pattern) --- Product laptop = new Product.Builder("Dell XPS 15", 1499.99) .withDescription("A powerful and sleek laptop.") .withCategory(ProductCategory.ELECTRONICS) .build(); Product book = new Product.Builder("The Pragmatic Programmer", 45.50) .withDescription("A classic book for software developers.") .withCategory(ProductCategory.BOOKS) .build(); system.addProduct(laptop, 10); // 10 laptops in stock system.addProduct(book, 50); // 50 books in stock // --- Register a Customer --- Address aliceAddress = new Address("123 Main St", "Anytown", "CA", "12345"); Customer alice = system.registerCustomer("Alice", "alice@example.com", "password123", aliceAddress); // --- Alice Shops --- System.out.println("--- Alice starts shopping ---"); // Alice adds a laptop to her cart system.addToCart(alice.getId(), laptop.getId(), 1); System.out.println("Alice added a laptop to her cart."); // Alice decides to gift-wrap the book (Decorator Pattern) Product giftWrappedBook = new GiftWrapDecorator(book); system.addToCart(alice.getId(), giftWrappedBook.getId(), 1); System.out.printf("Alice added a gift-wrapped book. Original price: $%.2f, New price: $%.2f%n", book.getPrice(), giftWrappedBook.getPrice()); ShoppingCart aliceCart = system.getCustomerCart(alice.getId()); System.out.printf("Alice's cart total: $%.2f%n", aliceCart.calculateTotal()); // --- Alice Checks Out --- System.out.println("\n--- Alice proceeds to checkout ---"); Order aliceOrder = system.placeOrder(alice.getId(), new CreditCardPaymentStrategy("1234-5678-9876-5432")); if (aliceOrder == null) { System.out.println("Order placement failed."); return; } System.out.printf("Order #%s placed successfully for Alice.%n", aliceOrder.getId()); // --- Order State and Notifications (State, Observer Patterns) --- System.out.println("\n--- Order processing starts ---"); // The warehouse ships the order aliceOrder.shipOrder(); // This will trigger a notification to Alice // The delivery service marks the order as delivered aliceOrder.deliverOrder(); // This will also trigger a notification // Try to cancel a delivered order (State pattern prevents this) aliceOrder.cancelOrder(); System.out.println("\n--- Out of Stock Scenario ---"); Customer bob = system.registerCustomer("Bob", "bob@example.com", "pass123", aliceAddress); // Bob tries to buy 15 laptops, but only 9 are left (1 was bought by Alice) system.addToCart(bob.getId(), laptop.getId(), 15); Order bobOrder = system.placeOrder(bob.getId(), new UPIPaymentStrategy("testupi@hdfc")); if (bobOrder == null) { System.out.println("Bob's order was correctly prevented due to insufficient stock."); } } } ================================================ FILE: solutions/java/src/onlineshoppingservice/OnlineShoppingSystem.java ================================================ package onlineshoppingservice; import onlineshoppingservice.models.*; import onlineshoppingservice.services.InventoryService; import onlineshoppingservice.services.OrderService; import onlineshoppingservice.services.PaymentService; import onlineshoppingservice.services.SearchService; import onlineshoppingservice.strategy.PaymentStrategy; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class OnlineShoppingSystem { private static volatile OnlineShoppingSystem instance; // Data stores private final Map products = new ConcurrentHashMap<>(); private final Map customers = new ConcurrentHashMap<>(); private final Map orders = new ConcurrentHashMap<>(); // Services private final InventoryService inventoryService; private final PaymentService paymentService; private final OrderService orderService; private final SearchService searchService; private OnlineShoppingSystem() { this.inventoryService = new InventoryService(); this.paymentService = new PaymentService(); this.orderService = new OrderService(inventoryService); this.searchService = new SearchService(products.values()); } public static OnlineShoppingSystem getInstance() { if (instance == null) { synchronized (OnlineShoppingSystem.class) { if (instance == null) { instance = new OnlineShoppingSystem(); } } } return instance; } // --- Facade Methods for simplified interaction --- public void addProduct(Product product, int initialStock) { products.put(product.getId(), product); inventoryService.addStock(product, initialStock); } public Customer registerCustomer(String name, String email, String password, Address address) { Customer customer = new Customer(name, email, password, address); customers.put(customer.getId(), customer); return customer; } public void addToCart(String customerId, String productId, int quantity) { Customer customer = customers.get(customerId); Product product = products.get(productId); customer.getAccount().getCart().addItem(product, quantity); } public ShoppingCart getCustomerCart(String customerId) { Customer customer = customers.get(customerId); return customer.getAccount().getCart(); } public List searchProducts(String name) { return searchService.searchByName(name); } public Order placeOrder(String customerId, PaymentStrategy paymentStrategy) { Customer customer = customers.get(customerId); ShoppingCart cart = customer.getAccount().getCart(); if (cart.getItems().isEmpty()) { System.out.println("Cannot place an order with an empty cart."); return null; } // 1. Process payment boolean paymentSuccess = paymentService.processPayment(paymentStrategy, cart.calculateTotal()); if (!paymentSuccess) { System.out.println("Payment failed. Please try again."); return null; } // 2. Create order and update inventory try { Order order = orderService.createOrder(customer, cart); orders.put(order.getId(), order); // 3. Clear the cart cart.clearCart(); return order; } catch (Exception e) { System.err.println("Order placement failed: " + e.getMessage()); // In a real system, we would trigger a refund here. return null; } } } ================================================ FILE: solutions/java/src/onlineshoppingservice/README.md ================================================ # Online Shopping Service (LLD) ## Problem Statement Design and implement an Online Shopping Service that allows users to browse products, add items to a cart, place orders, make payments, and track order status. --- ## Requirements - **User Management:** Users can register, log in, and manage their profiles. - **Product Catalog:** The system manages a catalog of products with details and prices. - **Cart Management:** Users can add, update, or remove products in their shopping cart. - **Order Placement:** Users can place orders for products in their cart. - **Order Tracking:** The system tracks the status of each order (e.g., PLACED, SHIPPED, DELIVERED, CANCELLED). - **Payment Processing:** Users can pay for their orders using different payment methods. - **Extensibility:** Easy to add new features such as discounts, reviews, or wishlists. --- ## Core Entities - **OnlineShoppingService:** Main class that manages users, products, carts, orders, and payments. - **User:** Represents a user with a unique ID, name, and cart. - **Product:** Represents a product with ID, name, description, and price. - **Cart:** Represents a user's shopping cart containing order items. - **Order:** Represents an order placed by a user, including items, status, and payment. - **OrderItem:** Represents an item in an order or cart. - **OrderStatus:** Enum for order status (PLACED, SHIPPED, DELIVERED, CANCELLED). - **Payment (in payment/):** Represents a payment transaction for an order. - **PaymentProcessor (in payment/):** Handles payment logic and validation. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/OnlineShoppingService-class-diagram.png) ### 1. OnlineShoppingService - **Fields:** List users, List products, List orders, PaymentProcessor paymentProcessor - **Methods:** registerUser(User), addProduct(Product), addToCart(User, Product, int quantity), placeOrder(User), processPayment(Order, Payment), updateOrderStatus(Order, OrderStatus), etc. ### 2. User - **Fields:** int id, String name, Cart cart ### 3. Product - **Fields:** int id, String name, String description, double price ### 4. Cart - **Fields:** List items - **Methods:** addItem(Product, int quantity), removeItem(Product), updateQuantity(Product, int quantity), getItems() ### 5. Order - **Fields:** int id, User user, List items, OrderStatus status, Payment payment ### 6. OrderItem - **Fields:** Product product, int quantity ### 7. OrderStatus (enum) - Values: PLACED, SHIPPED, DELIVERED, CANCELLED ### 8. Payment (in payment/) - **Fields:** int id, double amount, String method, PaymentStatus status ### 9. PaymentProcessor (in payment/) - **Methods:** process(Payment), validate(Payment) --- ## Example Usage ```java OnlineShoppingService service = new OnlineShoppingService(); User alice = new User(1, "Alice"); Product phone = new Product(1, "Smartphone", "Latest model", 699.0); service.registerUser(alice); service.addProduct(phone); service.addToCart(alice, phone, 1); Order order = service.placeOrder(alice); Payment payment = new Payment(1, 699.0, "CREDIT_CARD"); service.processPayment(order, payment); ``` --- ## Demo See `OnlineShoppingServiceDemo.java` for a sample usage and simulation of the online shopping service. --- ## Extending the Framework - **Add discounts or coupons:** Support promotional pricing. - **Add product reviews:** Allow users to review and rate products. - **Add wishlists:** Allow users to save products for later. --- ================================================ FILE: solutions/java/src/onlineshoppingservice/decorator/GiftWrapDecorator.java ================================================ package onlineshoppingservice.decorator; import onlineshoppingservice.models.Product; public class GiftWrapDecorator extends ProductDecorator { private static final double GIFT_WRAP_COST = 5.00; public GiftWrapDecorator(Product product) { super(product); } @Override public double getPrice() { return super.getPrice() + GIFT_WRAP_COST; } @Override public String getDescription() { return super.getDescription() + " (Gift Wrapped)"; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/decorator/ProductDecorator.java ================================================ package onlineshoppingservice.decorator; import onlineshoppingservice.enums.ProductCategory; import onlineshoppingservice.models.Product; public abstract class ProductDecorator extends Product { protected Product decoratedProduct; public ProductDecorator(Product product) { this.decoratedProduct = product; } @Override public String getId() { return decoratedProduct.getId(); } @Override public String getName() { return decoratedProduct.getName(); } @Override public double getPrice() { return decoratedProduct.getPrice(); } @Override public String getDescription() { return decoratedProduct.getDescription(); } @Override public ProductCategory getCategory() { return decoratedProduct.getCategory(); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/enums/OrderStatus.java ================================================ package onlineshoppingservice.enums; public enum OrderStatus { PENDING_PAYMENT, PLACED, SHIPPED, DELIVERED, CANCELLED, RETURNED } ================================================ FILE: solutions/java/src/onlineshoppingservice/enums/ProductCategory.java ================================================ package onlineshoppingservice.enums; public enum ProductCategory { ELECTRONICS, BOOKS, CLOTHING, HOME_GOODS, GROCERY } ================================================ FILE: solutions/java/src/onlineshoppingservice/exceptions/OutOfStockException.java ================================================ package onlineshoppingservice.exceptions; public class OutOfStockException extends RuntimeException { public OutOfStockException(String message) { super(message); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/Account.java ================================================ package onlineshoppingservice.models; public class Account { private final String username; private final String password; // Hashed password in real system private final ShoppingCart cart; public Account(String username, String password) { this.username = username; this.password = password; this.cart = new ShoppingCart(); } public ShoppingCart getCart() { return cart; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/Address.java ================================================ package onlineshoppingservice.models; public class Address { private final String street; private final String city; private final String state; private final String zipCode; public Address(String street, String city, String state, String zipCode) { this.street = street; this.city = city; this.state = state; this.zipCode = zipCode; } @Override public String toString() { return String.format("%s, %s, %s %s", street, city, state, zipCode); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/CartItem.java ================================================ package onlineshoppingservice.models; public class CartItem { private final Product product; private int quantity; public CartItem(Product product, int quantity) { this.product = product; this.quantity = quantity; } public Product getProduct() { return product; } public int getQuantity() { return quantity; } public void incrementQuantity(int amount) { this.quantity += amount; } public double getPrice() { return product.getPrice() * quantity; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/Customer.java ================================================ package onlineshoppingservice.models; import onlineshoppingservice.observer.OrderObserver; import java.util.UUID; public class Customer implements OrderObserver { private final String id; private final String name; private final String email; private final Account account; private Address shippingAddress; public Customer(String name, String email, String password, Address shippingAddress) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; this.account = new Account(email, password); this.shippingAddress = shippingAddress; } @Override public void update(Order order) { System.out.printf("[Notification for %s]: Your order #%s status has been updated to: %s.%n", this.name, order.getId(), order.getStatus()); } public String getId() { return id; } public String getName() { return name; } public Account getAccount() { return account; } public Address getShippingAddress() { return shippingAddress; } public void setShippingAddress(Address address) { this.shippingAddress = address; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/Order.java ================================================ package onlineshoppingservice.models; import onlineshoppingservice.enums.OrderStatus; import onlineshoppingservice.observer.Subject; import onlineshoppingservice.state.OrderState; import onlineshoppingservice.state.PlacedState; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; public class Order extends Subject { private final String id; private final Customer customer; private final List items; private final Address shippingAddress; private final double totalAmount; private final LocalDateTime orderDate; private OrderStatus status; private OrderState currentState; public Order(Customer customer, List items, Address shippingAddress, double totalAmount) { this.id = UUID.randomUUID().toString().substring(0, 8); this.customer = customer; this.items = items; this.shippingAddress = shippingAddress; this.totalAmount = totalAmount; this.orderDate = LocalDateTime.now(); this.status = OrderStatus.PLACED; this.currentState = new PlacedState(); addObserver(customer); } // State Pattern methods public void shipOrder() { currentState.ship(this); } public void deliverOrder() { currentState.deliver(this); } public void cancelOrder() { currentState.cancel(this); } // Getters and Setters public String getId() { return id; } public OrderStatus getStatus() { return status; } public void setState(OrderState state) { this.currentState = state; } public void setStatus(OrderStatus status) { this.status = status; notifyObservers(this); } public List getItems() { return items; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/OrderLineItem.java ================================================ package onlineshoppingservice.models; public class OrderLineItem { private final String productId; private final String productName; private final int quantity; private final double priceAtPurchase; public OrderLineItem(String productId, String productName, int quantity, double priceAtPurchase) { this.productId = productId; this.productName = productName; this.quantity = quantity; this.priceAtPurchase = priceAtPurchase; } public String getProductId() { return productId; } public int getQuantity() { return quantity; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/Product.java ================================================ package onlineshoppingservice.models; import onlineshoppingservice.enums.ProductCategory; import java.util.UUID; public abstract class Product { protected String id; protected String name; protected String description; protected double price; protected ProductCategory category; public abstract String getId(); public abstract String getName(); public abstract String getDescription(); public abstract double getPrice(); public abstract ProductCategory getCategory(); // Base implementation for the Builder public static class BaseProduct extends Product { private BaseProduct(String id, String name, String description, double price, ProductCategory category) { this.id = id; this.name = name; this.description = description; this.price = price; this.category = category; } @Override public String getId() { return id; } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public double getPrice() { return price; } @Override public ProductCategory getCategory() { return category; } } // Builder Pattern for creating products public static class Builder { private final String name; private final double price; private String description = ""; private ProductCategory category; public Builder(String name, double price) { this.name = name; this.price = price; } public Builder withDescription(String description) { this.description = description; return this; } public Builder withCategory(ProductCategory category) { this.category = category; return this; } public Product build() { return new BaseProduct(UUID.randomUUID().toString(), name, description, price, category); } } } ================================================ FILE: solutions/java/src/onlineshoppingservice/models/ShoppingCart.java ================================================ package onlineshoppingservice.models; import java.util.HashMap; import java.util.Map; public class ShoppingCart { private final Map items = new HashMap<>(); public void addItem(Product product, int quantity) { if (items.containsKey(product.getId())) { items.get(product.getId()).incrementQuantity(quantity); } else { items.put(product.getId(), new CartItem(product, quantity)); } } public void removeItem(String productId) { items.remove(productId); } public Map getItems() { return Map.copyOf(items); } public double calculateTotal() { return items.values().stream().mapToDouble(CartItem::getPrice).sum(); } public void clearCart() { items.clear(); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/observer/OrderObserver.java ================================================ package onlineshoppingservice.observer; import onlineshoppingservice.models.Order; public interface OrderObserver { void update(Order order); } ================================================ FILE: solutions/java/src/onlineshoppingservice/observer/Subject.java ================================================ package onlineshoppingservice.observer; import onlineshoppingservice.models.Order; import java.util.ArrayList; import java.util.List; public abstract class Subject { private final List observers = new ArrayList<>(); public void addObserver(OrderObserver observer) { observers.add(observer); } public void removeObserver(OrderObserver observer) { observers.remove(observer); } public void notifyObservers(Order order) { for (OrderObserver observer : observers) { observer.update(order); } } } ================================================ FILE: solutions/java/src/onlineshoppingservice/services/InventoryService.java ================================================ package onlineshoppingservice.services; import onlineshoppingservice.exceptions.OutOfStockException; import onlineshoppingservice.models.OrderLineItem; import onlineshoppingservice.models.Product; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class InventoryService { private final Map stock; // productId -> quantity public InventoryService() { this.stock = new ConcurrentHashMap<>(); } public void addStock(Product product, int quantity) { stock.put(product.getId(), stock.getOrDefault(product.getId(), 0) + quantity); } public synchronized void updateStockForOrder(List items) { // First, check if all items are in stock for (OrderLineItem item : items) { if (stock.getOrDefault(item.getProductId(), 0) < item.getQuantity()) { throw new OutOfStockException("Not enough stock for product ID: " + item.getProductId()); } } // If all checks pass, deduct the stock for (OrderLineItem item : items) { stock.compute(item.getProductId(), (id, currentStock) -> currentStock - item.getQuantity()); } } } ================================================ FILE: solutions/java/src/onlineshoppingservice/services/OrderService.java ================================================ package onlineshoppingservice.services; import onlineshoppingservice.models.Customer; import onlineshoppingservice.models.Order; import onlineshoppingservice.models.OrderLineItem; import onlineshoppingservice.models.ShoppingCart; import java.util.ArrayList; import java.util.List; public class OrderService { private final InventoryService inventoryService; public OrderService(InventoryService inventoryService) { this.inventoryService = inventoryService; } public Order createOrder(Customer customer, ShoppingCart cart) { List result = new ArrayList<>(); cart.getItems().values().stream() .map(cartItem -> new OrderLineItem( cartItem.getProduct().getId(), cartItem.getProduct().getName(), cartItem.getQuantity(), cartItem.getProduct().getPrice())) .forEach(result::add); inventoryService.updateStockForOrder(result); return new Order(customer, result, customer.getShippingAddress(), cart.calculateTotal()); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/services/PaymentService.java ================================================ package onlineshoppingservice.services; import onlineshoppingservice.strategy.PaymentStrategy; public class PaymentService { public boolean processPayment(PaymentStrategy strategy, double amount) { return strategy.pay(amount); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/services/SearchService.java ================================================ package onlineshoppingservice.services; import onlineshoppingservice.enums.ProductCategory; import onlineshoppingservice.models.Product; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class SearchService { private final Collection productCatalog; public SearchService(Collection productCatalog) { this.productCatalog = productCatalog; } public List searchByName(String name) { List result = new ArrayList<>(); productCatalog.stream() .filter(p -> p.getName().toLowerCase().contains(name.toLowerCase())) .forEach(result::add); return result; } public List searchByCategory(ProductCategory category) { List result = new ArrayList<>(); productCatalog.stream() .filter(p -> p.getCategory() == category) .forEach(result::add); return result; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/state/CancelledState.java ================================================ package onlineshoppingservice.state; import onlineshoppingservice.models.Order; public class CancelledState implements OrderState { @Override public void ship(Order order) { System.out.println("Cannot ship a cancelled order."); } @Override public void deliver(Order order) { System.out.println("Cannot deliver a cancelled order."); } @Override public void cancel(Order order) { System.out.println("Order is already cancelled."); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/state/DeliveredState.java ================================================ package onlineshoppingservice.state; import onlineshoppingservice.models.Order; public class DeliveredState implements OrderState { @Override public void ship(Order order) { System.out.println("Order already delivered."); } @Override public void deliver(Order order) { System.out.println("Order already delivered."); } @Override public void cancel(Order order) { System.out.println("Cannot cancel a delivered order."); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/state/OrderState.java ================================================ package onlineshoppingservice.state; import onlineshoppingservice.models.Order; public interface OrderState { void ship(Order order); void deliver(Order order); void cancel(Order order); } ================================================ FILE: solutions/java/src/onlineshoppingservice/state/PlacedState.java ================================================ package onlineshoppingservice.state; import onlineshoppingservice.enums.OrderStatus; import onlineshoppingservice.models.Order; public class PlacedState implements OrderState { @Override public void ship(Order order) { System.out.println("Shipping order " + order.getId()); order.setStatus(OrderStatus.SHIPPED); order.setState(new ShippedState()); } @Override public void deliver(Order order) { System.out.println("Cannot deliver an order that has not been shipped."); } @Override public void cancel(Order order) { System.out.println("Cancelling order " + order.getId()); order.setStatus(OrderStatus.CANCELLED); order.setState(new CancelledState()); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/state/ShippedState.java ================================================ package onlineshoppingservice.state; import onlineshoppingservice.enums.OrderStatus; import onlineshoppingservice.models.Order; public class ShippedState implements OrderState { @Override public void ship(Order order) { System.out.println("Order is already shipped."); } @Override public void deliver(Order order) { System.out.println("Delivering order " + order.getId()); order.setStatus(OrderStatus.DELIVERED); order.setState(new DeliveredState()); } @Override public void cancel(Order order) { System.out.println("Cannot cancel a shipped order."); } } ================================================ FILE: solutions/java/src/onlineshoppingservice/strategy/CreditCardPaymentStrategy.java ================================================ package onlineshoppingservice.strategy; public class CreditCardPaymentStrategy implements PaymentStrategy { private final String cardNumber; public CreditCardPaymentStrategy(String cardNumber) { this.cardNumber = cardNumber; } @Override public boolean pay(double amount) { System.out.printf("Processing credit card payment of $%.2f with card %s.%n", amount, cardNumber); // Simulate payment gateway logic return true; } } ================================================ FILE: solutions/java/src/onlineshoppingservice/strategy/PaymentStrategy.java ================================================ package onlineshoppingservice.strategy; public interface PaymentStrategy { boolean pay(double amount); } ================================================ FILE: solutions/java/src/onlineshoppingservice/strategy/UPIPaymentStrategy.java ================================================ package onlineshoppingservice.strategy; public class UPIPaymentStrategy implements PaymentStrategy{ private final String upiId; public UPIPaymentStrategy(String upiId) { this.upiId = upiId; } @Override public boolean pay(double amount) { System.out.printf("Processing UPI payment of $%.2f with upi id %s.%n", amount, upiId); // Simulate payment gateway logic return true; } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/BuyOrder.java ================================================ package onlinestockbrokeragesystem; public class BuyOrder extends Order { public BuyOrder(String orderId, Account account, Stock stock, int quantity, double price) { super(orderId, account, stock, quantity, price); } @Override public void execute() { double totalCost = quantity * price; if (account.getBalance() >= totalCost) { account.withdraw(totalCost); // Update portfolio and perform necessary actions account.getPortfolio().addStock(stock, quantity); status = OrderStatus.EXECUTED; } else { status = OrderStatus.REJECTED; throw new InsufficientFundsException("Insufficient funds to execute the buy order."); } } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/README.md ================================================ # Online Stock Brokerage System (LLD) ## Problem Statement Design and implement an Online Stock Brokerage System that allows users to buy and sell stocks, manage their portfolio, and track their investments. The system should handle order processing, account management, and stock trading. --- ## Requirements 1. **Account Management:** - Create and manage user accounts - Track account balance - Handle fund deposits and withdrawals 2. **Stock Management:** - Track available stocks - Maintain stock prices - Handle stock information 3. **Order Management:** - Process buy and sell orders - Track order status - Handle order execution 4. **Portfolio Management:** - Track user's stock holdings - Calculate portfolio value - Monitor investment performance 5. **Trading Rules:** - Validate order amounts - Check sufficient funds - Verify stock availability --- ## Core Entities ### 1. StockBroker - **Fields:** List accounts, List stocks, List orders - **Methods:** - createAccount() - placeBuyOrder() - placeSellOrder() - getPortfolio() - getStockPrice() ### 2. Account - **Fields:** String id, User user, double balance, Portfolio portfolio - **Methods:** - deposit() - withdraw() - getBalance() - getPortfolio() ### 3. User - **Fields:** String id, String name, String email - **Methods:** - getAccount() - updateProfile() ### 4. Stock - **Fields:** String symbol, String name, double currentPrice - **Methods:** - updatePrice() - getPrice() ### 5. Order - **Fields:** String id, Account account, Stock stock, int quantity, OrderStatus status - **Methods:** - execute() - cancel() - getStatus() ### 6. BuyOrder - **Fields:** double price - **Methods:** - validateFunds() - execute() ### 7. SellOrder - **Fields:** double price - **Methods:** - validateStocks() - execute() ### 8. Portfolio - **Fields:** Map holdings - **Methods:** - addStock() - removeStock() - getValue() ### 9. OrderStatus (Enum) - **Values:** PENDING, EXECUTED, CANCELLED, FAILED ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/onlineStockBrokerageSystem-class-diagram.png) --- ## Example Usage ```java StockBroker pubSubService = new StockBroker(); // Create a user account User user = new User("John Doe", "john@example.com"); Account account = pubSubService.createAccount(user); // Deposit funds account.deposit(10000.0); // Place a buy order Stock stock = pubSubService.getStock("AAPL"); BuyOrder buyOrder = pubSubService.placeBuyOrder(account, stock, 10); // Place a sell order SellOrder sellOrder = pubSubService.placeSellOrder(account, stock, 5); // Get portfolio Portfolio portfolio = account.getPortfolio(); ``` --- ## Demo See `StockBrokerageSystemDemo.java` for a sample usage and simulation of the stock brokerage system. --- ## Extending the Framework - **Add real-time market data:** Integrate with market data providers - **Add order types:** Support limit orders, stop-loss orders - **Add trading strategies:** Implement automated trading strategies - **Add transaction history:** Track all trading activities - **Add reporting system:** Generate investment reports - **Add notification system:** Send price alerts and order updates --- ## Design Patterns Used - **Singleton Pattern:** For the stock pubSubService instance - **Factory Pattern:** For creating different types of orders - **Observer Pattern:** For stock price updates - **Strategy Pattern:** For different order execution strategies --- ## Exception Handling - **InsufficientFundsException:** Thrown when account has insufficient funds - **InsufficientStockException:** Thrown when portfolio has insufficient stocks - **InvalidOrderException:** Thrown when order details are invalid - **OrderExecutionException:** Thrown when order execution fails --- ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/SellOrder.java ================================================ package onlinestockbrokeragesystem; public class SellOrder extends Order { public SellOrder(String orderId, Account account, Stock stock, int quantity, double price) { super(orderId, account, stock, quantity, price); } @Override public void execute() { // Check if the user has sufficient quantity of the stock to sell // Update portfolio and perform necessary actions double totalProceeds = quantity * price; account.deposit(totalProceeds); status = OrderStatus.EXECUTED; } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/StockBrokerageSystem.java ================================================ package onlinestockbrokeragesystem; import onlinestockbrokeragesystem.command.BuyStockCommand; import onlinestockbrokeragesystem.command.OrderCommand; import onlinestockbrokeragesystem.command.SellStockCommand; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.entities.Stock; import onlinestockbrokeragesystem.entities.User; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class StockBrokerageSystem { private static volatile StockBrokerageSystem instance; private final Map users; private final Map stocks; private StockBrokerageSystem() { this.users = new ConcurrentHashMap<>(); this.stocks = new ConcurrentHashMap<>(); } public static StockBrokerageSystem getInstance() { if (instance == null) { synchronized (StockBrokerageSystem.class) { if (instance == null) { instance = new StockBrokerageSystem(); } } } return instance; } public User registerUser(String name, double initialAmount) { User user = new User(name, initialAmount); users.put(user.getUserId(), user); return user; } public Stock addStock(String symbol, double initialPrice) { Stock stock = new Stock(symbol, initialPrice); stocks.put(stock.getSymbol(), stock); return stock; } public void placeBuyOrder(Order order) { User user = order.getUser(); OrderCommand command = new BuyStockCommand(user.getAccount(), order); command.execute(); } public void placeSellOrder(Order order) { User user = order.getUser(); OrderCommand command = new SellStockCommand(user.getAccount(), order); command.execute(); } public void cancelOrder(Order order) { order.cancel(); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/StockBrokerageSystemDemo.java ================================================ package onlinestockbrokeragesystem; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.entities.OrderBuilder; import onlinestockbrokeragesystem.entities.Stock; import onlinestockbrokeragesystem.entities.User; public class StockBrokerageSystemDemo { public static void main(String[] args) throws InterruptedException { // --- System Setup --- StockBrokerageSystem system = StockBrokerageSystem.getInstance(); // --- Create Stocks --- Stock apple = system.addStock("AAPL", 150.00); Stock google = system.addStock("GOOG", 2800.00); // --- Create Members (Users) --- User alice = system.registerUser("Alice", 20000.00); User bob = system.registerUser("Bob", 25000.00); // Bob already owns some Apple stock bob.getAccount().addStock("AAPL", 50); // --- Members subscribe to stock notifications (Observer Pattern) --- apple.addObserver(alice); google.addObserver(alice); apple.addObserver(bob); System.out.println("--- Initial State ---"); printAccountStatus(alice); printAccountStatus(bob); System.out.println("\n--- Trading Simulation Starts ---\n"); // --- SCENARIO 1: Limit Order Match --- System.out.println("--- SCENARIO 1: Alice places a limit buy, Bob places a limit sell that matches ---"); // Alice wants to buy 10 shares of AAPL if the price is $150.50 or less Order aliceBuyOrder = new OrderBuilder() .forUser(alice) .buy(10) .withStock(apple) .withLimit(150.50) .build(); system.placeBuyOrder(aliceBuyOrder); // Bob wants to sell 20 of his shares if the price is $150.50 or more Order bobSellOrder = new OrderBuilder() .forUser(bob) .sell(20) .withStock(apple) .withLimit(150.50) .build(); system.placeSellOrder(bobSellOrder); // The exchange will automatically match and execute this trade. // Let's check the status after the trade. Thread.sleep(100); // Give time for notifications to print System.out.println("\n--- Account Status After Trade 1 ---"); printAccountStatus(alice); printAccountStatus(bob); // --- SCENARIO 2: Price Update triggers notifications --- System.out.println("\n--- SCENARIO 2: Market price of GOOG changes ---"); google.setPrice(2850.00); // Alice will get a notification // --- SCENARIO 3: Order Cancellation (State Pattern) --- System.out.println("\n--- SCENARIO 3: Alice places an order and then cancels it ---"); Order aliceCancelOrder = new OrderBuilder() .forUser(alice) .buy(5) .withStock(google) .withLimit(2700.00) // Price is too low, so it won't execute immediately .build(); system.placeBuyOrder(aliceCancelOrder); System.out.println("Order status before cancellation: " + aliceCancelOrder.getStatus()); system.cancelOrder(aliceCancelOrder); System.out.println("Order status after cancellation attempt: " + aliceCancelOrder.getStatus()); // Now try to cancel an already filled order System.out.println("\n--- Trying to cancel an already FILLED order (State Pattern) ---"); System.out.println("Bob's sell order status: " + bobSellOrder.getStatus()); system.cancelOrder(bobSellOrder); // This should fail System.out.println("Bob's sell order status after cancel attempt: " + bobSellOrder.getStatus()); } private static void printAccountStatus(User user) { System.out.printf("Member: %s, Cash: $%.2f, Portfolio: %s%n", user.getName(), user.getAccount().getBalance(), user.getAccount().getPortfolio()); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/StockExchange.java ================================================ package onlinestockbrokeragesystem; import onlinestockbrokeragesystem.enums.OrderStatus; import onlinestockbrokeragesystem.enums.OrderType; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.entities.Stock; import onlinestockbrokeragesystem.entities.User; import onlinestockbrokeragesystem.state.FilledState; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class StockExchange { private static volatile StockExchange instance; private final Map> buyOrders; private final Map> sellOrders; private StockExchange() { this.buyOrders = new ConcurrentHashMap<>(); this.sellOrders = new ConcurrentHashMap<>(); } public static StockExchange getInstance() { if (instance == null) { synchronized (StockExchange.class) { if (instance == null) { instance = new StockExchange(); } } } return instance; } public void placeBuyOrder(Order order) { buyOrders.computeIfAbsent(order.getStock().getSymbol(), k -> new CopyOnWriteArrayList<>()).add(order); matchOrders(order.getStock()); } public void placeSellOrder(Order order) { sellOrders.computeIfAbsent(order.getStock().getSymbol(), k -> new CopyOnWriteArrayList<>()).add(order); matchOrders(order.getStock()); } private void matchOrders(Stock stock) { synchronized (this) { // Critical section to prevent race conditions during matching List buys = buyOrders.get(stock.getSymbol()); List sells = sellOrders.get(stock.getSymbol()); if (buys == null || sells == null) return; boolean matchFound; do { matchFound = false; Order bestBuy = findBestBuy(buys); Order bestSell = findBestSell(sells); if (bestBuy != null && bestSell != null) { double buyPrice = bestBuy.getType() == OrderType.MARKET ? stock.getPrice() : bestBuy.getPrice(); double sellPrice = bestSell.getType() == OrderType.MARKET ? stock.getPrice() : bestSell.getPrice(); if (buyPrice >= sellPrice) { executeTrade(bestBuy, bestSell, sellPrice); // Trade at the seller's asking price matchFound = true; } } } while (matchFound); } } private void executeTrade(Order buyOrder, Order sellOrder, double tradePrice) { System.out.printf("--- Executing Trade for %s at $%.2f ---%n", buyOrder.getStock(), tradePrice); User buyer = buyOrder.getUser(); User seller = sellOrder.getUser(); int tradeQuantity = Math.min(buyOrder.getQuantity(), sellOrder.getQuantity()); double totalCost = tradeQuantity * tradePrice; // Perform transaction buyer.getAccount().debit(totalCost); buyer.getAccount().addStock(buyOrder.getStock().getSymbol(), tradeQuantity); seller.getAccount().credit(totalCost); seller.getAccount().removeStock(sellOrder.getStock().getSymbol(), tradeQuantity); // Update orders updateOrderStatus(buyOrder, tradeQuantity); updateOrderStatus(sellOrder, tradeQuantity); // Update stock's market price to last traded price buyOrder.getStock().setPrice(tradePrice); System.out.println("--- Trade Complete ---"); } private void updateOrderStatus(Order order, int quantityTraded) { // This is a simplified update logic. A real system would handle partial fills. order.setStatus(OrderStatus.FILLED); order.setState(new FilledState()); String stockSymbol = order.getStock().getSymbol(); // Remove from books if (buyOrders.get(stockSymbol) != null) buyOrders.get(stockSymbol).remove(order); if (sellOrders.get(stockSymbol) != null) sellOrders.get(stockSymbol).remove(order); } private Order findBestBuy(List buys) { return buys.stream() .filter(o -> o.getStatus() == OrderStatus.OPEN) .max(Comparator.comparingDouble(Order::getPrice)) // Highest limit price is best .orElse(null); } private Order findBestSell(List sells) { return sells.stream() .filter(o -> o.getStatus() == OrderStatus.OPEN) .min(Comparator.comparingDouble(Order::getPrice)) // Lowest limit price is best .orElse(null); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/command/BuyStockCommand.java ================================================ package onlinestockbrokeragesystem.command; import onlinestockbrokeragesystem.StockExchange; import onlinestockbrokeragesystem.entities.Account; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.enums.OrderType; import onlinestockbrokeragesystem.exceptions.InsufficientFundsException; public class BuyStockCommand implements OrderCommand { private final Account account; private final Order order; private final StockExchange stockExchange; public BuyStockCommand(Account account, Order order) { this.account = account; this.order = order; this.stockExchange = StockExchange.getInstance(); } @Override public void execute() { // For market order, we can't pre-check funds perfectly. // For limit order, we can pre-authorize the amount. double estimatedCost = order.getQuantity() * order.getPrice(); if (order.getType() == OrderType.LIMIT && account.getBalance() < estimatedCost) { throw new InsufficientFundsException("Not enough cash to place limit buy order."); } System.out.printf("Placing BUY order %s for %d shares of %s.%n", order.getOrderId(), order.getQuantity(), order.getStock()); stockExchange.placeBuyOrder(order); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/command/OrderCommand.java ================================================ package onlinestockbrokeragesystem.command; public interface OrderCommand { void execute(); } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/command/SellStockCommand.java ================================================ package onlinestockbrokeragesystem.command; import onlinestockbrokeragesystem.StockExchange; import onlinestockbrokeragesystem.entities.Account; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.exceptions.InsufficientStockException; public class SellStockCommand implements OrderCommand { private final Account account; private final Order order; private final StockExchange stockExchange; public SellStockCommand(Account account, Order order) { this.account = account; this.order = order; this.stockExchange = StockExchange.getInstance(); } @Override public void execute() { if (account.getStockQuantity(order.getStock().getSymbol()) < order.getQuantity()) { throw new InsufficientStockException("Not enough stock to place sell order."); } System.out.printf("Placing SELL order %s for %d shares of %s.%n", order.getOrderId(), order.getQuantity(), order.getStock()); stockExchange.placeSellOrder(order); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/entities/Account.java ================================================ package onlinestockbrokeragesystem.entities; import onlinestockbrokeragesystem.exceptions.InsufficientFundsException; import onlinestockbrokeragesystem.exceptions.InsufficientStockException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Account { private double balance; private final Map portfolio; // Stock symbol -> quantity public Account(double initialCash) { this.balance = initialCash; this.portfolio = new ConcurrentHashMap<>(); } public synchronized void debit(double amount) { if (balance < amount) { throw new InsufficientFundsException("Insufficient funds to debit " + amount); } balance -= amount; } public synchronized void credit(double amount) { balance += amount; } public synchronized void addStock(String symbol, int quantity) { portfolio.put(symbol, portfolio.getOrDefault(symbol, 0) + quantity); } public synchronized void removeStock(String symbol, int quantity) { int currentQuantity = portfolio.getOrDefault(symbol, 0); if (currentQuantity < quantity) { throw new InsufficientStockException("Not enough " + symbol + " stock to sell."); } portfolio.put(symbol, currentQuantity - quantity); } public double getBalance() { return balance; } public Map getPortfolio() { return Map.copyOf(portfolio); } public int getStockQuantity(String symbol) { return portfolio.getOrDefault(symbol, 0); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/entities/Order.java ================================================ package onlinestockbrokeragesystem.entities; import onlinestockbrokeragesystem.enums.OrderStatus; import onlinestockbrokeragesystem.enums.OrderType; import onlinestockbrokeragesystem.state.OpenState; import onlinestockbrokeragesystem.state.OrderState; import onlinestockbrokeragesystem.strategy.ExecutionStrategy; public class Order { private final String orderId; private final User user; private final Stock stock; private final OrderType type; private final int quantity; private final double price; // Limit price for Limit orders private OrderStatus status; private User owner; private OrderState currentState; private final ExecutionStrategy executionStrategy; public Order(String orderId, User user, Stock stock, OrderType type, int quantity, double price, ExecutionStrategy strategy, User owner) { this.orderId = orderId; this.user = user; this.stock = stock; this.type = type; this.quantity = quantity; this.price = price; this.executionStrategy = strategy; this.owner = owner; this.currentState = new OpenState(); // Initial state this.status = OrderStatus.OPEN; } // State pattern methods public void cancel() { currentState.cancel(this); } // Getters public String getOrderId() { return orderId; } public User getUser() { return user; } public Stock getStock() { return stock; } public OrderType getType() { return type; } public int getQuantity() { return quantity; } public double getPrice() { return price; } public OrderStatus getStatus() { return status; } public ExecutionStrategy getExecutionStrategy() { return executionStrategy; } // Setters for state transitions public void setState(OrderState state) { this.currentState = state; } public void setStatus(OrderStatus status) { this.status = status; notifyOwner(); } private void notifyOwner() { if (owner != null) { owner.orderStatusUpdate(this); } } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/entities/OrderBuilder.java ================================================ package onlinestockbrokeragesystem.entities; import onlinestockbrokeragesystem.enums.OrderType; import onlinestockbrokeragesystem.enums.TransactionType; import onlinestockbrokeragesystem.strategy.LimitOrderStrategy; import onlinestockbrokeragesystem.strategy.MarketOrderStrategy; import java.util.UUID; public class OrderBuilder { private User user; private Stock stock; private OrderType type; private TransactionType transactionType; private int quantity; private double price; public OrderBuilder forUser(User user) { this.user = user; return this; } public OrderBuilder withStock(Stock stock) { this.stock = stock; return this; } public OrderBuilder buy(int quantity) { this.transactionType = TransactionType.BUY; this.quantity = quantity; return this; } public OrderBuilder sell(int quantity) { this.transactionType = TransactionType.SELL; this.quantity = quantity; return this; } public OrderBuilder atMarketPrice() { this.type = OrderType.MARKET; this.price = 0; // Not needed for market order return this; } public OrderBuilder withLimit(double limitPrice) { this.type = OrderType.LIMIT; this.price = limitPrice; return this; } public Order build() { return new Order( UUID.randomUUID().toString(), user, stock, type, quantity, price, type == OrderType.MARKET ? new MarketOrderStrategy() : new LimitOrderStrategy(transactionType), user ); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/entities/Stock.java ================================================ package onlinestockbrokeragesystem.entities; import onlinestockbrokeragesystem.observer.StockObserver; import java.util.ArrayList; import java.util.List; public class Stock { private final String symbol; private double price; private final List observers = new ArrayList<>(); public Stock(String symbol, double initialPrice) { this.symbol = symbol; this.price = initialPrice; } public String getSymbol() { return symbol; } public double getPrice() { return price; } public void setPrice(double newPrice) { if (this.price != newPrice) { this.price = newPrice; notifyObservers(); } } public void addObserver(StockObserver observer) { observers.add(observer); } public void removeObserver(StockObserver observer) { observers.remove(observer); } private void notifyObservers() { for (StockObserver observer : observers) { observer.update(this); } } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/entities/User.java ================================================ package onlinestockbrokeragesystem.entities; import onlinestockbrokeragesystem.observer.StockObserver; import java.util.UUID; public class User implements StockObserver { private final String userId; private final String name; private final Account account; public User(String name, double initialCash) { this.userId = UUID.randomUUID().toString(); this.name = name; this.account = new Account(initialCash); } public String getUserId() { return userId; } public String getName() { return name; } public Account getAccount() { return account; } @Override public void update(Stock stock) { System.out.printf("[Notification for %s] Stock %s price updated to: $%.2f%n", name, stock.getSymbol(), stock.getPrice()); } public void orderStatusUpdate(Order order) { System.out.printf("[Order Notification for %s] Order %s for %s is now %s.%n", name, order.getOrderId(), order.getStock(), order.getStatus()); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/enums/OrderStatus.java ================================================ package onlinestockbrokeragesystem.enums; public enum OrderStatus { OPEN, PARTIALLY_FILLED, FILLED, CANCELLED, FAILED } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/enums/OrderType.java ================================================ package onlinestockbrokeragesystem.enums; public enum OrderType { MARKET, LIMIT } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/enums/TransactionType.java ================================================ package onlinestockbrokeragesystem.enums; public enum TransactionType { BUY, SELL } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/exceptions/InsufficientFundsException.java ================================================ package onlinestockbrokeragesystem.exceptions; public class InsufficientFundsException extends RuntimeException { public InsufficientFundsException(String message) { super(message); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/exceptions/InsufficientStockException.java ================================================ package onlinestockbrokeragesystem.exceptions; public class InsufficientStockException extends RuntimeException { public InsufficientStockException(String message) { super(message); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/observer/StockObserver.java ================================================ package onlinestockbrokeragesystem.observer; import onlinestockbrokeragesystem.entities.Stock; public interface StockObserver { void update(Stock stock); } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/state/CancelledState.java ================================================ package onlinestockbrokeragesystem.state; import onlinestockbrokeragesystem.entities.Order; public class CancelledState implements OrderState { @Override public void handle(Order order) { System.out.println("Order is cancelled."); } @Override public void cancel(Order order) { System.out.println("Order is already cancelled."); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/state/FilledState.java ================================================ package onlinestockbrokeragesystem.state; import onlinestockbrokeragesystem.entities.Order; public class FilledState implements OrderState { @Override public void handle(Order order) { System.out.println("Order is already filled."); } @Override public void cancel(Order order) { System.out.println("Cannot cancel a filled order."); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/state/OpenState.java ================================================ package onlinestockbrokeragesystem.state; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.enums.OrderStatus; public class OpenState implements OrderState { @Override public void handle(Order order) { System.out.println("Order is open and waiting for execution."); } @Override public void cancel(Order order) { order.setStatus(OrderStatus.CANCELLED); order.setState(new CancelledState()); System.out.println("Order " + order.getOrderId() + " has been cancelled."); } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/state/OrderState.java ================================================ package onlinestockbrokeragesystem.state; import onlinestockbrokeragesystem.entities.Order; public interface OrderState { void handle(Order order); void cancel(Order order); } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/strategy/ExecutionStrategy.java ================================================ package onlinestockbrokeragesystem.strategy; import onlinestockbrokeragesystem.entities.Order; public interface ExecutionStrategy { boolean canExecute(Order order, double marketPrice); } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/strategy/LimitOrderStrategy.java ================================================ package onlinestockbrokeragesystem.strategy; import onlinestockbrokeragesystem.entities.Order; import onlinestockbrokeragesystem.enums.TransactionType; public class LimitOrderStrategy implements ExecutionStrategy { private final TransactionType type; public LimitOrderStrategy(TransactionType type) { this.type = type; } @Override public boolean canExecute(Order order, double marketPrice) { if (type == TransactionType.BUY) { // Buy if market price is less than or equal to limit price return marketPrice <= order.getPrice(); } else { // SELL // Sell if market price is greater than or equal to limit price return marketPrice >= order.getPrice(); } } } ================================================ FILE: solutions/java/src/onlinestockbrokeragesystem/strategy/MarketOrderStrategy.java ================================================ package onlinestockbrokeragesystem.strategy; import onlinestockbrokeragesystem.entities.Order; public class MarketOrderStrategy implements ExecutionStrategy { @Override public boolean canExecute(Order order, double marketPrice) { return true; // Market orders can always execute } } ================================================ FILE: solutions/java/src/parkinglot/ParkingLot.java ================================================ package parkinglot; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.entities.ParkingTicket; import parkinglot.strategy.fee.FeeStrategy; import parkinglot.strategy.fee.FlatRateFeeStrategy; import parkinglot.strategy.parking.BestFitStrategy; import parkinglot.strategy.parking.ParkingStrategy; import parkinglot.vehicle.Vehicle; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class ParkingLot { private static ParkingLot instance; private final List floors = new ArrayList<>(); private final Map activeTickets; private FeeStrategy feeStrategy; private ParkingStrategy parkingStrategy; private ParkingLot() { this.feeStrategy = new FlatRateFeeStrategy(); this.parkingStrategy = new BestFitStrategy(); this.activeTickets = new ConcurrentHashMap<>(); } public static synchronized ParkingLot getInstance() { if (instance == null) { instance = new ParkingLot(); } return instance; } public void addFloor(ParkingFloor floor) { floors.add(floor); } public void setFeeStrategy (FeeStrategy feeStrategy) { this.feeStrategy = feeStrategy; } public void setParkingStrategy(ParkingStrategy parkingStrategy) { this.parkingStrategy = parkingStrategy; } public Optional parkVehicle(Vehicle vehicle) { Optional availableSpot = parkingStrategy.findSpot(floors, vehicle); if (availableSpot.isPresent()) { ParkingSpot spot = availableSpot.get(); spot.parkVehicle(vehicle); ParkingTicket ticket = new ParkingTicket(vehicle, spot); activeTickets.put(vehicle.getLicenseNumber(), ticket); System.out.printf("%s parked at %s. Ticket: %s\n", vehicle.getLicenseNumber(), spot.getSpotId(), ticket.getTicketId()); return Optional.of(ticket); } System.out.println("No available spot for " + vehicle.getLicenseNumber()); return Optional.empty(); } public Optional unparkVehicle(String licenseNumber) { ParkingTicket ticket = activeTickets.remove(licenseNumber); if (ticket == null) { System.out.println("Ticket not found"); return Optional.empty(); } ticket.setExitTimestamp(); ticket.getSpot().unparkVehicle(); Double parkingFee = feeStrategy.calculateFee(ticket); return Optional.of(parkingFee); } } ================================================ FILE: solutions/java/src/parkinglot/ParkingLotDemo.java ================================================ package parkinglot; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.entities.ParkingTicket; import parkinglot.strategy.fee.VehicleBasedFeeStrategy; import parkinglot.vehicle.*; import java.util.Optional; public class ParkingLotDemo { public static void main(String[] args) { ParkingLot parkingLot = ParkingLot.getInstance(); // 1. Initialize the parking lot with floors and spots ParkingFloor floor1 = new ParkingFloor(1); floor1.addSpot(new ParkingSpot("F1-S1", VehicleSize.SMALL)); floor1.addSpot(new ParkingSpot("F1-M1", VehicleSize.MEDIUM)); floor1.addSpot(new ParkingSpot("F1-L1", VehicleSize.LARGE)); ParkingFloor floor2 = new ParkingFloor(2); floor2.addSpot(new ParkingSpot("F2-M1", VehicleSize.MEDIUM)); floor2.addSpot(new ParkingSpot("F2-M2", VehicleSize.MEDIUM)); parkingLot.addFloor(floor1); parkingLot.addFloor(floor2); parkingLot.setFeeStrategy(new VehicleBasedFeeStrategy()); // 2. Simulate vehicle entries System.out.println("\n--- Vehicle Entries ---"); floor1.displayAvailability(); floor2.displayAvailability(); Vehicle bike = new Bike("B-123"); Vehicle car = new Car("C-456"); Vehicle truck = new Truck("T-789"); Optional bikeTicketOpt = parkingLot.parkVehicle(bike); Optional carTicketOpt = parkingLot.parkVehicle(car); Optional truckTicketOpt = parkingLot.parkVehicle(truck); System.out.println("\n--- Availability after parking ---"); floor1.displayAvailability(); floor2.displayAvailability(); // 3. Simulate another car entry (should go to floor 2) Vehicle car2 = new Car("C-999"); Optional car2TicketOpt = parkingLot.parkVehicle(car2); // 4. Simulate a vehicle entry that fails (no available spots) Vehicle bike2 = new Bike("B-000"); Optional failedBikeTicketOpt = parkingLot.parkVehicle(bike2); // 5. Simulate vehicle exits and fee calculation System.out.println("\n--- Vehicle Exits ---"); if (carTicketOpt.isPresent()) { Optional feeOpt = parkingLot.unparkVehicle(car.getLicenseNumber()); feeOpt.ifPresent(fee -> System.out.printf("Car C-456 unparked. Fee: $%.2f\n", fee)); } System.out.println("\n--- Availability after one car leaves ---"); floor1.displayAvailability(); floor2.displayAvailability(); } } ================================================ FILE: solutions/java/src/parkinglot/README.md ================================================ # Parking Lot System (LLD) ## Problem Statement Design and implement a Parking Lot Management System that supports parking and unparking of vehicles, parkingTicket generation, fee calculation, and management of multiple floors and spot types. --- ## Requirements - **Multiple Floors:** The parking lot can have multiple floors. - **Parking Spots:** Each floor has multiple parking spots of different types (e.g., car, bike, truck). - **Vehicle Types:** Support for different vehicle types (see `vehicletype/`). - **Ticketing:** Generate a parkingTicket when a vehicle is parked. - **Unparking:** Allow vehicles to unpark and calculate the parking fee. - **Fee Calculation:** Support for different fee strategies (see `fee/`). - **Spot Allocation:** Allocate the nearest available spot of the correct type. - **Extensibility:** Easy to add new vehicle types, spot types, or fee strategies. --- ## Core Entities - **ParkingLot:** Main class managing the entire parking lot, floors, and overall operations. - **ParkingFloor:** Represents a single floor in the parking lot, manages its spots. - **ParkingSpot:** Represents an individual parking spot, knows its type and occupancy. - **Ticket:** Represents a parking parkingTicket issued when a vehicle is parked. - **VehicleType (in `vehicletype/`):** Enum or classes for different vehicle types. - **Fee Calculation (in `fee/`):** Classes for calculating parking fees based on duration and vehicle type. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/parkinglot-class-diagram.png) ### 1. ParkingLot - **Methods:** - `parkVehicle(Vehicle vehicle)` - `unparkVehicle(String ticketId)` - `addFloor(ParkingFloor floor)` - `getAvailableSpots()` - **Fields:** List of floors, mapping of tickets, etc. ### 2. ParkingFloor - **Methods:** - `getAvailableSpot(VehicleType type)` - `parkVehicle(Vehicle vehicle)` - `unparkVehicle(String spotId)` - **Fields:** List of spots, floor number. ### 3. ParkingSpot - **Methods:** - `isAvailable()` - `assignVehicle(Vehicle vehicle)` - `removeVehicle()` - **Fields:** Spot ID, type, current vehicle. ### 4. Ticket - **Fields:** Ticket ID, vehicle info, entry time, spot info. ### 5. VehicleType (in `vehicletype/`) - Enum or classes for vehicle types (Car, Bike, Truck, etc.) ### 6. Fee Calculation (in `fee/`) - **Methods:** `calculateFee(Ticket parkingTicket, Date exitTime)` - **Extensible:** Add new strategies for fee calculation. --- ## Design Patterns Used - **Strategy Pattern:** For fee calculation strategies. - **Factory Pattern:** (If used) For creating vehicles or spots. - **Singleton Pattern:** (If used) For ParkingLot instance. --- ## Example Usage ```java ParkingLot lot = new ParkingLot(); lot.addFloor(new ParkingFloor(...)); Ticket parkingTicket = lot.parkVehicle(new Car("KA-01-1234")); lot.unparkVehicle(parkingTicket.getId()); ``` --- ## Demo See `ParkingLotDemo.java` for a sample usage of the parking lot system. --- ## Extending the Framework - **Add a new vehicle type:** Update or add to `vehicletype/`. - **Add a new fee strategy:** Implement a new class in `fee/`. - **Add new spot types or floors:** Extend `ParkingSpot` or `ParkingFloor`. --- ================================================ FILE: solutions/java/src/parkinglot/entities/ParkingFloor.java ================================================ package parkinglot.entities; import parkinglot.vehicle.Vehicle; import parkinglot.vehicle.VehicleSize; import java.util.Comparator; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class ParkingFloor { private final int floorNumber; private final Map spots; public ParkingFloor(int floorNumber) { this.floorNumber = floorNumber; this.spots = new ConcurrentHashMap<>(); } public void addSpot(ParkingSpot spot) { spots.put(spot.getSpotId(), spot); } public synchronized Optional findAvailableSpot(Vehicle vehicle) { return spots.values().stream() .filter(spot -> !spot.isOccupied() && spot.canFitVehicle(vehicle)) .sorted(Comparator.comparing(ParkingSpot::getSpotSize)) .findFirst(); } public void displayAvailability() { System.out.printf("--- Floor %d Availability ---\n", floorNumber); Map availableCounts = spots.values().stream() .filter(spot -> !spot.isOccupied()) .collect(Collectors.groupingBy(ParkingSpot::getSpotSize, Collectors.counting())); for (VehicleSize size : VehicleSize.values()) { System.out.printf(" %s spots: %d\n", size, availableCounts.getOrDefault(size, 0L)); } } } ================================================ FILE: solutions/java/src/parkinglot/entities/ParkingSpot.java ================================================ package parkinglot.entities; import parkinglot.vehicle.Vehicle; import parkinglot.vehicle.VehicleSize; public class ParkingSpot { private final String spotId; private boolean isOccupied; private Vehicle parkedVehicle; private final VehicleSize spotSize; public ParkingSpot(String spotId, VehicleSize spotSize) { this.spotId = spotId; this.spotSize = spotSize; this.isOccupied = false; this.parkedVehicle = null; } public String getSpotId() { return spotId; } public VehicleSize getSpotSize() { return spotSize; } public synchronized boolean isAvailable() { return !isOccupied; } public boolean isOccupied() { return isOccupied; } public synchronized void parkVehicle(Vehicle vehicle) { this.parkedVehicle = vehicle; this.isOccupied = true; } public synchronized void unparkVehicle() { this.parkedVehicle = null; this.isOccupied = false; } public boolean canFitVehicle(Vehicle vehicle) { if (isOccupied) return false; switch (vehicle.getSize()) { case SMALL: return spotSize == VehicleSize.SMALL; case MEDIUM: return spotSize == VehicleSize.MEDIUM || spotSize == VehicleSize.LARGE; case LARGE: return spotSize == VehicleSize.LARGE; default: return false; } } } ================================================ FILE: solutions/java/src/parkinglot/entities/ParkingTicket.java ================================================ package parkinglot.entities; import parkinglot.vehicle.Vehicle; import java.util.Date; import java.util.UUID; public class ParkingTicket { private final String ticketId; private final Vehicle vehicle; private final ParkingSpot spot; private final long entryTimestamp; private long exitTimestamp; public ParkingTicket(Vehicle vehicle, ParkingSpot spot) { this.ticketId = UUID.randomUUID().toString(); this.vehicle = vehicle; this.spot = spot; this.entryTimestamp = new Date().getTime(); } public String getTicketId() { return ticketId; } public Vehicle getVehicle() { return vehicle; } public ParkingSpot getSpot() { return spot; } public long getEntryTimestamp() { return entryTimestamp; } public long getExitTimestamp() { return exitTimestamp; } public void setExitTimestamp() { this.exitTimestamp = new Date().getTime(); } } ================================================ FILE: solutions/java/src/parkinglot/strategy/fee/FeeStrategy.java ================================================ package parkinglot.strategy.fee; import parkinglot.entities.ParkingTicket; public interface FeeStrategy { double calculateFee(ParkingTicket parkingTicket); } ================================================ FILE: solutions/java/src/parkinglot/strategy/fee/FlatRateFeeStrategy.java ================================================ package parkinglot.strategy.fee; import parkinglot.entities.ParkingTicket; public class FlatRateFeeStrategy implements FeeStrategy { private static final double RATE_PER_HOUR = 10.0; @Override public double calculateFee(ParkingTicket parkingTicket) { long duration = parkingTicket.getExitTimestamp() - parkingTicket.getEntryTimestamp(); long hours = (duration / (1000 * 60 * 60)) + 1; return hours * RATE_PER_HOUR; } } ================================================ FILE: solutions/java/src/parkinglot/strategy/fee/VehicleBasedFeeStrategy.java ================================================ package parkinglot.strategy.fee; import parkinglot.entities.ParkingTicket; import parkinglot.vehicle.VehicleSize; import java.util.Map; public class VehicleBasedFeeStrategy implements FeeStrategy { private static final Map HOURLY_RATES = Map.of( VehicleSize.SMALL, 10.0, VehicleSize.MEDIUM, 20.0, VehicleSize.LARGE, 30.0 ); @Override public double calculateFee(ParkingTicket parkingTicket) { long duration = parkingTicket.getExitTimestamp() - parkingTicket.getEntryTimestamp(); long hours = (duration / (1000 * 60 * 60)) + 1; return hours * HOURLY_RATES.get(parkingTicket.getVehicle().getSize()); } } ================================================ FILE: solutions/java/src/parkinglot/strategy/parking/BestFitStrategy.java ================================================ package parkinglot.strategy.parking; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.vehicle.Vehicle; import java.util.List; import java.util.Optional; public class BestFitStrategy implements ParkingStrategy { @Override public Optional findSpot(List floors, Vehicle vehicle) { Optional bestSpot = Optional.empty(); for (ParkingFloor floor : floors) { Optional spotOnThisFloor = floor.findAvailableSpot(vehicle); if (spotOnThisFloor.isPresent()) { if (bestSpot.isEmpty()) { // If this is the first spot we've found, it's the best one so far. bestSpot = spotOnThisFloor; } else { // A smaller spot size enum ordinal means a tighter fit. if (spotOnThisFloor.get().getSpotSize().ordinal() < bestSpot.get().getSpotSize().ordinal()) { bestSpot = spotOnThisFloor; } } } } return bestSpot; } } ================================================ FILE: solutions/java/src/parkinglot/strategy/parking/FarthestFirstStrategy.java ================================================ package parkinglot.strategy.parking; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.vehicle.Vehicle; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; public class FarthestFirstStrategy implements ParkingStrategy { @Override public Optional findSpot(List floors, Vehicle vehicle) { // Create a reversed copy of the floors list to search from the top floor down. List reversedFloors = new ArrayList<>(floors); Collections.reverse(reversedFloors); for (ParkingFloor floor : reversedFloors) { Optional spot = floor.findAvailableSpot(vehicle); if (spot.isPresent()) { return spot; } } return Optional.empty(); } } ================================================ FILE: solutions/java/src/parkinglot/strategy/parking/NearestFirstStrategy.java ================================================ package parkinglot.strategy.parking; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.vehicle.Vehicle; import java.util.List; import java.util.Optional; public class NearestFirstStrategy implements ParkingStrategy { @Override public Optional findSpot(List floors, Vehicle vehicle) { for (ParkingFloor floor : floors) { Optional spot = floor.findAvailableSpot(vehicle); if (spot.isPresent()) { return spot; } } return Optional.empty(); } } ================================================ FILE: solutions/java/src/parkinglot/strategy/parking/ParkingStrategy.java ================================================ package parkinglot.strategy.parking; import parkinglot.entities.ParkingFloor; import parkinglot.entities.ParkingSpot; import parkinglot.vehicle.Vehicle; import java.util.List; import java.util.Optional; public interface ParkingStrategy { Optional findSpot(List floors, Vehicle vehicle); } ================================================ FILE: solutions/java/src/parkinglot/vehicle/Bike.java ================================================ package parkinglot.vehicle; public class Bike extends Vehicle { public Bike(String licenseNumber) { super(licenseNumber, VehicleSize.SMALL); } } ================================================ FILE: solutions/java/src/parkinglot/vehicle/Car.java ================================================ package parkinglot.vehicle; public class Car extends Vehicle { public Car(String licenseNumber) { super(licenseNumber, VehicleSize.MEDIUM); } } ================================================ FILE: solutions/java/src/parkinglot/vehicle/Truck.java ================================================ package parkinglot.vehicle; public class Truck extends Vehicle { public Truck(String licenseNumber) { super(licenseNumber, VehicleSize.LARGE); } } ================================================ FILE: solutions/java/src/parkinglot/vehicle/Vehicle.java ================================================ package parkinglot.vehicle; public abstract class Vehicle { private final String licenseNumber; private final VehicleSize size; public Vehicle(String licenseNumber, VehicleSize size) { this.licenseNumber = licenseNumber; this.size = size; } public String getLicenseNumber() { return licenseNumber; } public VehicleSize getSize() { return size; } } ================================================ FILE: solutions/java/src/parkinglot/vehicle/VehicleSize.java ================================================ package parkinglot.vehicle; public enum VehicleSize { SMALL, MEDIUM, LARGE } ================================================ FILE: solutions/java/src/pubsubsystem/PubSubDemo.java ================================================ package pubsubsystem; import pubsubsystem.entities.Message; import pubsubsystem.subscriber.AlertSubscriber; import pubsubsystem.subscriber.NewsSubscriber; import pubsubsystem.subscriber.Subscriber; public class PubSubDemo { public static void main(String[] args) throws InterruptedException { PubSubService pubSubService = PubSubService.getInstance(); // --- Create Subscribers --- Subscriber sportsFan1 = new NewsSubscriber("SportsFan1"); Subscriber sportsFan2 = new NewsSubscriber("SportsFan2"); Subscriber techie1 = new NewsSubscriber("Techie1"); Subscriber allNewsReader = new NewsSubscriber("AllNewsReader"); Subscriber systemAdmin = new AlertSubscriber("SystemAdmin"); // --- Create Topics and Subscriptions --- final String SPORTS_TOPIC = "SPORTS"; final String TECH_TOPIC = "TECH"; final String WEATHER_TOPIC = "WEATHER"; pubSubService.createTopic(SPORTS_TOPIC); pubSubService.createTopic(TECH_TOPIC); pubSubService.createTopic(WEATHER_TOPIC); pubSubService.subscribe(SPORTS_TOPIC, sportsFan1); pubSubService.subscribe(SPORTS_TOPIC, sportsFan2); pubSubService.subscribe(SPORTS_TOPIC, allNewsReader); pubSubService.subscribe(SPORTS_TOPIC, systemAdmin); pubSubService.subscribe(TECH_TOPIC, techie1); pubSubService.subscribe(TECH_TOPIC, allNewsReader); System.out.println("\n--- Publishing Messages ---"); // --- Publish to SPORTS topic --- pubSubService.publish(SPORTS_TOPIC, new Message("Team A wins the championship!")); // Expected: SportsFan1, SportsFan2, AllNewsReader, SystemAdmin receive this. // --- Publish to TECH topic --- pubSubService.publish(TECH_TOPIC, new Message("New AI model released.")); // Expected: Techie1, AllNewsReader receive this. // --- Publish to WEATHER topic (no subscribers) --- pubSubService.publish(WEATHER_TOPIC, new Message("Sunny with a high of 75°F.")); // Expected: Message is dropped. // Allow some time for async messages to be processed Thread.sleep(500); System.out.println("\n--- Unsubscribing a user and re-publishing ---"); // SportsFan2 gets tired of sports news pubSubService.unsubscribe(SPORTS_TOPIC, sportsFan2); // Publish another message to SPORTS pubSubService.publish(SPORTS_TOPIC, new Message("Major player traded to Team B.")); // Expected: SportsFan1, AllNewsReader, SystemAdmin receive this. SportsFan2 does NOT. // Give messages time to be delivered Thread.sleep(500); // --- Shutdown the service --- pubSubService.shutdown(); } } ================================================ FILE: solutions/java/src/pubsubsystem/PubSubService.java ================================================ package pubsubsystem; import pubsubsystem.entities.Message; import pubsubsystem.entities.Topic; import pubsubsystem.subscriber.Subscriber; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class PubSubService { private static final PubSubService INSTANCE = new PubSubService(); private final ExecutorService deliveryExecutor; private final Map topicRegistry; private PubSubService() { this.topicRegistry = new ConcurrentHashMap<>(); // A cached thread pool is suitable for handling many short-lived, bursty tasks (message deliveries). deliveryExecutor = Executors.newCachedThreadPool(); } public static PubSubService getInstance() { return INSTANCE; } public void createTopic(String topicName) { topicRegistry.putIfAbsent(topicName, new Topic(topicName, deliveryExecutor)); System.out.println("Topic " + topicName + " created"); } public void subscribe(String topicName, Subscriber subscriber) { Topic topic = topicRegistry.get(topicName); if (topic == null) throw new IllegalArgumentException("Topic not found: " + topicName); topic.addSubscriber(subscriber); System.out.println("Subscriber '" + subscriber.getId() + "' subscribed to topic: " + topicName); } public void unsubscribe(String topicName, Subscriber subscriber) { Topic topic = topicRegistry.get(topicName); if (topic != null) topic.removeSubscriber(subscriber); System.out.println("Subscriber '" + subscriber.getId() + "' unsubscribed from topic: " + topicName); } public void publish(String topicName, Message message) { System.out.println("Publishing message to topic: " + topicName); Topic topic = topicRegistry.get(topicName); if (topic == null) throw new IllegalArgumentException("Topic not found: " + topicName); topic.broadcast(message); } public void shutdown() { System.out.println("PubSubService shutting down..."); deliveryExecutor.shutdown(); try { // Wait a reasonable time for existing tasks to complete if (!deliveryExecutor.awaitTermination(60, TimeUnit.SECONDS)) { deliveryExecutor.shutdownNow(); } } catch (InterruptedException ie) { deliveryExecutor.shutdownNow(); Thread.currentThread().interrupt(); } System.out.println("PubSubService shutdown complete."); } } ================================================ FILE: solutions/java/src/pubsubsystem/README.md ================================================ # Pub/Sub System (LLD) ## Problem Statement Design and implement a Publish-Subscribe (Pub/Sub) system that allows publishers to send messages to topics, and subscribers to receive messages from topics they are interested in. The system should support multiple topics, multiple subscribers per topic, and asynchronous message delivery. --- ## Requirements - **Topics:** The system supports multiple topics. - **Publishers:** Publishers can publish messages to any topic. - **Subscribers:** Subscribers can subscribe to one or more topics and receive messages published to those topics. - **Multiple Subscribers:** Each topic can have multiple subscribers. - **Asynchronous Delivery:** Messages are delivered to subscribers asynchronously. - **Unsubscribe:** Subscribers can unsubscribe from topics. - **Extensibility:** Easy to add new subscriber types or message processing logic. --- ## Core Entities - **Broker:** Manages topics, subscriptions, and message delivery. - **Topic:** Represents a topic to which messages can be published and subscribers can subscribe. - **Publisher:** Publishes messages to topics via the pubSubService. - **Subscriber (interface):** Interface for all subscribers, defines the `consume(Message)` method. - **PrintSubscriber:** A subscriber that prints received messages. - **LoggingSubscriber:** A subscriber that logs received messages. - **Message:** Represents a message with a payload. - **Dispatcher:** Handles asynchronous delivery of messages to subscribers. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/pubsubsystem-class-diagram.png) ### 1. Broker - **Fields:** Map topics - **Methods:** createTopic(String), subscribe(String, Subscriber), unsubscribe(String, Subscriber), publish(String, Message) ### 2. Topic - **Fields:** String name, List subscribers - **Methods:** addSubscriber(Subscriber), removeSubscriber(Subscriber), publish(Message) ### 3. Publisher - **Fields:** String name, Broker pubSubService - **Methods:** publish(String topic, String payload) ### 4. Subscriber (interface) - **Methods:** consume(Message) ### 5. PrintSubscriber - **Implements:** Subscriber - **Behavior:** Prints received messages to the console ### 6. LoggingSubscriber - **Implements:** Subscriber - **Behavior:** Logs received messages (prints with a log prefix) ### 7. Message - **Fields:** String payload - **Methods:** getPayload() ### 8. Dispatcher - **Methods:** dispatch(Subscriber, Message), shutdown() --- ## Design Patterns Used - **Observer Pattern:** The Pub/Sub system is a concrete implementation of the Observer pattern. Topics (subjects) maintain a list of subscribers (observers) and notify them asynchronously when a new message is published. ## Example Usage ```java Broker pubSubService = new Broker(); pubSubService.createTopic("topic1"); pubSubService.createTopic("topic2"); Publisher publisher1 = new Publisher("publisher1", pubSubService); Subscriber subscriber1 = new PrintSubscriber("PrintSubscriber1"); Subscriber subscriber2 = new LoggingSubscriber("LoggingSubscriber2"); pubSubService.subscribe("topic1", subscriber1); pubSubService.subscribe("topic2", subscriber2); publisher1.publish("topic1", "Hello Topic1!"); publisher1.publish("topic2", "Hello Topic2!"); ``` --- ## Demo See `PubSubSystemDemo.java` for a sample usage and simulation of the pub/sub system. --- ## Extending the Design - **Add new subscriber types:** Implement the `Subscriber` interface for custom processing. - **Add new message types:** Extend the `Message` class for richer payloads. - **Add filtering or transformation:** Enhance the pubSubService or topic to support message filtering or transformation. --- ================================================ FILE: solutions/java/src/pubsubsystem/entities/Message.java ================================================ package pubsubsystem.entities; import java.time.Instant; public class Message { private final String payload; private final Instant timestamp; public Message(String payload) { this.payload = payload; this.timestamp = Instant.now(); } public String getPayload() { return payload; } @Override public String toString() { return "Message{" + "payload='" + payload + '\'' + '}'; } } ================================================ FILE: solutions/java/src/pubsubsystem/entities/Topic.java ================================================ package pubsubsystem.entities; import pubsubsystem.subscriber.Subscriber; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; public class Topic { private final String name; private final Set subscribers; private final ExecutorService deliveryExecutor; public Topic(String name, ExecutorService deliveryExecutor) { this.name = name; this.deliveryExecutor = deliveryExecutor; this.subscribers = new CopyOnWriteArraySet<>(); } public String getName() { return name; } public void addSubscriber(Subscriber subscriber) { subscribers.add(subscriber); } public void removeSubscriber(Subscriber subscriber) { subscribers.remove(subscriber); } public void broadcast(Message message) { for (Subscriber subscriber : subscribers) { deliveryExecutor.submit(() -> { try { subscriber.onMessage(message); } catch (Exception e) { System.err.println("Error delivering message to subscriber " + subscriber.getId() + ": " + e.getMessage()); } }); } } } ================================================ FILE: solutions/java/src/pubsubsystem/subscriber/AlertSubscriber.java ================================================ package pubsubsystem.subscriber; import pubsubsystem.entities.Message; public class AlertSubscriber implements Subscriber { private final String id; public AlertSubscriber(String id) { this.id = id; } @Override public String getId() { return id; } @Override public void onMessage(Message message) { System.out.printf("!!! [ALERT - %s] : '%s' !!!%n", id, message.getPayload()); } } ================================================ FILE: solutions/java/src/pubsubsystem/subscriber/NewsSubscriber.java ================================================ package pubsubsystem.subscriber; import pubsubsystem.entities.Message; public class NewsSubscriber implements Subscriber { private final String id; public NewsSubscriber(String id) { this.id = id; } @Override public String getId() { return id; } @Override public void onMessage(Message message) { System.out.printf("[Subscriber %s] received message '%s'%n", id, message.getPayload()); } } ================================================ FILE: solutions/java/src/pubsubsystem/subscriber/Subscriber.java ================================================ package pubsubsystem.subscriber; import pubsubsystem.entities.Message; public interface Subscriber { String getId(); void onMessage(Message message); } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/README.md ================================================ # Restaurant Management System (LLD) ## Problem Statement Design and implement a Restaurant Management System that allows customers to make reservations, place orders, manage tables, generate bills, and process payments. The system should also support staff management and menu management. --- ## Requirements - **Table Management:** The system manages tables, their availability, and assignments. - **Reservation Management:** Customers can reserve tables in advance. - **Menu Management:** The system manages a menu of items, including prices and descriptions. - **Order Placement:** Customers can place orders for menu items. - **Order Tracking:** The system tracks the status of each order (e.g., PLACED, PREPARING, SERVED, COMPLETED). - **Billing:** The system generates bills for completed orders. - **Payment Processing:** The system processes payments for bills. - **Staff Management:** The system manages staff assignments (e.g., waiters, chefs). - **Extensibility:** Easy to add new features such as customer feedback, loyalty programs, or online ordering. --- ## Core Entities - **RestaurantManagementSystem:** Main class that manages tables, reservations, orders, menu, staff, and payments. - **Table:** Represents a table in the restaurant, with table number, capacity, and availability. - **Reservation:** Represents a reservation for a table by a customer. - **MenuItem:** Represents an item on the menu, with name, description, and price. - **Order:** Represents a customer's order, including items, status, and associated table. - **OrderItem:** Represents an item in an order. - **OrderStatus:** Enum for order status (PLACED, PREPARING, SERVED, COMPLETED). - **Bill:** Represents the bill for an order, including total amount and payment status. - **Payment (in payment/):** Represents a payment transaction for a bill. - **Staff:** Represents a staff member (e.g., waiter, chef). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/RestaurantManagementSystem-class-diagram.png) ### 1. RestaurantManagementSystem - **Fields:** List tables, List reservations, List menu, List orders, List bills, List staff, PaymentProcessor paymentProcessor - **Methods:** addTable(Table), addMenuItem(MenuItem), makeReservation(Reservation), placeOrder(Order), updateOrderStatus(Order, OrderStatus), generateBill(Order), processPayment(Bill, Payment), addStaff(Staff), etc. ### 2. Table - **Fields:** int tableNumber, int capacity, boolean isAvailable ### 3. Reservation - **Fields:** int id, Table table, String customerName, Date reservationTime ### 4. MenuItem - **Fields:** int id, String name, String description, double price ### 5. Order - **Fields:** int id, Table table, List items, OrderStatus status ### 6. OrderItem - **Fields:** MenuItem menuItem, int quantity ### 7. OrderStatus (enum) - Values: PLACED, PREPARING, SERVED, COMPLETED ### 8. Bill - **Fields:** int id, Order order, double totalAmount, boolean isPaid ### 9. Payment (in payment/) - **Fields:** int id, double amount, String method, PaymentStatus status ### 10. Staff - **Fields:** int id, String name, String role ### 11. PaymentProcessor (in payment/) - **Methods:** process(Payment), validate(Payment) --- ## Example Usage ```java RestaurantManagementSystem system = new RestaurantManagementSystem(); Table table = new Table(1, 4, true); system.addTable(table); MenuItem pizza = new MenuItem(1, "Pizza", "Cheese Pizza", 12.0); system.addMenuItem(pizza); Reservation reservation = new Reservation(1, table, "Alice", new Date()); system.makeReservation(reservation); Order order = new Order(1, table, List.of(new OrderItem(pizza, 2)), OrderStatus.PLACED); system.placeOrder(order); Bill bill = system.generateBill(order); Payment payment = new Payment(1, bill.getTotalAmount(), "CREDIT_CARD"); system.processPayment(bill, payment); ``` --- ## Demo See `RestaurantManagementSystemDemo.java` for a sample usage and simulation of the restaurant management system. --- ## Extending the Design - **Add customer feedback:** Allow customers to rate their experience. - **Add loyalty programs:** Track and reward repeat customers. - **Add online ordering:** Support for online reservations and orders. --- ================================================ FILE: solutions/java/src/restaurantmanagementsystem/RestaurantManagementSystem.java ================================================ package restaurantmanagementsystem; import restaurantmanagementsystem.payment.Payment; import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class RestaurantManagementSystem { private static RestaurantManagementSystem instance; private final Map menu; private final Map orders; private final List reservations; private final Map payments; private final List staff; private final Map tables; private RestaurantManagementSystem() { menu = new ConcurrentHashMap<>(); orders = new ConcurrentHashMap<>(); reservations = new CopyOnWriteArrayList<>(); payments = new ConcurrentHashMap<>(); staff = new CopyOnWriteArrayList<>(); tables = new ConcurrentHashMap<>(); } public static synchronized RestaurantManagementSystem getInstance() { if (instance == null) { instance = new RestaurantManagementSystem(); } return instance; } public MenuItem addMenuItem(String name, double price) { MenuItem menuItem = new MenuItem(name, price); menu.put(name, new MenuItem(name, price)); return menuItem; } public void removeMenuItem(String itemName) { menu.remove(itemName); } public List getMenu() { return new ArrayList<>(menu.values()); } public void addTable(int tableId, int capacity) { tables.put(tableId, new Table(tableId, capacity)); } public Table reserveTable(int tableId) { Table table = tables.get(tableId); if (table == null) { throw new IllegalArgumentException("Invalid table ID"); } table.reserve(); return table; } public Order placeOrder(int tableId, List items) { Table table = tables.get(tableId); if (table == null || !table.isAvailable()) { throw new IllegalStateException("Table not reserved or invalid"); } Order order = new Order(table, items); orders.put(order.getId(), order); notifyKitchen(order); return order; } public void markOrderPreparing(String orderId) { Order order = orders.get(orderId); order.markPreparing(); notifyKitchen(order); } public void markOrderReady(String orderId) { Order order = orders.get(orderId); order.markReady(); notifyStaff(order); } public void markOrderServed(String orderId) { Order order = orders.get(orderId); order.markServed(); } public Bill getBill(String orderId) { Order order = orders.get(orderId); if (order.getStatus() == OrderStatus.PAID) throw new IllegalStateException("Order already paid"); order.markPaid(); return new Bill(order.getId(), order.calculateTotal()); } public void makePayment(Bill bill, Payment payment) { Order order = orders.get(bill.getOrderId()); if (payment.processPayment(bill.getTotalAmount())) { bill.markPaymentCompleted(); order.markPaid(); } else { bill.markPaymentFailed(); throw new RuntimeException("Payment failed for the orderId: " + order.getId()); } } public Reservation makeReservation(String customerName, String contactNumber, int partySize, Timestamp reservationTime) { Reservation reservation = new Reservation(customerName, contactNumber, partySize, reservationTime); reservations.add(reservation); return reservation; } public void cancelReservation(Reservation reservation) { reservations.remove(reservation); } public void addStaff(Staff staff) { this.staff.add(staff); } public void removeStaff(Staff staff) { this.staff.remove(staff); } private void notifyKitchen(Order order) { // Notify kitchen staff to prepare the order // ... } private void notifyStaff(Order order) { // Notify relevant staff about the order status update // ... } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/RestaurantManagementSystemDemo.java ================================================ package restaurantmanagementsystem; import restaurantmanagementsystem.payment.CreditCardPayment; import java.sql.Timestamp; import java.util.List; public class RestaurantManagementSystemDemo { public static void run() { RestaurantManagementSystem restaurantManagementSystem = RestaurantManagementSystem.getInstance(); // Add menu items MenuItem menuItem1 = restaurantManagementSystem.addMenuItem("Burger", 9.99); MenuItem menuItem2 = restaurantManagementSystem.addMenuItem("Pizza", 12.99); MenuItem menuItem3 = restaurantManagementSystem.addMenuItem("Salad", 7.99); // Add tables restaurantManagementSystem.addTable(1, 4); restaurantManagementSystem.addTable(2, 2); // Place an order Order order = restaurantManagementSystem.placeOrder(1, List.of( new OrderItem(menuItem1, 1), new OrderItem(menuItem3, 2) )); // Update order status restaurantManagementSystem.markOrderPreparing(order.getId()); restaurantManagementSystem.markOrderReady(order.getId()); restaurantManagementSystem.markOrderServed(order.getId()); // Process payment Bill bill = restaurantManagementSystem.getBill(order.getId()); restaurantManagementSystem.makePayment(bill, new CreditCardPayment()); // Make a reservation Reservation reservation = restaurantManagementSystem.makeReservation("John Doe", "1234567890", 4, new Timestamp(System.currentTimeMillis())); // Add staff restaurantManagementSystem.addStaff(new Staff(1, "Alice", "Manager", "9876543210")); restaurantManagementSystem.addStaff(new Staff(2, "Bob", "Chef", "5432109876")); // Get menu List menu = restaurantManagementSystem.getMenu(); System.out.println("Menu:"); for (MenuItem item : menu) { System.out.println(item.getName() + " - $" + item.getPrice()); } } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/RestaurantManagementSystemFacade.java ================================================ package restaurantmanagementsystem; import restaurantmanagementsystem.command.Command; import restaurantmanagementsystem.command.PrepareOrderCommand; import restaurantmanagementsystem.command.ServeOrderCommand; import restaurantmanagementsystem.decorator.*; import restaurantmanagementsystem.model.*; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public class RestaurantManagementSystemFacade { private static RestaurantManagementSystemFacade instance; private final Restaurant restaurant = Restaurant.getInstance(); private final AtomicInteger orderIdCounter; private final Map orders; private RestaurantManagementSystemFacade() { this.orderIdCounter = new AtomicInteger(1); this.orders = new HashMap<>(); } public static synchronized RestaurantManagementSystemFacade getInstance() { if (instance == null) { instance = new RestaurantManagementSystemFacade(); } return instance; } public Table addTable(int id, int capacity) { Table table = new Table(id, capacity); restaurant.addTable(table); return table; } public Waiter addWaiter(String id, String name) { Waiter waiter = new Waiter(id, name); restaurant.addWaiter(waiter); return waiter; } public Chef addChef(String id, String name) { Chef chef = new Chef(id, name); restaurant.addChef(chef); return chef; } public MenuItem addMenuItem(String id, String name, double price) { MenuItem item = new MenuItem(id, name, price); restaurant.getMenu().addItem(item); return item; } public Order takeOrder(int tableId, String waiterId, List menuItemIds) { Waiter waiter = restaurant.getWaiter(waiterId); if (waiter == null) { throw new IllegalArgumentException("Invalid waiter ID."); } // For simplicity, we get the first available chef. Chef chef = restaurant.getChefs().stream().findFirst() .orElseThrow(() -> new IllegalStateException("No chefs available.")); Order order = new Order(orderIdCounter.getAndIncrement(), tableId); for (String itemId : menuItemIds) { MenuItem menuItem = restaurant.getMenu().getItem(itemId); OrderItem orderItem = new OrderItem(menuItem, order); // Waiter subscribes to each item to get notified when it's ready. orderItem.addObserver(waiter); order.addItem(orderItem); } // The Command pattern decouples the waiter (invoker) from the chef (receiver). Command prepareOrderCommand = new PrepareOrderCommand(order, chef); prepareOrderCommand.execute(); orders.put(order.getOrderId(), order); return order; } public void markItemsAsReady(int orderId) { Order order = orders.get(orderId); System.out.println("\nChef has finished preparing order " + order.getOrderId()); order.getOrderItems().forEach(item -> { // Preparing -> ReadyForPickup -> Notifies Observer (Waiter) item.nextState(); item.nextState(); }); } public void serveOrder(String waiterId, int orderId) { Order order = orders.get(orderId); Waiter waiter = restaurant.getWaiter(waiterId); Command serveOrderCommand = new ServeOrderCommand(order, waiter); serveOrderCommand.execute(); } public Bill generateBill(int orderId) { Order order = orders.get(orderId); // The Decorator pattern adds charges dynamically. BillComponent billComponent = new BaseBill(order); billComponent = new TaxDecorator(billComponent, 0.08); // 8% tax billComponent = new ServiceChargeDecorator(billComponent, 5.00); // $5 flat service charge return new Bill(billComponent); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/command/Command.java ================================================ package restaurantmanagementsystem.command; public interface Command { void execute(); } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/command/PrepareOrderCommand.java ================================================ package restaurantmanagementsystem.command; import restaurantmanagementsystem.model.Chef; import restaurantmanagementsystem.model.Order; public class PrepareOrderCommand implements Command { private final Order order; private final Chef chef; public PrepareOrderCommand(Order order, Chef chef) { this.order = order; this.chef = chef; } @Override public void execute() { chef.prepareOrder(order); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/command/ServeOrderCommand.java ================================================ package restaurantmanagementsystem.command; import restaurantmanagementsystem.model.Order; import restaurantmanagementsystem.model.Waiter; public class ServeOrderCommand implements Command{ private final Order order; private final Waiter waiter; public ServeOrderCommand(Order order, Waiter waiter) { this.order = order; this.waiter = waiter; } @Override public void execute() { waiter.serveOrder(order); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/BaseBill.java ================================================ package restaurantmanagementsystem.decorator; import restaurantmanagementsystem.model.Order; public class BaseBill implements BillComponent { private final Order order; public BaseBill(Order order) { this.order = order; } @Override public double calculateTotal() { return order.getTotalPrice(); } @Override public String getDescription() { return "Order Items"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/Bill.java ================================================ package restaurantmanagementsystem.decorator; public class Bill { private final BillComponent component; public Bill(BillComponent component) { this.component = component; } public void printBill() { System.out.println("\n--- BILL ---"); System.out.printf("Description: %s\n", component.getDescription()); System.out.printf("Total: $%.2f\n", component.calculateTotal()); System.out.println("------------"); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/BillComponent.java ================================================ package restaurantmanagementsystem.decorator; public interface BillComponent { double calculateTotal(); String getDescription(); } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/BillDecorator.java ================================================ package restaurantmanagementsystem.decorator; public abstract class BillDecorator implements BillComponent { protected BillComponent wrapped; public BillDecorator(BillComponent component) { this.wrapped = component; } @Override public double calculateTotal() { return wrapped.calculateTotal(); } @Override public String getDescription() { return wrapped.getDescription(); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/ServiceChargeDecorator.java ================================================ package restaurantmanagementsystem.decorator; public class ServiceChargeDecorator extends BillDecorator { private final double serviceCharge; public ServiceChargeDecorator(BillComponent component, double charge) { super(component); this.serviceCharge = charge; } @Override public double calculateTotal() { return super.calculateTotal() + serviceCharge; } @Override public String getDescription() { return super.getDescription() + ", Service Charge"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/decorator/TaxDecorator.java ================================================ package restaurantmanagementsystem.decorator; public class TaxDecorator extends BillDecorator { private final double taxRate; public TaxDecorator(BillComponent component, double taxRate) { super(component); this.taxRate = taxRate; } @Override public double calculateTotal() { return super.calculateTotal() * (1 + taxRate); } @Override public String getDescription() { return super.getDescription() + ", Tax @" + (taxRate * 100) + "%"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/enums/TableStatus.java ================================================ package restaurantmanagementsystem.enums; public enum TableStatus { AVAILABLE, OCCUPIED, RESERVED } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Chef.java ================================================ package restaurantmanagementsystem.model; import restaurantmanagementsystem.state.PreparingState; public class Chef extends Staff { public Chef(String id, String name) { super(id, name); } public void prepareOrder(Order order) { System.out.println("Chef " + name + " received order " + order.getOrderId() + " and is starting preparation."); order.getOrderItems().forEach(item -> { // Chef's action triggers the first state change for each item. item.changeState(new PreparingState()); }); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Menu.java ================================================ package restaurantmanagementsystem.model; import java.util.HashMap; import java.util.Map; public class Menu { private final Map items = new HashMap<>(); public void addItem(MenuItem item) { items.put(item.getId(), item); } public MenuItem getItem(String id) { MenuItem item = items.get(id); if (item == null) { throw new IllegalArgumentException("Menu item with ID " + id + " not found."); } return item; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/MenuItem.java ================================================ package restaurantmanagementsystem.model; public class MenuItem { private final String id; private final String name; private final double price; public MenuItem(String id, String name, double price) { this.id = id; this.name = name; this.price = price; } public String getId() { return id; } public String getName() { return name; } public double getPrice() { return price; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Order.java ================================================ package restaurantmanagementsystem.model; import java.util.ArrayList; import java.util.List; public class Order { private final int orderId; private final int tableId; private final List items = new ArrayList<>(); public Order(int orderId, int tableId) { this.orderId = orderId; this.tableId = tableId; } public void addItem(OrderItem item) { items.add(item); } public double getTotalPrice() { return items.stream() .mapToDouble(item -> item.getMenuItem().getPrice()) .sum(); } public int getOrderId() { return orderId; } public int getTableId() { return tableId; } public List getOrderItems() { return items; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/OrderItem.java ================================================ package restaurantmanagementsystem.model; import restaurantmanagementsystem.observer.OrderObserver; import restaurantmanagementsystem.state.OrderItemState; import restaurantmanagementsystem.state.OrderedState; import java.util.ArrayList; import java.util.List; public class OrderItem { private final MenuItem menuItem; private final Order order; private OrderItemState state; private final List observers = new ArrayList<>(); public OrderItem(MenuItem menuItem, Order order) { this.menuItem = menuItem; this.order = order; this.state = new OrderedState(); } public void changeState(OrderItemState newState) { this.state = newState; System.out.println("Item '" + menuItem.getName() + "' state changed to: " + newState.getStatus()); } public void nextState() { state.next(this); } public void setState(OrderItemState state) { this.state = state; } public void addObserver(OrderObserver observer) { observers.add(observer); } public void notifyObservers() { new ArrayList<>(observers).forEach(observer -> observer.update(this)); } public MenuItem getMenuItem() { return menuItem; } public Order getOrder() { return order; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Restaurant.java ================================================ package restaurantmanagementsystem.model; import java.util.HashMap; import java.util.List; import java.util.Map; public class Restaurant { private static final Restaurant INSTANCE = new Restaurant(); private final Map waiters = new HashMap<>(); private final Map chefs = new HashMap<>(); private final Map tables = new HashMap<>(); private final Menu menu = new Menu(); private Restaurant() {} public static Restaurant getInstance() { return INSTANCE; } public void addWaiter(Waiter waiter) { waiters.put(waiter.getId(), waiter); } public Waiter getWaiter(String id) { return waiters.get(id); } public void addChef(Chef chef) { chefs.put(chef.getId(), chef); } public Chef getChef(String id) { return chefs.get(id); } public List getChefs() { return chefs.values().stream().toList(); } public List getWaiters() { return waiters.values().stream().toList(); } public void addTable(Table table) { tables.put(table.getId(), table); } public Menu getMenu() { return menu; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Staff.java ================================================ package restaurantmanagementsystem.model; public abstract class Staff { protected String id; protected String name; public Staff(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Table.java ================================================ package restaurantmanagementsystem.model; import restaurantmanagementsystem.enums.TableStatus; public class Table { private final int id; private final int capacity; private TableStatus status; public Table(int id, int capacity) { this.id = id; this.capacity = capacity; this.status = TableStatus.AVAILABLE; } public int getId() { return id; } public int getCapacity() { return capacity; } public TableStatus getStatus() { return status; } public void setStatus(TableStatus status) { this.status = status; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/model/Waiter.java ================================================ package restaurantmanagementsystem.model; import restaurantmanagementsystem.observer.OrderObserver; import restaurantmanagementsystem.state.ServedState; public class Waiter extends Staff implements OrderObserver { public Waiter(String id, String name) { super(id, name); } public void serveOrder(Order order) { System.out.println("Waiter " + name + " is serving order " + order.getOrderId()); order.getOrderItems().forEach(item -> { item.changeState(new ServedState()); }); } @Override public void update(OrderItem item) { System.out.println(">>> WAITER " + name + " NOTIFIED: Item '" + item.getMenuItem().getName() + "' for table " + item.getOrder().getTableId() + " is READY FOR PICKUP."); } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/observer/OrderObserver.java ================================================ package restaurantmanagementsystem.observer; import restaurantmanagementsystem.model.OrderItem; public interface OrderObserver { void update(OrderItem item); } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/state/OrderItemState.java ================================================ package restaurantmanagementsystem.state; import restaurantmanagementsystem.model.OrderItem; public interface OrderItemState { void next(OrderItem item); void prev(OrderItem item); String getStatus(); } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/state/OrderedState.java ================================================ package restaurantmanagementsystem.state; import restaurantmanagementsystem.model.OrderItem; public class OrderedState implements OrderItemState { @Override public void next(OrderItem item) { item.setState(new PreparingState()); } @Override public void prev(OrderItem item) { System.out.println("This is the initial state."); } @Override public String getStatus() { return "ORDERED"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/state/PreparingState.java ================================================ package restaurantmanagementsystem.state; import restaurantmanagementsystem.model.OrderItem; public class PreparingState implements OrderItemState { @Override public void next(OrderItem item) { item.setState(new ReadyForPickupState()); } @Override public void prev(OrderItem item) { item.setState(new OrderedState()); } @Override public String getStatus() { return "PREPARING"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/state/ReadyForPickupState.java ================================================ package restaurantmanagementsystem.state; import restaurantmanagementsystem.model.OrderItem; public class ReadyForPickupState implements OrderItemState { @Override public void next(OrderItem item) { // This is the key state. When it transitions, it notifies observers. item.notifyObservers(); } @Override public void prev(OrderItem item) { item.setState(new PreparingState()); } @Override public String getStatus() { return "READY_FOR_PICKUP"; } } ================================================ FILE: solutions/java/src/restaurantmanagementsystem/state/ServedState.java ================================================ package restaurantmanagementsystem.state; import restaurantmanagementsystem.model.OrderItem; public class ServedState implements OrderItemState { @Override public void next(OrderItem item) { System.out.println("This is the final state."); } @Override public void prev(OrderItem item) { System.out.println("Cannot revert a served item."); } @Override public String getStatus() { return "SERVED"; } } ================================================ FILE: solutions/java/src/ridesharingservice/README.md ================================================ # Ride Sharing Service (LLD) ## Problem Statement Design and implement a Ride Sharing Service that allows riders to request rides, drivers to accept trips, and the system to manage trip assignments, payments, and trip status. --- ## Requirements - **User Management:** The system manages both riders and drivers. - **Location Management:** The system tracks the current location of drivers and riders. - **Trip Request:** Riders can request rides by specifying pickup and drop-off locations. - **Driver Assignment:** The system assigns available drivers to ride requests based on proximity and availability. - **Trip Management:** The system tracks the status of each trip (e.g., REQUESTED, ONGOING, COMPLETED, CANCELLED). - **Payment Processing:** The system processes payments for completed trips. - **Driver Status:** The system tracks driver availability (e.g., AVAILABLE, ON_TRIP, OFFLINE). - **Extensibility:** Easy to add new features such as ratings, ride pooling, or surge pricing. --- ## Core Entities - **RideSharingService:** Main class that manages riders, drivers, trips, and payments. - **Rider:** Represents a rider who can request trips. - **Driver:** Represents a driver with current status and location. - **Trip:** Represents a ride, including rider, driver, locations, status, and payment. - **Location:** Represents a geographic location (latitude, longitude). - **TripStatus (enum):** REQUESTED, ONGOING, COMPLETED, CANCELLED. - **DriverStatus (enum):** AVAILABLE, ON_TRIP, OFFLINE. - **Payment (in payment/):** Represents a payment transaction for a trip. - **User:** Base class for Rider and Driver (if applicable). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/RideSharingService-class-diagram.png) ### 1. RideSharingService - **Fields:** List riders, List drivers, List trips, PaymentProcessor paymentProcessor - **Methods:** registerRider(Rider), registerDriver(Driver), requestTrip(Rider, Location, Location), assignDriver(Trip), startTrip(Trip), completeTrip(Trip), processPayment(Trip, Payment), updateDriverStatus(Driver, DriverStatus), etc. ### 2. Rider - **Fields:** int id, String name, Location currentLocation ### 3. Driver - **Fields:** int id, String name, Location currentLocation, DriverStatus status ### 4. Trip - **Fields:** int id, Rider rider, Driver driver, Location pickup, Location dropoff, TripStatus status, Payment payment ### 5. Location - **Fields:** double latitude, double longitude ### 6. TripStatus (enum) - Values: REQUESTED, ONGOING, COMPLETED, CANCELLED ### 7. DriverStatus (enum) - Values: AVAILABLE, ON_TRIP, OFFLINE ### 8. Payment (in payment/) - **Fields:** int id, double amount, String method, PaymentStatus status ### 9. PaymentProcessor (in payment/) - **Methods:** process(Payment), validate(Payment) ### 10. User - **Fields:** int id, String name --- ## Example Usage ```java RideSharingService service = new RideSharingService(); Rider alice = new Rider(1, "Alice", new Location(12.9716, 77.5946)); Driver bob = new Driver(2, "Bob", new Location(12.9718, 77.5940), DriverStatus.AVAILABLE); service.registerRider(alice); service.registerDriver(bob); Trip trip = service.requestTrip(alice, alice.getCurrentLocation(), new Location(12.9352, 77.6245)); service.assignDriver(trip); service.startTrip(trip); // ... after trip completion Payment payment = new Payment(1, 250.0, "CREDIT_CARD"); service.completeTrip(trip); service.processPayment(trip, payment); ``` --- ## Demo See `RideSharingServiceDemo.java` for a sample usage and simulation of the ride sharing service. --- ## Extending the Framework - **Add ratings and reviews:** Allow riders and drivers to rate each other. - **Add ride pooling:** Support multiple riders sharing a trip. - **Add surge pricing:** Adjust pricing based on demand and supply. --- ================================================ FILE: solutions/java/src/ridesharingservice/RideSharingService.java ================================================ package ridesharingservice; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Location; import ridesharingservice.entities.Trip; import ridesharingservice.entities.Vehicle; import ridesharingservice.enums.DriverStatus; import ridesharingservice.enums.RideType; import ridesharingservice.observer.Rider; import ridesharingservice.strategy.matching.DriverMatchingStrategy; import ridesharingservice.strategy.pricing.PricingStrategy; public class RideSharingService { private static volatile RideSharingService instance; private final Map riders = new ConcurrentHashMap<>(); private final Map drivers = new ConcurrentHashMap<>(); private final Map trips = new ConcurrentHashMap<>(); private PricingStrategy pricingStrategy; private DriverMatchingStrategy driverMatchingStrategy; private RideSharingService() {} public static synchronized RideSharingService getInstance() { if (instance == null) { instance = new RideSharingService(); } return instance; } // Allow changing strategies at runtime for extensibility public void setPricingStrategy(PricingStrategy pricingStrategy) { this.pricingStrategy = pricingStrategy; } public void setDriverMatchingStrategy(DriverMatchingStrategy driverMatchingStrategy) { this.driverMatchingStrategy = driverMatchingStrategy; } public Rider registerRider(String name, String contact) { Rider rider = new Rider(name, contact); riders.put(rider.getId(), rider); return rider; } public Driver registerDriver(String name, String contact, Vehicle vehicle, Location initialLocation) { Driver driver = new Driver(name, contact, vehicle, initialLocation); drivers.put(driver.getId(), driver); return driver; } public Trip requestRide(String riderId, Location pickup, Location dropoff, RideType rideType) { Rider rider = riders.get(riderId); if (rider == null) throw new NoSuchElementException("Rider not found"); System.out.println("\n--- New Ride Request from " + rider.getName() + " ---"); // 1. Find available drivers List availableDrivers = driverMatchingStrategy.findDrivers(List.copyOf(drivers.values()), pickup, rideType); if (availableDrivers.isEmpty()) { System.out.println("No drivers available for your request. Please try again later."); return null; } System.out.println("Found " + availableDrivers.size() + " available driver(s)."); // 2. Calculate fare double fare = pricingStrategy.calculateFare(pickup, dropoff, rideType); System.out.printf("Estimated fare: $%.2f%n", fare); // 3. Create a trip using the Builder Trip trip = new Trip.TripBuilder() .withRider(rider) .withPickupLocation(pickup) .withDropoffLocation(dropoff) .withFare(fare) .build(); trips.put(trip.getId(), trip); // 4. Notify nearby drivers (in a real system, this would be a push notification) System.out.println("Notifying nearby drivers of the new ride request..."); for (Driver driver : availableDrivers) { System.out.println(" > Notifying " + driver.getName() + " at " + driver.getCurrentLocation()); driver.onUpdate(trip); } return trip; } public void acceptRide(String driverId, String tripId) { Driver driver = drivers.get(driverId); Trip trip = trips.get(tripId); if (driver == null || trip == null) throw new NoSuchElementException("Driver or Trip not found"); System.out.println("\n--- Driver " + driver.getName() + " accepted the ride ---"); driver.setStatus(DriverStatus.IN_TRIP); trip.assignDriver(driver); } public void startTrip(String tripId) { Trip trip = trips.get(tripId); if (trip == null) throw new NoSuchElementException("Trip not found"); System.out.println("\n--- Trip " + trip.getId() + " is starting ---"); trip.startTrip(); } public void endTrip(String tripId) { Trip trip = trips.get(tripId); if (trip == null) throw new NoSuchElementException("Trip not found"); System.out.println("\n--- Trip " + trip.getId() + " is ending ---"); trip.endTrip(); // Update statuses and history Driver driver = trip.getDriver(); driver.setStatus(DriverStatus.ONLINE); // Driver is available again driver.setCurrentLocation(trip.getDropoffLocation()); // Update driver location Rider rider = trip.getRider(); driver.addTripToHistory(trip); rider.addTripToHistory(trip); System.out.println("Driver " + driver.getName() + " is now back online at " + driver.getCurrentLocation()); } } ================================================ FILE: solutions/java/src/ridesharingservice/RideSharingServiceDemo.java ================================================ package ridesharingservice; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Location; import ridesharingservice.entities.Trip; import ridesharingservice.entities.Vehicle; import ridesharingservice.enums.DriverStatus; import ridesharingservice.enums.RideType; import ridesharingservice.observer.Rider; import ridesharingservice.strategy.matching.NearestDriverMatchingStrategy; import ridesharingservice.strategy.pricing.VehicleBasedPricingStrategy; public class RideSharingServiceDemo { public static void main(String[] args) { // 1. Setup the system using singleton instance RideSharingService service = RideSharingService.getInstance(); service.setDriverMatchingStrategy(new NearestDriverMatchingStrategy()); service.setPricingStrategy(new VehicleBasedPricingStrategy()); // 2. Register riders and drivers Rider alice = service.registerRider("Alice", "123-456-7890"); Driver bob = service.registerDriver("Bob", "243-987-2860", new Vehicle("KA01-1234", "Toyota Prius", RideType.SEDAN), new Location(1.0, 1.0)); Driver charlie = service.registerDriver("Charlie", "313-486-2691", new Vehicle("KA02-5678", "Honda CRV", RideType.SUV), new Location(2.0, 2.0)); Driver david = service.registerDriver("David", "613-586-3241", new Vehicle("KA03-9012", "Honda CRV", RideType.SEDAN), new Location(1.2, 1.2)); // 3. Drivers go online bob.setStatus(DriverStatus.ONLINE); charlie.setStatus(DriverStatus.ONLINE); david.setStatus(DriverStatus.ONLINE); // David is online but will be too far for the first request david.setCurrentLocation(new Location(10.0, 10.0)); // 4. Alice requests a ride Location pickupLocation = new Location(0.0, 0.0); Location dropoffLocation = new Location(5.0, 5.0); // Rider wants a SEDAN Trip trip1 = service.requestRide(alice.getId(), pickupLocation, dropoffLocation, RideType.SEDAN); if (trip1 != null) { // 5. One of the nearby drivers accepts the ride // In this case, Bob (1.0, 1.0) is closer than David (10.0, 10.0 is too far). // Charlie is ignored because he drives an SUV. service.acceptRide(bob.getId(), trip1.getId()); // 6. The trip progresses service.startTrip(trip1.getId()); service.endTrip(trip1.getId()); } System.out.println("\n--- Checking Trip History ---"); System.out.println("Alice's trip history: " + alice.getTripHistory()); System.out.println("Bob's trip history: " + bob.getTripHistory()); // --- Second ride request --- System.out.println("\n============================================="); Rider harry = service.registerRider("Harry", "167-342-7834"); // Harry requests an SUV Trip trip2 = service.requestRide(harry.getId(), new Location(2.5, 2.5), new Location(8.0, 8.0), RideType.SUV); if(trip2 != null) { // Only Charlie is available for an SUV ride service.acceptRide(charlie.getId(), trip2.getId()); service.startTrip(trip2.getId()); service.endTrip(trip2.getId()); } } } ================================================ FILE: solutions/java/src/ridesharingservice/entities/Driver.java ================================================ package ridesharingservice.entities; import ridesharingservice.enums.DriverStatus; import ridesharingservice.enums.TripStatus; public class Driver extends User { private Vehicle vehicle; private Location currentLocation; private DriverStatus status; public Driver(String name, String contact, Vehicle vehicle, Location initialLocation) { super(name, contact); this.vehicle = vehicle; this.currentLocation = initialLocation; this.status = DriverStatus.OFFLINE; // Default status } public Vehicle getVehicle() { return vehicle; } public DriverStatus getStatus() { return status; } public void setStatus(DriverStatus status) { this.status = status; System.out.println("Driver " + getName() + " is now " + status); } public Location getCurrentLocation() { return currentLocation; } public void setCurrentLocation(Location currentLocation) { this.currentLocation = currentLocation; } @Override public void onUpdate(Trip trip) { System.out.printf("--- Notification for Driver %s ---\n", getName()); System.out.printf(" Trip %s status: %s.\n", trip.getId(), trip.getStatus()); if (trip.getStatus() == TripStatus.REQUESTED) { System.out.println(" A new ride is available for you to accept."); } System.out.println("--------------------------------\n"); } } ================================================ FILE: solutions/java/src/ridesharingservice/entities/Location.java ================================================ package ridesharingservice.entities; public class Location { private final double latitude; private final double longitude; public Location(double latitude, double longitude) { this.latitude = latitude; this.longitude = longitude; } public double distanceTo(Location other) { double dx = this.latitude - other.latitude; double dy = this.longitude - other.longitude; return Math.sqrt(dx * dx + dy * dy); // Euclidean for simplicity } @Override public String toString() { return "Location(" + latitude + ", " + longitude + ")"; } } ================================================ FILE: solutions/java/src/ridesharingservice/entities/Trip.java ================================================ package ridesharingservice.entities; import java.util.UUID; import ridesharingservice.enums.TripStatus; import ridesharingservice.observer.Rider; import ridesharingservice.observer.TripObserver; import ridesharingservice.state.RequestedState; import ridesharingservice.state.TripState; import java.util.ArrayList; import java.util.List; public class Trip { private final String id; private final Rider rider; private Driver driver; private final Location pickupLocation; private final Location dropoffLocation; private final double fare; private TripStatus status; private TripState currentState; private final List observers = new ArrayList<>(); private Trip(TripBuilder builder) { this.id = builder.id; this.rider = builder.rider; this.pickupLocation = builder.pickupLocation; this.dropoffLocation = builder.dropoffLocation; this.fare = builder.fare; this.status = TripStatus.REQUESTED; this.currentState = new RequestedState(); // Initial state } public void addObserver(TripObserver observer) { observers.add(observer); } private void notifyObservers() { observers.forEach(o -> o.onUpdate(this)); } public void assignDriver(Driver driver) { currentState.assign(this, driver); addObserver(driver); notifyObservers(); } public void startTrip() { currentState.start(this); notifyObservers(); } public void endTrip() { currentState.end(this); notifyObservers(); } // Getters public String getId() { return id; } public Rider getRider() { return rider; } public Driver getDriver() { return driver; } public Location getPickupLocation() { return pickupLocation; } public Location getDropoffLocation() { return dropoffLocation; } public double getFare() { return fare; } public TripStatus getStatus() { return status; } // Setters are protected, only to be called by State objects public void setState(TripState state) { this.currentState = state; } public void setStatus(TripStatus status) { this.status = status; } public void setDriver(Driver driver) { this.driver = driver; } // --- Builder Pattern --- public static class TripBuilder { private final String id; private Rider rider; private Location pickupLocation; private Location dropoffLocation; private double fare; public TripBuilder() { this.id = UUID.randomUUID().toString(); } public TripBuilder withRider(Rider rider) { this.rider = rider; return this; } public TripBuilder withPickupLocation(Location pickupLocation) { this.pickupLocation = pickupLocation; return this; } public TripBuilder withDropoffLocation(Location dropoffLocation) { this.dropoffLocation = dropoffLocation; return this; } public TripBuilder withFare(double fare) { this.fare = fare; return this; } public Trip build() { // Basic validation if (rider == null || pickupLocation == null || dropoffLocation == null) { throw new IllegalStateException("Rider, pickup, and dropoff locations are required to build a trip."); } return new Trip(this); } } @Override public String toString() { return "Trip [id=" + id + ", status=" + status + ", fare=$" + String.format("%.2f", fare) + "]"; } } ================================================ FILE: solutions/java/src/ridesharingservice/entities/User.java ================================================ package ridesharingservice.entities; import java.util.ArrayList; import java.util.List; import java.util.UUID; import ridesharingservice.observer.TripObserver; public abstract class User implements TripObserver { private final String id; private final String name; private final String contact; private final List tripHistory; public User(String name, String contact) { this.id = UUID.randomUUID().toString(); this.name = name; this.contact = contact; this.tripHistory = new ArrayList<>(); } public void addTripToHistory(Trip trip) { tripHistory.add(trip); } public List getTripHistory() { return tripHistory; } public String getId() { return id; } public String getName() { return name; } public String getContact() { return contact; } } ================================================ FILE: solutions/java/src/ridesharingservice/entities/Vehicle.java ================================================ package ridesharingservice.entities; import ridesharingservice.enums.RideType; public class Vehicle { private final String licenseNumber; private final String model; private final RideType type; public Vehicle(String licenseNumber, String model, RideType type) { this.licenseNumber = licenseNumber; this.model = model; this.type = type; } public String getLicenseNumber() { return licenseNumber; } public String getModel() { return model; } public RideType getType() { return type; } } ================================================ FILE: solutions/java/src/ridesharingservice/enums/DriverStatus.java ================================================ package ridesharingservice.enums; public enum DriverStatus { ONLINE, IN_TRIP, OFFLINE } ================================================ FILE: solutions/java/src/ridesharingservice/enums/RideType.java ================================================ package ridesharingservice.enums; public enum RideType { SEDAN, SUV, AUTO } ================================================ FILE: solutions/java/src/ridesharingservice/enums/TripStatus.java ================================================ package ridesharingservice.enums; public enum TripStatus { REQUESTED, ASSIGNED, IN_PROGRESS, COMPLETED, CANCELLED } ================================================ FILE: solutions/java/src/ridesharingservice/observer/Rider.java ================================================ package ridesharingservice.observer; import ridesharingservice.entities.Trip; import ridesharingservice.entities.User; public class Rider extends User { public Rider(String name, String contact) { super(name, contact); } @Override public void onUpdate(Trip trip) { System.out.printf("--- Notification for Rider %s ---\n", getName()); System.out.printf(" Trip %s is now %s.\n", trip.getId(), trip.getStatus()); if (trip.getDriver() != null) { System.out.printf(" Driver: %s in a %s (%s)\n", trip.getDriver().getName(), trip.getDriver().getVehicle().getModel(), trip.getDriver().getVehicle().getLicenseNumber()); } System.out.println("--------------------------------\n"); } } ================================================ FILE: solutions/java/src/ridesharingservice/observer/TripObserver.java ================================================ package ridesharingservice.observer; import ridesharingservice.entities.Trip; public interface TripObserver { void onUpdate(Trip trip); } ================================================ FILE: solutions/java/src/ridesharingservice/state/AssignedState.java ================================================ package ridesharingservice.state; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Trip; import ridesharingservice.enums.TripStatus; public class AssignedState implements TripState { @Override public void request(Trip trip) { System.out.println("Trip has already been requested and assigned."); } @Override public void assign(Trip trip, Driver driver) { System.out.println("Trip is already assigned. To re-assign, cancel first."); } @Override public void start(Trip trip) { trip.setStatus(TripStatus.IN_PROGRESS); trip.setState(new InProgressState()); } @Override public void end(Trip trip) { System.out.println("Cannot end a trip that has not started."); } } ================================================ FILE: solutions/java/src/ridesharingservice/state/CompletedState.java ================================================ package ridesharingservice.state; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Trip; public class CompletedState implements TripState { @Override public void request(Trip trip) { System.out.println("Cannot request a trip that is already completed."); } @Override public void assign(Trip trip, Driver driver) { System.out.println("Cannot assign a driver to a completed trip."); } @Override public void start(Trip trip) { System.out.println("Cannot start a completed trip."); } @Override public void end(Trip trip) { System.out.println("Trip is already completed."); } } ================================================ FILE: solutions/java/src/ridesharingservice/state/InProgressState.java ================================================ package ridesharingservice.state; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Trip; import ridesharingservice.enums.TripStatus; public class InProgressState implements TripState { @Override public void request(Trip trip) { System.out.println("Trip is already in progress."); } @Override public void assign(Trip trip, Driver driver) { System.out.println("Cannot assign a new driver while trip is in progress."); } @Override public void start(Trip trip) { System.out.println("Trip is already in progress."); } @Override public void end(Trip trip) { trip.setStatus(TripStatus.COMPLETED); trip.setState(new CompletedState()); } } ================================================ FILE: solutions/java/src/ridesharingservice/state/RequestedState.java ================================================ package ridesharingservice.state; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Trip; import ridesharingservice.enums.TripStatus; public class RequestedState implements TripState { @Override public void request(Trip trip) { System.out.println("Trip is already in requested state."); } @Override public void assign(Trip trip, Driver driver) { trip.setDriver(driver); trip.setStatus(TripStatus.ASSIGNED); trip.setState(new AssignedState()); } @Override public void start(Trip trip) { System.out.println("Cannot start a trip that has not been assigned a driver."); } @Override public void end(Trip trip) { System.out.println("Cannot end a trip that has not been assigned a driver."); } } ================================================ FILE: solutions/java/src/ridesharingservice/state/TripState.java ================================================ package ridesharingservice.state; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Trip; public interface TripState { void request(Trip trip); void assign(Trip trip, Driver driver); void start(Trip trip); void end(Trip trip); } ================================================ FILE: solutions/java/src/ridesharingservice/strategy/matching/DriverMatchingStrategy.java ================================================ package ridesharingservice.strategy.matching; import java.util.List; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Location; import ridesharingservice.enums.RideType; public interface DriverMatchingStrategy { List findDrivers(List allDrivers, Location pickupLocation, RideType rideType); } ================================================ FILE: solutions/java/src/ridesharingservice/strategy/matching/NearestDriverMatchingStrategy.java ================================================ package ridesharingservice.strategy.matching; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import ridesharingservice.entities.Driver; import ridesharingservice.entities.Location; import ridesharingservice.enums.DriverStatus; import ridesharingservice.enums.RideType; public class NearestDriverMatchingStrategy implements DriverMatchingStrategy { private static final double MAX_DISTANCE_KM = 5.0; // Max distance to consider a driver "nearby" @Override public List findDrivers(List allDrivers, Location pickupLocation, RideType rideType) { System.out.println("Finding nearest drivers for ride type: " + rideType); return allDrivers.stream() .filter(driver -> driver.getStatus() == DriverStatus.ONLINE) .filter(driver -> driver.getVehicle().getType() == rideType) .filter(driver -> pickupLocation.distanceTo(driver.getCurrentLocation()) <= MAX_DISTANCE_KM) .sorted(Comparator.comparingDouble(driver -> pickupLocation.distanceTo(driver.getCurrentLocation()))) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/ridesharingservice/strategy/pricing/FlatRatePricingStrategy.java ================================================ package ridesharingservice.strategy.pricing; import ridesharingservice.entities.Location; import ridesharingservice.enums.RideType; public class FlatRatePricingStrategy implements PricingStrategy { private static final double BASE_FARE = 5.0; private static final double FLAT_RATE = 1.5; @Override public double calculateFare(Location pickup, Location dropoff, RideType rideType) { double distance = pickup.distanceTo(dropoff); return BASE_FARE + distance * FLAT_RATE; } } ================================================ FILE: solutions/java/src/ridesharingservice/strategy/pricing/PricingStrategy.java ================================================ package ridesharingservice.strategy.pricing; import ridesharingservice.entities.Location; import ridesharingservice.enums.RideType; public interface PricingStrategy { double calculateFare(Location pickup, Location dropoff, RideType rideType); } ================================================ FILE: solutions/java/src/ridesharingservice/strategy/pricing/VehicleBasedPricingStrategy.java ================================================ package ridesharingservice.strategy.pricing; import java.util.Map; import ridesharingservice.entities.Location; import ridesharingservice.enums.RideType; public class VehicleBasedPricingStrategy implements PricingStrategy { private static final double BASE_FARE = 2.50; private static final Map RATE_PER_KM = Map.of( RideType.SEDAN, 1.50, RideType.SUV, 2.00, RideType.AUTO, 1.00 ); @Override public double calculateFare(Location pickup, Location dropoff, RideType rideType) { return BASE_FARE + RATE_PER_KM.get(rideType) * pickup.distanceTo(dropoff); } } ================================================ FILE: solutions/java/src/snakeandladdergame/Game.java ================================================ package snakeandladdergame; import snakeandladdergame.enums.GameStatus; import snakeandladdergame.models.Board; import snakeandladdergame.models.BoardEntity; import snakeandladdergame.models.Dice; import snakeandladdergame.models.Player; import java.util.LinkedList; import java.util.List; import java.util.Queue; public class Game { private final Board board; private final Queue players; private final Dice dice; private GameStatus status; private Player winner; private Game(Builder builder) { this.board = builder.board; this.players = new LinkedList<>(builder.players); this.dice = builder.dice; this.status = GameStatus.NOT_STARTED; } public void play() { if (players.size() < 2) { System.out.println("Cannot start game. At least 2 players are required."); return; } this.status = GameStatus.RUNNING; System.out.println("Game started!"); while (status == GameStatus.RUNNING) { Player currentPlayer = players.poll(); takeTurn(currentPlayer); // If the game is not finished and the player didn't roll a 6, add them back to the queue if (status == GameStatus.RUNNING) { players.add(currentPlayer); } } System.out.println("Game Finished!"); if (winner != null) { System.out.printf("The winner is %s!\n", winner.getName()); } } private void takeTurn(Player player) { int roll = dice.roll(); System.out.printf("\n%s's turn. Rolled a %d.\n", player.getName(), roll); int currentPosition = player.getPosition(); int nextPosition = currentPosition + roll; if (nextPosition > board.getSize()) { System.out.printf("Oops, %s needs to land exactly on %d. Turn skipped.\n", player.getName(), board.getSize()); return; } if (nextPosition == board.getSize()) { player.setPosition(nextPosition); this.winner = player; this.status = GameStatus.FINISHED; System.out.printf("Hooray! %s reached the final square %d and won!\n", player.getName(), board.getSize()); return; } int finalPosition = board.getFinalPosition(nextPosition); if (finalPosition > nextPosition) { // Ladder System.out.printf("Wow! %s found a ladder 🪜 at %d and climbed to %d.\n", player.getName(), nextPosition, finalPosition); } else if (finalPosition < nextPosition) { // Snake System.out.printf("Oh no! %s was bitten by a snake 🐍 at %d and slid down to %d.\n", player.getName(), nextPosition, finalPosition); } else { System.out.printf("%s moved from %d to %d.\n", player.getName(), currentPosition, finalPosition); } player.setPosition(finalPosition); if (roll == 6) { System.out.printf("%s rolled a 6 and gets another turn!\n", player.getName()); takeTurn(player); } } // 🧱 Inner Builder class public static class Builder { private Board board; private Queue players; private Dice dice; public Builder setBoard(int boardSize, List boardEntities) { this.board = new Board(boardSize, boardEntities); return this; } public Builder setPlayers(List playerNames) { this.players = new LinkedList<>(); for (String playerName : playerNames) { players.add(new Player(playerName)); } return this; } public Builder setDice(Dice dice) { this.dice = dice; return this; } public Game build() { if (board == null || players == null || dice == null) { throw new IllegalStateException("Board, Players, and Dice must be set."); } return new Game(this); } } } ================================================ FILE: solutions/java/src/snakeandladdergame/README.md ================================================ # Snake and Ladder Game (LLD) ## Problem Statement Design and implement a Snake and Ladder Game that allows multiple players to play on a board with snakes and ladders, simulates dice rolls, and determines the winner. --- ## Requirements - **Multiple Players:** The game supports two or more players. - **Board:** The game uses a board with a configurable size (typically 1 to 100). - **Snakes and Ladders:** The board contains snakes (which move players down) and ladders (which move players up). - **Dice Roll:** Players roll a dice to determine their move. - **Turn Management:** Players take turns in a round-robin fashion. - **Win Condition:** The first player to reach the last cell wins. - **Input Validation:** The game prevents invalid moves (e.g., moving beyond the last cell). - **Extensibility:** Easy to add new features such as multiple dice, power-ups, or custom board sizes. --- ## Core Entities - **SnakeAndLadderGame:** Main class that manages the game flow, player turns, and win condition. - **Board:** Represents the game board, including snakes, ladders, and player positions. - **Snake:** Represents a snake with a start and end position. - **Ladder:** Represents a ladder with a start and end position. - **Player:** Represents a player with a name and current position. - **Dice:** Simulates dice rolls. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/SnakeAndLadderGame-class-diagram.png) ### 1. SnakeAndLadderGame - **Fields:** Board board, List players, Dice dice, boolean isGameOver - **Methods:** start(), playTurn(), movePlayer(Player, int steps), checkWin(Player), getCurrentPlayer() ### 2. Board - **Fields:** int size, List snakes, List ladders, Map playerPositions - **Methods:** getNextPosition(int current, int roll), addSnake(Snake), addLadder(Ladder), setPlayerPosition(Player, int position), getPlayerPosition(Player) ### 3. Snake - **Fields:** int start, int end ### 4. Ladder - **Fields:** int start, int end ### 5. Player - **Fields:** String name, int position ### 6. Dice - **Methods:** roll() --- ## Example Usage ```java List players = List.of(new Player("Alice"), new Player("Bob")); List snakes = List.of(new Snake(14, 7), new Snake(31, 26)); List ladders = List.of(new Ladder(3, 22), new Ladder(5, 8)); Board board = new Board(100, snakes, ladders, players); Dice dice = new Dice(); SnakeAndLadderGame game = new SnakeAndLadderGame(board, players, dice); game.start(); ``` --- ## Demo See `SnakeAndLadderDemo.java` for a sample usage and simulation of the snake and ladder game. --- ## Extending the Framework - **Add multiple dice:** Allow rolling more than one dice per turn. - **Add power-ups:** Introduce special cells with unique effects. - **Add custom board sizes:** Support boards larger or smaller than 100 cells. --- ================================================ FILE: solutions/java/src/snakeandladdergame/SnakeAndLadderDemo.java ================================================ package snakeandladdergame; import snakeandladdergame.models.BoardEntity; import snakeandladdergame.models.Dice; import snakeandladdergame.models.Ladder; import snakeandladdergame.models.Snake; import java.util.Arrays; import java.util.List; public class SnakeAndLadderDemo { public static void main(String[] args) { List boardEntities = List.of( new Snake(17, 7), new Snake(54, 34), new Snake(62, 19), new Snake(98, 79), new Ladder(3, 38), new Ladder(24, 33), new Ladder(42, 93), new Ladder(72, 84) ); List players = Arrays.asList("Alice", "Bob", "Charlie"); Game game = new Game.Builder() .setBoard(100, boardEntities) .setPlayers(players) .setDice(new Dice(1, 6)) .build(); game.play(); } } ================================================ FILE: solutions/java/src/snakeandladdergame/enums/GameStatus.java ================================================ package snakeandladdergame.enums; public enum GameStatus { NOT_STARTED, RUNNING, FINISHED } ================================================ FILE: solutions/java/src/snakeandladdergame/models/Board.java ================================================ package snakeandladdergame.models; import java.util.HashMap; import java.util.List; import java.util.Map; public class Board { private final int size; private final Map snakesAndLadders; public Board(int size, List entities) { this.size = size; this.snakesAndLadders = new HashMap<>(); for (BoardEntity entity : entities) { snakesAndLadders.put(entity.getStart(), entity.getEnd()); } } public int getSize() { return size; } public int getFinalPosition(int position) { return snakesAndLadders.getOrDefault(position, position); } } ================================================ FILE: solutions/java/src/snakeandladdergame/models/BoardEntity.java ================================================ package snakeandladdergame.models; public abstract class BoardEntity { private final int start; private final int end; public BoardEntity(int start, int end) { this.start = start; this.end = end; } public int getStart() { return start; } public int getEnd() { return end; } } ================================================ FILE: solutions/java/src/snakeandladdergame/models/Dice.java ================================================ package snakeandladdergame.models; public class Dice { private final int minValue; private final int maxValue; public Dice(int minValue, int maxValue) { this.minValue = minValue; this.maxValue = maxValue; } public int roll() { return (int) (Math.random() * (maxValue - minValue + 1) + minValue); } } ================================================ FILE: solutions/java/src/snakeandladdergame/models/Ladder.java ================================================ package snakeandladdergame.models; public class Ladder extends BoardEntity { public Ladder(int start, int end) { super(start, end); if (start >= end) { throw new IllegalArgumentException("Ladder bottom must be at a lower position than its top."); } } } ================================================ FILE: solutions/java/src/snakeandladdergame/models/Player.java ================================================ package snakeandladdergame.models; public class Player { private final String name; private int position; public Player(String name) { this.name = name; this.position = 0; } public String getName() { return name; } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } } ================================================ FILE: solutions/java/src/snakeandladdergame/models/Snake.java ================================================ package snakeandladdergame.models; public class Snake extends BoardEntity { public Snake(int start, int end) { super(start, end); if (start <= end) { throw new IllegalArgumentException("Snake head must be at a higher position than its tail."); } } } ================================================ FILE: solutions/java/src/socialnetworkingservice/README.md ================================================ Facade Pattern: The SocialNetworkFacade is the main entry point for the client. It provides a simple, unified interface (createPost, addFriend, getNewsFeed) to the complex subsystem of services and repositories. Observer Pattern: The PostService acts as a Subject. When a user creates a post, it notifies all registered Observers (like a NewsFeedNotifier). This decouples the action of posting from the consequence of updating news feeds. Strategy Pattern: The NewsFeedService uses a NewsFeedGenerationStrategy to generate a user's news feed. The default is a ChronologicalStrategy, but this can be easily swapped for a more complex algorithm. Composite Pattern: To model comments and replies, the Commentable interface is used. Both Post and Comment implement this interface, allowing them to be treated uniformly. A comment can be added to a post or to another comment, forming a tree structure. Singleton Pattern: The Repository classes are implemented as Singletons to provide a global, in-memory data store for this simulation. Repository Pattern: This pattern is used to abstract the data access layer. Services interact with UserRepository and PostRepository interfaces, completely decoupling them from the underlying data storage mechanism (which is a ConcurrentHashMap in this case). ================================================ FILE: solutions/java/src/socialnetworkingservice/SocialNetworkDemo.java ================================================ package socialnetworkingservice; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import java.util.List; public class SocialNetworkDemo { public static void main(String[] args) { SocialNetworkFacade socialNetwork = new SocialNetworkFacade(); System.out.println("----------- 1. Creating Users -----------"); User alice = socialNetwork.createUser("Alice", "alice@example.com"); User bob = socialNetwork.createUser("Bob", "bob@example.com"); User charlie = socialNetwork.createUser("Charlie", "charlie@example.com"); System.out.println("Created users: " + alice.getName() + ", " + bob.getName() + ", " + charlie.getName()); System.out.println("\n----------- 2. Building Friendships -----------"); socialNetwork.addFriend(alice.getId(), bob.getId()); socialNetwork.addFriend(bob.getId(), charlie.getId()); System.out.println(alice.getName() + " and " + bob.getName() + " are now friends."); System.out.println(bob.getName() + " and " + charlie.getName() + " are now friends."); System.out.println("\n----------- 3. Users Create Posts -----------"); Post alicePost = socialNetwork.createPost(alice.getId(), "Hello from Alice!"); Post bobPost = socialNetwork.createPost(bob.getId(), "It's a beautiful day!"); Post charliePost = socialNetwork.createPost(charlie.getId(), "Thinking about design patterns."); System.out.println("\n----------- 4. Users Interact with Posts -----------"); socialNetwork.addComment(bob.getId(), alicePost.getId(), "Hey Alice, nice to see you here!"); socialNetwork.likePost(charlie.getId(), alicePost.getId()); System.out.println("\n----------- 5. Viewing News Feeds (Strategy Pattern) -----------"); System.out.println("\n--- Alice's News Feed (should see Bob's post) ---"); List alicesFeed = socialNetwork.getNewsFeed(alice.getId()); printFeed(alicesFeed); System.out.println("\n--- Bob's News Feed (should see Alice's, and Charlie's post) ---"); List bobsFeed = socialNetwork.getNewsFeed(bob.getId()); printFeed(bobsFeed); System.out.println("\n--- Charlie's News Feed (should see Bob's post) ---"); List charliesFeed = socialNetwork.getNewsFeed(charlie.getId()); printFeed(charliesFeed); } private static void printFeed(List feed) { if (feed.isEmpty()) { System.out.println(" No posts in the feed."); return; } feed.forEach(post -> { System.out.println(" Post by " + post.getAuthor().getName() + " at " + post.getTimestamp()); System.out.println(" \"" + post.getContent() + "\""); System.out.println(" Likes: " + post.getLikes().size() + ", Comments: " + post.getComments().size()); }); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/SocialNetworkFacade.java ================================================ package socialnetworkingservice; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import socialnetworkingservice.observer.UserNotifier; import socialnetworkingservice.service.NewsFeedService; import socialnetworkingservice.service.PostService; import socialnetworkingservice.service.UserService; import java.util.List; public class SocialNetworkFacade { private final UserService userService; private final PostService postService; private final NewsFeedService newsFeedService; public SocialNetworkFacade() { this.userService = new UserService(); this.postService = new PostService(); this.newsFeedService = new NewsFeedService(); // Wire up the observer postService.addObserver(new UserNotifier()); } public User createUser(String name, String email) { return userService.createUser(name, email); } public void addFriend(String userId1, String userId2) { userService.addFriend(userId1, userId2); } public Post createPost(String authorId, String content) { User author = userService.getUserById(authorId); return postService.createPost(author, content); } public void addComment(String userId, String postId, String content) { User user = userService.getUserById(userId); postService.addComment(user, postId, content); } public void likePost(String userId, String postId) { User user = userService.getUserById(userId); postService.likePost(user, postId); } public List getNewsFeed(String userId) { User user = userService.getUserById(userId); return newsFeedService.getNewsFeed(user); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/model/Comment.java ================================================ package socialnetworkingservice.model; import java.util.List; public class Comment extends CommentableEntity { public Comment(User author, String content) { super(author, content); } public List getReplies() { return getComments(); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/model/CommentableEntity.java ================================================ package socialnetworkingservice.model; import java.time.LocalDateTime; import java.util.*; public abstract class CommentableEntity { protected final String id; protected final User author; protected final String content; protected final LocalDateTime timestamp; private final Set likes = new HashSet<>(); protected final List comments = new ArrayList<>(); public CommentableEntity(User author, String content) { this.id = UUID.randomUUID().toString(); this.author = author; this.content = content; this.timestamp = LocalDateTime.now(); } public void addLike(User user) { likes.add(user); } public void addComment(Comment comment) { comments.add(comment); } public String getId() { return id; } public User getAuthor() { return author; } public String getContent() { return content; } public LocalDateTime getTimestamp() { return timestamp; } public List getComments() { return comments; } public Set getLikes() { return likes; } } ================================================ FILE: solutions/java/src/socialnetworkingservice/model/Post.java ================================================ package socialnetworkingservice.model; public class Post extends CommentableEntity { public Post(User author, String content) { super(author, content); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/model/User.java ================================================ package socialnetworkingservice.model; import java.util.*; public class User { private final String id; private final String name; private final String email; private final Set friends = new HashSet<>(); private final List posts = new ArrayList<>(); public User(String name, String email) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; } public void addFriend(User friend) { friends.add(friend); } public void addPost(Post post) { posts.add(post); } public String getId() { return id; } public String getName() { return name; } public Set getFriends() { return friends; } public List getPosts() { return posts; } } ================================================ FILE: solutions/java/src/socialnetworkingservice/observer/PostObserver.java ================================================ package socialnetworkingservice.observer; import socialnetworkingservice.model.Comment; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; public interface PostObserver { void onPostCreated(Post post); void onLike(Post post, User user); void onComment(Post post, Comment comment); } ================================================ FILE: solutions/java/src/socialnetworkingservice/observer/UserNotifier.java ================================================ package socialnetworkingservice.observer; import socialnetworkingservice.model.Comment; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; public class UserNotifier implements PostObserver { @Override public void onPostCreated(Post post) { User author = post.getAuthor(); for (User friend: author.getFriends()) { System.out.println("Notification for " + friend.getName() + ": " + author.getName() + " created a new post: " + post.getContent()); } } @Override public void onLike(Post post, User user) { User author = post.getAuthor(); System.out.println("Notification for " + author.getName() + ": " + user.getName() + " liked your post"); } @Override public void onComment(Post post, Comment comment) { User author = post.getAuthor(); System.out.println("Notification for " + author.getName() + ": " + comment.getAuthor().getName() + " commented on your post"); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/repository/PostRepository.java ================================================ package socialnetworkingservice.repository; import socialnetworkingservice.model.Post; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class PostRepository { private static final PostRepository INSTANCE = new PostRepository(); private final Map posts = new ConcurrentHashMap<>(); private PostRepository() {} public static PostRepository getInstance() { return INSTANCE; } public void save(Post post) { posts.put(post.getId(), post); } public Post findById(String id) { return posts.get(id); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/repository/UserRepository.java ================================================ package socialnetworkingservice.repository; import socialnetworkingservice.model.User; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class UserRepository { private static final UserRepository INSTANCE = new UserRepository(); private final Map users = new ConcurrentHashMap<>(); private UserRepository() {} public static UserRepository getInstance() { return INSTANCE; } public void save(User user) { users.put(user.getId(), user); } public User findById(String id) { return users.get(id); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/service/NewsFeedService.java ================================================ package socialnetworkingservice.service; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import socialnetworkingservice.strategy.ChronologicalStrategy; import socialnetworkingservice.strategy.NewsFeedGenerationStrategy; import java.util.List; public class NewsFeedService { private NewsFeedGenerationStrategy strategy; public NewsFeedService() { this.strategy = new ChronologicalStrategy(); // Default strategy } public void setStrategy(NewsFeedGenerationStrategy strategy) { this.strategy = strategy; } public List getNewsFeed(User user) { return strategy.generateFeed(user); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/service/PostService.java ================================================ package socialnetworkingservice.service; import socialnetworkingservice.model.Comment; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import socialnetworkingservice.observer.PostObserver; import socialnetworkingservice.repository.PostRepository; import java.util.ArrayList; import java.util.List; public class PostService { private final PostRepository postRepository = PostRepository.getInstance(); private final List observers = new ArrayList<>(); public void addObserver(PostObserver observer) { observers.add(observer); } public Post createPost(User author, String content) { Post post = new Post(author, content); postRepository.save(post); author.addPost(post); observers.forEach(observer -> observer.onPostCreated(post)); // Notify observers return post; } public void likePost(User user, String postId) { Post post = postRepository.findById(postId); post.addLike(user); observers.forEach(observer -> observer.onLike(post, user)); } public void addComment(User author, String commentableId, String content) { Comment comment = new Comment(author, content); Post post = postRepository.findById(commentableId); post.addComment(comment); observers.forEach(observer -> observer.onComment(post, comment)); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/service/UserService.java ================================================ package socialnetworkingservice.service; import socialnetworkingservice.model.User; import socialnetworkingservice.repository.UserRepository; public class UserService { private final UserRepository userRepository = UserRepository.getInstance(); public User createUser(String name, String email) { User user = new User(name, email); userRepository.save(user); return user; } public void addFriend(String userId1, String userId2) { User user1 = userRepository.findById(userId1); User user2 = userRepository.findById(userId2); user1.addFriend(user2); user2.addFriend(user1); } public User getUserById(String userId) { return userRepository.findById(userId); } } ================================================ FILE: solutions/java/src/socialnetworkingservice/strategy/ChronologicalStrategy.java ================================================ package socialnetworkingservice.strategy; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import java.util.ArrayList; import java.util.List; import java.util.Set; public class ChronologicalStrategy implements NewsFeedGenerationStrategy { @Override public List generateFeed(User user) { Set friends = user.getFriends(); List feed = new ArrayList<>(); for (User friend: friends) { feed.addAll(friend.getPosts()); } // Sort posts by timestamp in reverse (most recent first) feed.sort((p1, p2) -> p2.getTimestamp().compareTo(p1.getTimestamp())); return feed; } } ================================================ FILE: solutions/java/src/socialnetworkingservice/strategy/NewsFeedGenerationStrategy.java ================================================ package socialnetworkingservice.strategy; import socialnetworkingservice.model.Post; import socialnetworkingservice.model.User; import java.util.List; public interface NewsFeedGenerationStrategy { List generateFeed(User user); } ================================================ FILE: solutions/java/src/splitwise/README.md ================================================ # Splitwise System (LLD) ## Problem Statement Design and implement a Splitwise System that allows users to split expenses among groups and individuals. The system should handle expense tracking, balance calculations, and settlement of debts between users. --- ## Requirements 1. **User Management:** - Create and manage user profiles - Track user balances - Handle user relationships 2. **Group Management:** - Create and manage groups - Add/remove members - Track group expenses 3. **Expense Management:** - Add expenses to groups or individuals - Support different split types (EQUAL, EXACT, PERCENTAGE) - Track expense history 4. **Balance Management:** - Calculate balances between users - Track who owes whom - Handle settlements 5. **Transaction Management:** - Record transactions - Track payment status - Generate balance reports --- ## Core Entities ### 1. SplitwiseService - **Fields:** List users, List groups, List expenses - **Methods:** - addUser() - createGroup() - addExpense() - getBalance() - settleExpense() ### 2. User - **Fields:** String id, String name, String email, Map balances - **Methods:** - updateProfile() - getBalance() - addBalance() - subtractBalance() ### 3. Group - **Fields:** String id, String name, List members, List expenses - **Methods:** - addMember() - removeMember() - addExpense() - getBalances() ### 4. Expense - **Fields:** String id, String description, double amount, User paidBy, List paidFor, SplitType splitType - **Methods:** - calculateSplits() - getAmount() - getPaidBy() ### 5. Transaction - **Fields:** String id, User from, User to, double amount - **Methods:** - execute() - getStatus() ### 6. SplitType (Enum) - **Values:** EQUAL, EXACT, PERCENTAGE ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/splitwise-class-diagram.png) --- ## Example Usage ```java SplitwiseService service = new SplitwiseService(); // Create users User user1 = service.addUser("John", "john@example.com"); User user2 = service.addUser("Jane", "jane@example.com"); // Create a group Group group = service.createGroup("Trip to Paris"); group.addMember(user1); group.addMember(user2); // Add an expense Expense expense = service.addExpense( "Dinner", 100.0, user1, Arrays.asList(user1, user2), SplitType.EQUAL ); // Get balances double balance = service.getBalance(user1, user2); // Settle expense service.settleExpense(user2, user1, 50.0); ``` --- ## Demo See `SplitwiseDemo.java` for a sample usage and simulation of the Splitwise system. --- ## Extending the Framework - **Add expense categories:** Categorize expenses (food, travel, etc.) - **Add recurring expenses:** Support for regular payments - **Add expense comments:** Allow users to add notes to expenses - **Add expense attachments:** Support for receipts and documents - **Add payment integration:** Integrate with payment gateways - **Add notification system:** Send reminders for pending payments --- ## Design Patterns Used - **Singleton Pattern:** For the Splitwise service instance - **Factory Pattern:** For creating different types of splits - **Strategy Pattern:** For different expense splitting strategies - **Observer Pattern:** For balance updates and notifications --- ## Exception Handling - **InvalidAmountException:** Thrown when expense amount is invalid - **InvalidSplitException:** Thrown when split details are invalid - **UserNotFoundException:** Thrown when user is not found - **GroupNotFoundException:** Thrown when group is not found - **InsufficientBalanceException:** Thrown when user has insufficient balance --- ================================================ FILE: solutions/java/src/splitwise/SplitwiseDemo.java ================================================ package splitwise; import splitwise.entities.Expense; import splitwise.entities.Group; import splitwise.entities.Transaction; import splitwise.entities.User; import splitwise.strategy.EqualSplitStrategy; import splitwise.strategy.ExactSplitStrategy; import splitwise.strategy.PercentageSplitStrategy; import java.util.Arrays; import java.util.List; public class SplitwiseDemo { public static void main(String[] args) { // 1. Setup the service SplitwiseService service = SplitwiseService.getInstance(); // 2. Create users and groups User alice = service.addUser("Alice", "alice@a.com"); User bob = service.addUser( "Bob", "bob@b.com"); User charlie = service.addUser("Charlie", "charlie@c.com"); User david = service.addUser("David", "david@d.com"); Group friendsGroup = service.addGroup("Friends Trip", List.of(alice, bob, charlie, david)); System.out.println("--- System Setup Complete ---\n"); // 3. Use Case 1: Equal Split System.out.println("--- Use Case 1: Equal Split ---"); service.createExpense(new Expense.ExpenseBuilder() .setDescription("Dinner") .setAmount(1000) .setPaidBy(alice) .setParticipants(Arrays.asList(alice, bob, charlie, david)) .setSplitStrategy(new EqualSplitStrategy()) ); service.showBalanceSheet(alice.getId()); service.showBalanceSheet(bob.getId()); System.out.println(); // 4. Use Case 2: Exact Split System.out.println("--- Use Case 2: Exact Split ---"); service.createExpense(new Expense.ExpenseBuilder() .setDescription("Movie Tickets") .setAmount(370) .setPaidBy(alice) .setParticipants(Arrays.asList(bob, charlie)) .setSplitStrategy(new ExactSplitStrategy()) .setSplitValues(Arrays.asList(120.0, 250.0)) ); service.showBalanceSheet(alice.getId()); service.showBalanceSheet(bob.getId()); System.out.println(); // 5. Use Case 3: Percentage Split System.out.println("--- Use Case 3: Percentage Split ---"); service.createExpense(new Expense.ExpenseBuilder() .setDescription("Groceries") .setAmount(500) .setPaidBy(david) .setParticipants(Arrays.asList(alice, bob, charlie)) .setSplitStrategy(new PercentageSplitStrategy()) .setSplitValues(Arrays.asList(40.0, 30.0, 30.0)) // 40%, 30%, 30% ); System.out.println("--- Balances After All Expenses ---"); service.showBalanceSheet(alice.getId()); service.showBalanceSheet(bob.getId()); service.showBalanceSheet(charlie.getId()); service.showBalanceSheet(david.getId()); System.out.println(); // 6. Use Case 4: Simplify Group Debts System.out.println("--- Use Case 4: Simplify Group Debts for 'Friends Trip' ---"); List simplifiedDebts = service.simplifyGroupDebts(friendsGroup.getId()); if (simplifiedDebts.isEmpty()) { System.out.println("All debts are settled within the group!"); } else { simplifiedDebts.forEach(System.out::println); } System.out.println(); service.showBalanceSheet(bob.getId()); // 7. Use Case 5: Partial Settlement System.out.println("--- Use Case 5: Partial Settlement ---"); // From the simplified debts, we see Bob should pay Alice. Let's say Bob pays 100. service.settleUp(bob.getId(), alice.getId(), 100); System.out.println("--- Balances After Partial Settlement ---"); service.showBalanceSheet(alice.getId()); service.showBalanceSheet(bob.getId()); } } ================================================ FILE: solutions/java/src/splitwise/SplitwiseService.java ================================================ package splitwise; import splitwise.entities.*; import java.util.*; import java.util.stream.Collectors; public class SplitwiseService { private static SplitwiseService instance; private final Map users = new HashMap<>(); private final Map groups = new HashMap<>(); private SplitwiseService() {} public static synchronized SplitwiseService getInstance() { if (instance == null) { instance = new SplitwiseService(); } return instance; } // --- Setup Methods --- public User addUser(String name, String email) { User user = new User(name, email); users.put(user.getId(), user); return user; } public Group addGroup(String name, List members) { Group group = new Group(name, members); groups.put(group.getId(), group); return group; } public User getUser(String id) { return users.get(id); } public Group getGroup(String id) { return groups.get(id); } // --- Core Functional Methods (Facade) --- public synchronized void createExpense(Expense.ExpenseBuilder builder) { Expense expense = builder.build(); User paidBy = expense.getPaidBy(); for (Split split : expense.getSplits()) { User participant = split.getUser(); double amount = split.getAmount(); if (!paidBy.equals(participant)) { paidBy.getBalanceSheet().adjustBalance(participant, amount); participant.getBalanceSheet().adjustBalance(paidBy, -amount); } } System.out.println("Expense '" + expense.getDescription() + "' of amount " + expense.getAmount() + " created."); } public synchronized void settleUp(String payerId, String payeeId, double amount) { User payer = users.get(payerId); User payee = users.get(payeeId); System.out.println(payer.getName() + " is settling up " + amount + " with " + payee.getName()); // Settlement is like a reverse expense. payer owes less to payee. payee.getBalanceSheet().adjustBalance(payer, -amount); payer.getBalanceSheet().adjustBalance(payee, amount); } public void showBalanceSheet(String userId) { User user = users.get(userId); user.getBalanceSheet().showBalances(); } public List simplifyGroupDebts(String groupId) { Group group = groups.get(groupId); if (group == null) throw new IllegalArgumentException("Group not found"); // Calculate net balance for each member within the group context Map netBalances = new HashMap<>(); for (User member : group.getMembers()) { double balance = 0; for(Map.Entry entry : member.getBalanceSheet().getBalances().entrySet()) { // Consider only balances with other group members if (group.getMembers().contains(entry.getKey())) { balance += entry.getValue(); } } netBalances.put(member, balance); } // Separate into creditors and debtors List> creditors = netBalances.entrySet().stream() .filter(e -> e.getValue() > 0).collect(Collectors.toList()); List> debtors = netBalances.entrySet().stream() .filter(e -> e.getValue() < 0).collect(Collectors.toList()); creditors.sort(Map.Entry.comparingByValue(Comparator.reverseOrder())); debtors.sort(Map.Entry.comparingByValue()); List transactions = new ArrayList<>(); int i = 0, j = 0; while (i < creditors.size() && j < debtors.size()) { Map.Entry creditor = creditors.get(i); Map.Entry debtor = debtors.get(j); double amountToSettle = Math.min(creditor.getValue(), -debtor.getValue()); transactions.add(new Transaction(debtor.getKey(), creditor.getKey(), amountToSettle)); creditor.setValue(creditor.getValue() - amountToSettle); debtor.setValue(debtor.getValue() + amountToSettle); if (Math.abs(creditor.getValue()) < 0.01) i++; if (Math.abs(debtor.getValue()) < 0.01) j++; } return transactions; } } ================================================ FILE: solutions/java/src/splitwise/entities/BalanceSheet.java ================================================ package splitwise.entities; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class BalanceSheet { private final User owner; // A map where: // Key: The user to whom the balance is related. // Value: The net amount. // - Positive value: The key-user owes the owner of this balance sheet money. // - Negative value: The owner owes the key-user money. private final Map balances = new ConcurrentHashMap<>(); public BalanceSheet(User owner) { this.owner = owner; } public Map getBalances() { return balances; } public synchronized void adjustBalance(User otherUser, double amount) { if (owner.equals(otherUser)) { return; // Cannot owe yourself } balances.merge(otherUser, amount, Double::sum); } public void showBalances() { System.out.println("--- Balance Sheet for " + owner.getName() + " ---"); if (balances.isEmpty()) { System.out.println("All settled up!"); return; } double totalOwedToMe = 0; double totalIOwe = 0; for (Map.Entry entry : balances.entrySet()) { User otherUser = entry.getKey(); double amount = entry.getValue(); if (amount > 0.01) { System.out.println(otherUser.getName() + " owes " + owner.getName() + " $" + String.format("%.2f", amount)); totalOwedToMe += amount; } else if (amount < -0.01) { System.out.println(owner.getName() + " owes " + otherUser.getName() + " $" + String.format("%.2f", -amount)); totalIOwe += (-amount); } } System.out.println("Total Owed to " + owner.getName() + ": $" + String.format("%.2f", totalOwedToMe)); System.out.println("Total " + owner.getName() + " Owes: $" + String.format("%.2f", totalIOwe)); System.out.println("---------------------------------"); } } ================================================ FILE: solutions/java/src/splitwise/entities/Expense.java ================================================ package splitwise.entities; import splitwise.strategy.SplitStrategy; import java.time.LocalDateTime; import java.util.List; public class Expense { private final String id; private final String description; private final double amount; private final User paidBy; private final List splits; private final LocalDateTime timestamp; private Expense(ExpenseBuilder builder) { this.id = builder.id; this.description = builder.description; this.amount = builder.amount; this.paidBy = builder.paidBy; this.timestamp = LocalDateTime.now(); // Use the strategy to calculate splits this.splits = builder.splitStrategy.calculateSplits(builder.amount, builder.paidBy, builder.participants, builder.splitValues); } // Getters... public String getId() { return id; } public String getDescription() { return description; } public double getAmount() { return amount; } public User getPaidBy() { return paidBy; } public List getSplits() { return splits; } // --- Builder Pattern --- public static class ExpenseBuilder { private String id; private String description; private double amount; private User paidBy; private List participants; private SplitStrategy splitStrategy; private List splitValues; // For EXACT and PERCENTAGE splits public ExpenseBuilder setId(String id) { this.id = id; return this; } public ExpenseBuilder setDescription(String description) { this.description = description; return this; } public ExpenseBuilder setAmount(double amount) { this.amount = amount; return this; } public ExpenseBuilder setPaidBy(User paidBy) { this.paidBy = paidBy; return this; } public ExpenseBuilder setParticipants(List participants) { this.participants = participants; return this; } public ExpenseBuilder setSplitStrategy(SplitStrategy splitStrategy) { this.splitStrategy = splitStrategy; return this; } public ExpenseBuilder setSplitValues(List splitValues) { this.splitValues = splitValues; return this; } public Expense build() { // Validations if (splitStrategy == null) { throw new IllegalStateException("Split strategy is required."); } return new Expense(this); } } } ================================================ FILE: solutions/java/src/splitwise/entities/Group.java ================================================ package splitwise.entities; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class Group { private final String id; private final String name; private final List members; public Group(String name, List members) { this.id = UUID.randomUUID().toString(); this.name = name; this.members = members; } public String getId() { return id; } public String getName() { return name; } public List getMembers() { return new ArrayList<>(members); } } ================================================ FILE: solutions/java/src/splitwise/entities/Split.java ================================================ package splitwise.entities; public class Split { private final User user; private final double amount; public Split(User user, double amount) { this.user = user; this.amount = amount; } public User getUser() { return user; } public double getAmount() { return amount; } } ================================================ FILE: solutions/java/src/splitwise/entities/Transaction.java ================================================ package splitwise.entities; public class Transaction { private final User from; private final User to; private final double amount; public Transaction(User from, User to, double amount) { this.from = from; this.to = to; this.amount = amount; } @Override public String toString() { return from.getName() + " should pay " + to.getName() + " $" + String.format("%.2f", amount); } } ================================================ FILE: solutions/java/src/splitwise/entities/User.java ================================================ package splitwise.entities; import java.util.UUID; public class User { private final String id; private final String name; private final String email; private final BalanceSheet balanceSheet; public User(String name, String email) { this.id = UUID.randomUUID().toString();; this.name = name; this.email = email; this.balanceSheet = new BalanceSheet(this); } public String getId() { return id; } public String getName() { return name; } public BalanceSheet getBalanceSheet() { return balanceSheet; } } ================================================ FILE: solutions/java/src/splitwise/strategy/EqualSplitStrategy.java ================================================ package splitwise.strategy; import splitwise.entities.Split; import splitwise.entities.User; import java.util.ArrayList; import java.util.List; public class EqualSplitStrategy implements SplitStrategy { @Override public List calculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { List splits = new ArrayList<>(); double amountPerPerson = totalAmount / participants.size(); for (User participant : participants) { splits.add(new Split(participant, amountPerPerson)); } return splits; } } ================================================ FILE: solutions/java/src/splitwise/strategy/ExactSplitStrategy.java ================================================ package splitwise.strategy; import splitwise.entities.Split; import splitwise.entities.User; import java.util.ArrayList; import java.util.List; public class ExactSplitStrategy implements SplitStrategy { @Override public List calculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { if (participants.size() != splitValues.size()) { throw new IllegalArgumentException("Number of participants and split values must match."); } if (Math.abs(splitValues.stream().mapToDouble(Double::doubleValue).sum() - totalAmount) > 0.01) { throw new IllegalArgumentException("Sum of exact amounts must equal the total expense amount."); } List splits = new ArrayList<>(); for (int i = 0; i < participants.size(); i++) { splits.add(new Split(participants.get(i), splitValues.get(i))); } return splits; } } ================================================ FILE: solutions/java/src/splitwise/strategy/PercentageSplitStrategy.java ================================================ package splitwise.strategy; import splitwise.entities.Split; import splitwise.entities.User; import java.util.ArrayList; import java.util.List; public class PercentageSplitStrategy implements SplitStrategy { @Override public List calculateSplits(double totalAmount, User paidBy, List participants, List splitValues) { if (participants.size() != splitValues.size()) { throw new IllegalArgumentException("Number of participants and split values must match."); } if (Math.abs(splitValues.stream().mapToDouble(Double::doubleValue).sum() - 100.0) > 0.01) { throw new IllegalArgumentException("Sum of percentages must be 100."); } List splits = new ArrayList<>(); for (int i = 0; i < participants.size(); i++) { double amount = (totalAmount * splitValues.get(i)) / 100.0; splits.add(new Split(participants.get(i), amount)); } return splits; } } ================================================ FILE: solutions/java/src/splitwise/strategy/SplitStrategy.java ================================================ package splitwise.strategy; import splitwise.entities.Split; import splitwise.entities.User; import java.util.List; public interface SplitStrategy { List calculateSplits(double totalAmount, User paidBy, List participants, List splitValues); } ================================================ FILE: solutions/java/src/stackoverflow/README.md ================================================ # StackOverflow System (LLD) ## Problem Statement Design and implement a simplified StackOverflow-like Q&A platform. The system should allow users to post questions and answers, vote on them, comment, tag questions, and track user reputation. --- ## Requirements - **User Management:** Users can ask questions, answer, comment, and vote. - **Questions & Answers:** Users can post questions and answers. Each question can have multiple answers, and one accepted answer. - **Voting:** Users can upvote or downvote questions and answers. Reputation is updated accordingly. - **Comments:** Users can comment on both questions and answers. - **Tags:** Questions can be tagged for categorization. - **Reputation:** Users gain or lose reputation based on votes and accepted answers. - **Accepted Answer:** The question author can mark one answer as accepted. --- ## Core Entities - **User:** Represents a user, tracks reputation and user details. - **Question:** Represents a question, holds answers, comments, tags, votes, and accepted answer. - **Answer:** Represents an answer to a question, holds comments, votes, and accepted status. - **Comment:** Represents a comment on a question or answer. - **Tag:** Represents a tag for categorizing questions. - **Vote:** Represents a vote (upvote/downvote) by a user on a question or answer. - **VoteType:** Enum for UPVOTE and DOWNVOTE. - **Votable (interface):** For entities that can be voted on. - **Commentable (interface):** For entities that can be commented on. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/stackoverflow-class-diagram.png) ### 1. User - **Fields:** id, name, reputation, etc. - **Methods:** updateReputation(int delta), getReputation(), etc. ### 2. Question - **Fields:** id, title, content, author, creationDate, answers, comments, tags, votes, acceptedAnswer - **Methods:** addAnswer(Answer), acceptAnswer(Answer), vote(User, VoteType), getVoteCount(), addComment(Comment), getComments(), etc. ### 3. Answer - **Fields:** id, content, author, question, isAccepted, creationDate, comments, votes - **Methods:** vote(User, VoteType), getVoteCount(), addComment(Comment), getComments(), markAsAccepted(), etc. ### 4. Comment - **Fields:** id, content, author, creationDate ### 5. Tag - **Fields:** name ### 6. Vote - **Fields:** voter, type (VoteType) - **Methods:** getVoter(), getType() ### 7. VoteType - Enum: UPVOTE, DOWNVOTE ### 8. Votable (interface) - **Methods:** vote(User, VoteType), getVoteCount() ### 9. Commentable (interface) - **Methods:** addComment(Comment), getComments() --- ## Design Patterns Used - **Strategy Pattern:** For voting and commenting behaviors via interfaces. - **Observer Pattern:** (Conceptually) for reputation updates on votes and accepted answers. --- ## Example Usage ```java User alice = new User("Alice"); Question q = new Question(alice, "What is Java?", "Explain Java basics.", Arrays.asList("java", "basics")); User bob = new User("Bob"); Answer a = new Answer(bob, q, "Java is a programming language."); q.addAnswer(a); q.vote(bob, VoteType.UPVOTE); a.vote(alice, VoteType.UPVOTE); q.acceptAnswer(a); ``` --- ## Demo See `StackOverflowDemo.java` for a sample usage of the StackOverflow system. --- ## Extending the Framework - **Add new features:** Such as badges, user profiles, or advanced search. - **Add new vote types:** Extend `VoteType` and update logic in `vote()` methods. - **Add moderation:** Implement admin/moderator roles for content management. --- ================================================ FILE: solutions/java/src/stackoverflow/StackOverflowDemo.java ================================================ package stackoverflow; import stackoverflow.enums.VoteType; import stackoverflow.entities.Answer; import stackoverflow.entities.Question; import stackoverflow.entities.Tag; import stackoverflow.entities.User; import stackoverflow.strategy.SearchStrategy; import stackoverflow.strategy.TagSearchStrategy; import stackoverflow.strategy.UserSearchStrategy; import java.util.List; import java.util.Set; public class StackOverflowDemo { public static void main(String[] args) { StackOverflowService service = new StackOverflowService(); // 1. Create Users User alice = service.createUser("Alice"); User bob = service.createUser("Bob"); User charlie = service.createUser("Charlie"); // 2. Alice posts a question System.out.println("--- Alice posts a question ---"); Tag javaTag = new Tag("java"); Tag designPatternsTag = new Tag("design-patterns"); Set tags = Set.of(javaTag, designPatternsTag); Question question = service.postQuestion(alice.getId(), "How to implement Observer Pattern?", "Details about Observer Pattern...", tags); printReputations(alice, bob, charlie); // 3. Bob and Charlie post answers System.out.println("\n--- Bob and Charlie post answers ---"); Answer bobAnswer = service.postAnswer(bob.getId(), question.getId(), "You can use the java.util.Observer interface."); Answer charlieAnswer = service.postAnswer(charlie.getId(), question.getId(), "A better way is to create your own Observer interface."); printReputations(alice, bob, charlie); // 4. Voting happens System.out.println("\n--- Voting Occurs ---"); service.voteOnPost(alice.getId(), question.getId(), VoteType.UPVOTE); // Alice upvotes her own question service.voteOnPost(bob.getId(), charlieAnswer.getId(), VoteType.UPVOTE); // Bob upvotes Charlie's answer service.voteOnPost(alice.getId(), bobAnswer.getId(), VoteType.DOWNVOTE); // Alice downvotes Bob's answer printReputations(alice, bob, charlie); // 5. Alice accepts Charlie's answer System.out.println("\n--- Alice accepts Charlie's answer ---"); service.acceptAnswer(question.getId(), charlieAnswer.getId()); printReputations(alice, bob, charlie); // 6. Search for questions System.out.println("\n--- (C) Combined Search: Questions by 'Alice' with tag 'java' ---"); List filtersC = List.of( new UserSearchStrategy(alice), new TagSearchStrategy(javaTag) ); List searchResults = service.searchQuestions(filtersC); searchResults.forEach(q -> System.out.println(" - Found: " + q.getTitle())); } private static void printReputations(User... users) { System.out.println("--- Current Reputations ---"); for(User user : users) { System.out.printf("%s: %d\n", user.getName(), user.getReputation()); } } } ================================================ FILE: solutions/java/src/stackoverflow/StackOverflowService.java ================================================ package stackoverflow; import stackoverflow.enums.VoteType; import stackoverflow.entities.*; import stackoverflow.observer.PostObserver; import stackoverflow.observer.ReputationManager; import stackoverflow.strategy.SearchStrategy; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class StackOverflowService { private final Map users = new ConcurrentHashMap<>(); private final Map questions = new ConcurrentHashMap<>(); private final Map answers = new ConcurrentHashMap<>(); private final PostObserver reputationManager = new ReputationManager(); public User createUser(String name) { User user = new User(name); users.put(user.getId(), user); return user; } public Question postQuestion(String userId, String title, String body, Set tags) { User author = users.get(userId); Question question = new Question(title, body, author, tags); question.addObserver(reputationManager); questions.put(question.getId(), question); return question; } public Answer postAnswer(String userId, String questionId, String body) { User author = users.get(userId); Question question = questions.get(questionId); Answer answer = new Answer(body, author); answer.addObserver(reputationManager); question.addAnswer(answer); answers.put(answer.getId(), answer); return answer; } public void voteOnPost(String userId, String postId, VoteType voteType) { User user = users.get(userId); Post post = findPostById(postId); post.vote(user, voteType); } public void acceptAnswer(String questionId, String answerId) { Question question = questions.get(questionId); Answer answer = answers.get(answerId); question.acceptAnswer(answer); } public List searchQuestions(List strategies) { List results = new ArrayList<>(questions.values()); // Sequentially apply each filter strategy to the results of the previous one. for (SearchStrategy strategy : strategies) { results = strategy.filter(results); } return results; } public User getUser(String userId) { return users.get(userId); } private Post findPostById(String postId) { if (questions.containsKey(postId)) { return questions.get(postId); } else if (answers.containsKey(postId)) { return answers.get(postId); } throw new NoSuchElementException("Post not found"); } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Answer.java ================================================ package stackoverflow.entities; import java.util.UUID; public class Answer extends Post { private boolean isAccepted = false; public Answer(String body, User author) { super(UUID.randomUUID().toString(), body, author); } public void setAccepted(boolean accepted) { isAccepted = accepted; } public boolean isAccepted() { return isAccepted; } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Comment.java ================================================ package stackoverflow.entities; import java.util.UUID; public class Comment extends Content { public Comment(String body, User author) { super(UUID.randomUUID().toString(), body, author); } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Content.java ================================================ package stackoverflow.entities; import java.time.LocalDateTime; public abstract class Content { protected final String id; protected final String body; protected final User author; protected final LocalDateTime creationTime; public Content(String id, String body, User author) { this.id = id; this.body = body; this.author = author; this.creationTime = LocalDateTime.now(); } public String getId() { return id; } public String getBody() { return body; } public User getAuthor() { return author; } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Event.java ================================================ package stackoverflow.entities; import stackoverflow.enums.EventType; public class Event { private final EventType type; private final User actor; // user who performed the action private final Post targetPost; // post being acted on public Event(EventType type, User actor, Post targetPost) { this.type = type; this.actor = actor; this.targetPost = targetPost; } public EventType getType() { return type; } public User getActor() { return actor; } public Post getTargetPost() { return targetPost; } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Post.java ================================================ package stackoverflow.entities; import stackoverflow.enums.EventType; import stackoverflow.enums.VoteType; import stackoverflow.observer.PostObserver; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; public abstract class Post extends Content { private final AtomicInteger voteCount = new AtomicInteger(0); private final Map voters = new ConcurrentHashMap<>(); private final List comments = new CopyOnWriteArrayList<>(); private final List observers = new CopyOnWriteArrayList<>(); public Post(String id, String body, User author) { super(id, body, author); } public void addObserver(PostObserver observer) { this.observers.add(observer); } protected void notifyObservers(Event event) { observers.forEach(o -> o.onPostEvent(event)); } public synchronized void vote(User user, VoteType voteType) { String userId = user.getId(); if (voters.get(userId) == voteType) return; // Already voted int scoreChange = 0; if (voters.containsKey(userId)) { // User is changing their vote scoreChange = (voteType == VoteType.UPVOTE) ? 2 : -2; } else { // New vote scoreChange = (voteType == VoteType.UPVOTE) ? 1 : -1; } voters.put(userId, voteType); voteCount.addAndGet(scoreChange); EventType eventType = EventType.UPVOTE_QUESTION; if (this instanceof Question) { eventType = (voteType == VoteType.UPVOTE ? EventType.UPVOTE_QUESTION : EventType.DOWNVOTE_QUESTION); } else { eventType = (voteType == VoteType.UPVOTE ? EventType.UPVOTE_ANSWER : EventType.DOWNVOTE_ANSWER); } notifyObservers(new Event(eventType, user, this)); } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Question.java ================================================ package stackoverflow.entities; import stackoverflow.enums.EventType; import java.util.*; public class Question extends Post { private final String title; private final Set tags; private final List answers = new ArrayList<>(); private Answer acceptedAnswer; public Question(String title, String body, User author, Set tags) { super(UUID.randomUUID().toString(), body, author); this.title = title; this.tags = tags; } public void addAnswer(Answer answer) { this.answers.add(answer); } public synchronized void acceptAnswer(Answer answer) { if (!this.author.getId().equals(answer.getAuthor().getId()) && this.acceptedAnswer == null) { this.acceptedAnswer = answer; answer.setAccepted(true); notifyObservers(new Event(EventType.ACCEPT_ANSWER, answer.getAuthor(), answer)); } } public String getTitle() { return title; } public Set getTags() { return tags; } public List getAnswers() { return answers; } } ================================================ FILE: solutions/java/src/stackoverflow/entities/Tag.java ================================================ package stackoverflow.entities; public class Tag { private final String name; public Tag(String name) { this.name = name; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/stackoverflow/entities/User.java ================================================ package stackoverflow.entities; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; public class User { private final String id; private final String name; private final AtomicInteger reputation; public User(String name) { this.id = UUID.randomUUID().toString(); this.name = name; this.reputation = new AtomicInteger(0); } public void updateReputation(int change) { this.reputation.addAndGet(change); } public String getId() { return id; } public String getName() { return name; } public int getReputation() { return reputation.get(); } } ================================================ FILE: solutions/java/src/stackoverflow/enums/EventType.java ================================================ package stackoverflow.enums; public enum EventType { UPVOTE_QUESTION, DOWNVOTE_QUESTION, UPVOTE_ANSWER, DOWNVOTE_ANSWER, ACCEPT_ANSWER } ================================================ FILE: solutions/java/src/stackoverflow/enums/VoteType.java ================================================ package stackoverflow.enums; public enum VoteType { UPVOTE, DOWNVOTE } ================================================ FILE: solutions/java/src/stackoverflow/observer/PostObserver.java ================================================ package stackoverflow.observer; import stackoverflow.entities.Event; public interface PostObserver { void onPostEvent(Event event); } ================================================ FILE: solutions/java/src/stackoverflow/observer/ReputationManager.java ================================================ package stackoverflow.observer; import stackoverflow.entities.Event; import stackoverflow.entities.User; public class ReputationManager implements PostObserver { private static final int QUESTION_UPVOTE_REP = 5; private static final int ANSWER_UPVOTE_REP = 10; private static final int ACCEPTED_ANSWER_REP = 15; private static final int DOWNVOTE_REP_PENALTY = -1; // Penalty for the voter private static final int POST_DOWNVOTED_REP_PENALTY = -2; // Penalty for the post author @Override public void onPostEvent(Event event) { User postAuthor = event.getTargetPost().getAuthor(); switch (event.getType()) { case UPVOTE_QUESTION: postAuthor.updateReputation(QUESTION_UPVOTE_REP); break; case DOWNVOTE_QUESTION: postAuthor.updateReputation(DOWNVOTE_REP_PENALTY); event.getActor().updateReputation(POST_DOWNVOTED_REP_PENALTY); // voter penalty break; case UPVOTE_ANSWER: postAuthor.updateReputation(ANSWER_UPVOTE_REP); break; case DOWNVOTE_ANSWER: postAuthor.updateReputation(DOWNVOTE_REP_PENALTY); event.getActor().updateReputation(POST_DOWNVOTED_REP_PENALTY); break; case ACCEPT_ANSWER: postAuthor.updateReputation(ACCEPTED_ANSWER_REP); break; } } } ================================================ FILE: solutions/java/src/stackoverflow/strategy/KeywordSearchStrategy.java ================================================ package stackoverflow.strategy; import stackoverflow.entities.Question; import java.util.List; import java.util.stream.Collectors; public class KeywordSearchStrategy implements SearchStrategy { private final String keyword; public KeywordSearchStrategy(String keyword) { this.keyword = keyword.toLowerCase(); } @Override public List filter(List questions) { return questions.stream() .filter(q -> q.getTitle().toLowerCase().contains(keyword) || q.getBody().toLowerCase().contains(keyword)) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/stackoverflow/strategy/SearchStrategy.java ================================================ package stackoverflow.strategy; import stackoverflow.entities.Question; import java.util.List; public interface SearchStrategy { List filter(List questions); } ================================================ FILE: solutions/java/src/stackoverflow/strategy/TagSearchStrategy.java ================================================ package stackoverflow.strategy; import stackoverflow.entities.Question; import stackoverflow.entities.Tag; import java.util.List; import java.util.stream.Collectors; public class TagSearchStrategy implements SearchStrategy { private final Tag tag; public TagSearchStrategy(Tag tag) { this.tag = tag; } @Override public List filter(List questions) { return questions.stream() .filter(q -> q.getTags().stream() .anyMatch(t -> t.getName().equalsIgnoreCase(tag.getName()))) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/stackoverflow/strategy/UserSearchStrategy.java ================================================ package stackoverflow.strategy; import stackoverflow.entities.Question; import stackoverflow.entities.User; import java.util.List; import java.util.stream.Collectors; public class UserSearchStrategy implements SearchStrategy { private final User user; public UserSearchStrategy(User user) { this.user = user; } @Override public List filter(List questions) { return questions.stream() .filter(q -> q.getAuthor().getId().equals(user.getId())) .collect(Collectors.toList()); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/README.md ================================================ # Task Management System (LLD) ## Problem Statement Design and implement a Task Management System that allows users to create, assign, update, and track tasks. The system should support task priorities, statuses, comments, and user assignment. --- ## Requirements - **Task Creation:** Users can create tasks with a title, description, priority, and assignee. - **Task Assignment:** Tasks can be assigned to users and reassigned as needed. - **Task Status:** Tasks can have statuses such as TODO, IN_PROGRESS, DONE, etc. - **Task Priority:** Tasks can have priorities such as LOW, MEDIUM, HIGH. - **Comments:** Users can add comments to tasks. - **Task Updates:** Tasks can be updated (status, priority, assignee, etc.). - **Task Listing:** List all tasks, or filter by status, priority, or assignee. - **Extensibility:** Easy to add new statuses, priorities, or features. --- ## Core Entities - **Task:** Represents a task with title, description, status, priority, assignee, and comments. - **User:** Represents a user who can create, assign, and be assigned tasks. - **Comment:** Represents a comment on a task. - **TaskStatus:** Enum for task statuses (TODO, IN_PROGRESS, DONE, etc.). - **TaskPriority:** Enum for task priorities (LOW, MEDIUM, HIGH). - **TaskManager:** Manages the collection of tasks and provides methods for task operations. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/taskmanagementsystem-class-diagram.png) ### 1. Task - **Fields:** id, title, description, status, priority, assignee (User), List - **Methods:** updateStatus(TaskStatus), updatePriority(TaskPriority), assignUser(User), addComment(Comment), etc. ### 2. User - **Fields:** id, name - **Methods:** getId(), getName() ### 3. Comment - **Fields:** id, content, author (User), timestamp ### 4. TaskStatus (enum) - Values: TODO, IN_PROGRESS, DONE, etc. ### 5. TaskPriority (enum) - Values: LOW, MEDIUM, HIGH ### 6. TaskManager - **Fields:** List - **Methods:** createTask(...), assignTask(...), updateTaskStatus(...), updateTaskPriority(...), addCommentToTask(...), listTasks(), listTasksByStatus(...), listTasksByAssignee(...), etc. --- ## Design Patterns Used - **Separation of Concerns:** Each class has a single responsibility (task, user, comment, management). - **Manager Pattern:** `TaskManager` acts as a service/manager for all task operations. --- ## Example Usage ```java TaskManager manager = new TaskManager(); User alice = new User("Alice"); User bob = new User("Bob"); Task task = manager.createTask("Implement login", "Add login functionality", TaskPriority.HIGH, alice); manager.assignTask(task.getId(), bob); manager.updateTaskStatus(task.getId(), TaskStatus.IN_PROGRESS); manager.addCommentToTask(task.getId(), new Comment("Started working on this", bob)); ``` --- ## Demo See `TaskManagementSystemDemo.java` for a sample usage and simulation of the task management system. --- ## Extending the Framework - **Add new statuses or priorities:** Update the `TaskStatus` or `TaskPriority` enums. - **Add new features:** Such as deadlines, notifications, or task dependencies. --- ================================================ FILE: solutions/java/src/taskmanagementsystem/TaskManagementSystem.java ================================================ package taskmanagementsystem; import taskmanagementsystem.enums.TaskPriority; import taskmanagementsystem.enums.TaskStatus; import taskmanagementsystem.models.Task; import taskmanagementsystem.models.TaskList; import taskmanagementsystem.models.User; import taskmanagementsystem.observer.ActivityLogger; import taskmanagementsystem.strategy.TaskSortStrategy; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class TaskManagementSystem { private static TaskManagementSystem instance; private final Map users; private final Map tasks; private final Map taskLists; private TaskManagementSystem() { users = new ConcurrentHashMap<>(); tasks = new ConcurrentHashMap<>(); taskLists = new ConcurrentHashMap<>(); } public static synchronized TaskManagementSystem getInstance() { if (instance == null) { instance = new TaskManagementSystem(); } return instance; } public User createUser(String name, String email) { User user = new User(name, email); users.put(user.getId(), user); return user; } public TaskList createTaskList(String listName) { TaskList taskList = new TaskList(listName); taskLists.put(taskList.getId(), taskList); return taskList; } public Task createTask(String title, String description, LocalDate dueDate, TaskPriority priority, String createdByUserId) { User createdBy = users.get(createdByUserId); if (createdBy == null) throw new IllegalArgumentException("User not found."); Task task = new Task.TaskBuilder(title) .description(description) .dueDate(dueDate) .priority(priority) .createdBy(createdBy) .build(); task.addObserver(new ActivityLogger()); tasks.put(task.getId(), task); return task; } public List listTasksByUser(String userId) { User user = users.get(userId); return tasks.values().stream() .filter(task -> user.equals(task.getAssignee())) .toList(); } public List listTasksByStatus(TaskStatus status) { return tasks.values().stream() .filter(task -> task.getStatus() == status) .collect(Collectors.toList()); } public void deleteTask(String taskId) { tasks.remove(taskId); } public List searchTasks(String keyword, TaskSortStrategy sortingStrategy) { List matchingTasks = new ArrayList<>(); for (Task task : tasks.values()) { if (task.getTitle().contains(keyword) || task.getDescription().contains(keyword)) { matchingTasks.add(task); } } sortingStrategy.sort(matchingTasks); return matchingTasks; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/TaskManagementSystemDemo.java ================================================ package taskmanagementsystem; import taskmanagementsystem.enums.TaskPriority; import taskmanagementsystem.enums.TaskStatus; import taskmanagementsystem.models.Task; import taskmanagementsystem.models.TaskList; import taskmanagementsystem.models.User; import taskmanagementsystem.strategy.SortByDueDate; import java.time.LocalDate; import java.util.List; public class TaskManagementSystemDemo { public static void main(String[] args) { TaskManagementSystem taskManagementSystem = TaskManagementSystem.getInstance(); // Create users User user1 = taskManagementSystem.createUser("John Doe", "john@example.com"); User user2 = taskManagementSystem.createUser("Jane Smith", "jane@example.com"); // Create task lists TaskList taskList1 = taskManagementSystem.createTaskList("Enhancements"); TaskList taskList2 = taskManagementSystem.createTaskList("Bug Fix"); // Create tasks Task task1 = taskManagementSystem.createTask("Enhancement Task", "Launch New Feature", LocalDate.now().plusDays(2), TaskPriority.LOW, user1.getId()); Task subtask1 = taskManagementSystem.createTask( "Enhancement sub task", "Design UI/UX", LocalDate.now().plusDays(1), TaskPriority.MEDIUM, user1.getId()); Task task2 = taskManagementSystem.createTask("Bug Fix Task", "Fix API Bug", LocalDate.now().plusDays(3), TaskPriority.HIGH, user2.getId()); task1.addSubtask(subtask1); taskList1.addTask(task1); taskList2.addTask(task2); taskList1.display(); // Update task status subtask1.startProgress(); // Assign task subtask1.setAssignee(user2); taskList1.display(); // Search tasks List searchResults = taskManagementSystem.searchTasks("Task", new SortByDueDate()); System.out.println("\nTasks with keyword Task:"); for (Task task : searchResults) { System.out.println(task.getTitle()); } // Filter tasks by status List filteredTasks = taskManagementSystem.listTasksByStatus(TaskStatus.TODO); System.out.println("\nTODO Tasks:"); for (Task task : filteredTasks) { System.out.println(task.getTitle()); } // Mark a task as done subtask1.completeTask(); // Get tasks assigned to a user List userTaskList = taskManagementSystem.listTasksByUser(user2.getId()); System.out.println("\nTask for " + user2.getName() + ":"); for (Task task : userTaskList) { System.out.println(task.getTitle()); } taskList1.display(); // Delete a task taskManagementSystem.deleteTask(task2.getId()); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/enums/TaskPriority.java ================================================ package taskmanagementsystem.enums; public enum TaskPriority { LOW, MEDIUM, HIGH, CRITICAL } ================================================ FILE: solutions/java/src/taskmanagementsystem/enums/TaskStatus.java ================================================ package taskmanagementsystem.enums; public enum TaskStatus { TODO, IN_PROGRESS, DONE } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/ActivityLog.java ================================================ package taskmanagementsystem.models; import java.time.LocalDateTime; public class ActivityLog { private final String description; private final LocalDateTime timestamp; public ActivityLog(String description) { this.description = description; this.timestamp = LocalDateTime.now(); } @Override public String toString() { return "[" + timestamp + "] " + description; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/Comment.java ================================================ package taskmanagementsystem.models; import java.util.Date; import java.util.UUID; public class Comment { private final String id; private final String content; private final User author; private final Date timestamp; public Comment(String content, User author) { this.id = UUID.randomUUID().toString(); this.content = content; this.author = author; this.timestamp = new Date(); } public User getAuthor() { return author; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/Tag.java ================================================ package taskmanagementsystem.models; public class Tag { private final String name; public Tag(String name) { this.name = name; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/Task.java ================================================ package taskmanagementsystem.models; import taskmanagementsystem.enums.TaskPriority; import taskmanagementsystem.enums.TaskStatus; import taskmanagementsystem.observer.TaskObserver; import taskmanagementsystem.state.TaskState; import taskmanagementsystem.state.TodoState; import java.time.LocalDate; import java.util.*; public class Task { private final String id; private String title; private String description; private LocalDate dueDate; private TaskPriority priority; private final User createdBy; private User assignee; private TaskState currentState; private final Set tags; private final List comments; private final List subtasks; private final List activityLogs; private final List observers; private Task(TaskBuilder builder) { this.id = builder.id; this.title = builder.title; this.description = builder.description; this.dueDate = builder.dueDate; this.priority = builder.priority; this.createdBy = builder.createdBy; this.assignee = builder.assignee; this.tags = builder.tags; this.currentState = new TodoState(); // Initial state this.comments = new ArrayList<>(); this.subtasks = new ArrayList<>(); this.activityLogs = new ArrayList<>(); this.observers = new ArrayList<>(); addLog("Task created with title: " + title); } public synchronized void setAssignee(User user) { this.assignee = user; addLog("Assigned to " + user.getName()); notifyObservers("assignee"); } public synchronized void updatePriority(TaskPriority priority) { this.priority = priority; notifyObservers("priority"); } public synchronized void addComment(Comment comment) { comments.add(comment); addLog("Comment added by " + comment.getAuthor().getName()); notifyObservers("comment"); } public synchronized void addSubtask(Task subtask) { subtasks.add(subtask); addLog("Subtask added: " + subtask.getTitle()); notifyObservers("subtask_added"); } // --- State Pattern Methods --- public void setState(TaskState state) { this.currentState = state; addLog("Status changed to: " + state.getStatus()); notifyObservers("status"); } public void startProgress() { currentState.startProgress(this); } public void completeTask() { currentState.completeTask(this); } public void reopenTask() { currentState.reopenTask(this); } // --- Observer Pattern Methods --- public void addObserver(TaskObserver observer) { observers.add(observer); } public void removeObserver(TaskObserver observer) { observers.remove(observer); } public void notifyObservers(String changeType) { for (TaskObserver observer : observers) { observer.update(this, changeType); } } public void addLog(String logDescription) { this.activityLogs.add(new ActivityLog(logDescription)); } public boolean isComposite() { return !subtasks.isEmpty(); } public void display(String indent) { System.out.println(indent + "- " + title + " [" + getStatus() + ", " + priority + ", Due: " + dueDate + "]"); if (isComposite()) { for (Task subtask : subtasks) { subtask.display(indent + " "); } } } // Getters and setters public String getId() { return id; } public String getTitle() { return title; } public String getDescription() { return description; } public TaskPriority getPriority() { return priority; } public LocalDate getDueDate() { return dueDate; } public User getAssignee() { return assignee; } public void setTitle(String title) { this.title = title; } public void setDescription(String description) { this.description = description; } public TaskStatus getStatus() { return currentState.getStatus(); } // --- Builder Pattern --- public static class TaskBuilder { private final String id; private String title; private String description = ""; private LocalDate dueDate; private TaskPriority priority; private User createdBy; private User assignee; private Set tags; public TaskBuilder(String title) { this.id = UUID.randomUUID().toString(); this.title = title; } public TaskBuilder description(String description) { this.description = description; return this; } public TaskBuilder dueDate(LocalDate dueDate) { this.dueDate = dueDate; return this; } public TaskBuilder priority(TaskPriority priority) { this.priority = priority; return this; } public TaskBuilder assignee(User assignee) { this.assignee = assignee; return this; } public TaskBuilder createdBy(User createdBy) { this.createdBy = createdBy; return this; } public TaskBuilder tags(Set tags) { this.tags = tags; return this; } public Task build() { return new Task(this); } } } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/TaskList.java ================================================ package taskmanagementsystem.models; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; public class TaskList { private final String id; private final String name; private final List tasks; public TaskList(String name) { this.id = UUID.randomUUID().toString(); this.name = name; this.tasks = new CopyOnWriteArrayList<>(); } public void addTask(Task task) { this.tasks.add(task); } public List getTasks() { return new ArrayList<>(tasks); // Return a copy to prevent external modification } // Getters... public String getId() { return id; } public String getName() { return name; } public void display() { System.out.println("--- Task List: " + name + " ---"); for (Task task : tasks) { task.display(""); } System.out.println("-----------------------------------"); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/models/User.java ================================================ package taskmanagementsystem.models; import java.util.UUID; public class User { private final String id; private final String name; private final String email; public User(String name, String email) { this.id = UUID.randomUUID().toString(); this.name = name; this.email = email; } // Getters... public String getId() { return id; } public String getEmail() { return email; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/observer/ActivityLogger.java ================================================ package taskmanagementsystem.observer; import taskmanagementsystem.models.Task; public class ActivityLogger implements TaskObserver { @Override public void update(Task task, String changeType) { System.out.println("LOGGER: Task '" + task.getTitle() + "' was updated. Change: " + changeType); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/observer/TaskObserver.java ================================================ package taskmanagementsystem.observer; import taskmanagementsystem.models.Task; public interface TaskObserver { void update(Task task, String changeType); } ================================================ FILE: solutions/java/src/taskmanagementsystem/state/DoneState.java ================================================ package taskmanagementsystem.state; import taskmanagementsystem.models.Task; import taskmanagementsystem.enums.TaskStatus; public class DoneState implements TaskState { @Override public void startProgress(Task task) { System.out.println("Cannot start a completed task. Reopen it first."); } @Override public void completeTask(Task task) { System.out.println("Task is already done."); } @Override public void reopenTask(Task task) { task.setState(new TodoState()); } @Override public TaskStatus getStatus() { return TaskStatus.DONE; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/state/InProgressState.java ================================================ package taskmanagementsystem.state; import taskmanagementsystem.models.Task; import taskmanagementsystem.enums.TaskStatus; public class InProgressState implements TaskState { @Override public void startProgress(Task task) { System.out.println("Task is already in progress."); } @Override public void completeTask(Task task) { task.setState(new DoneState()); } @Override public void reopenTask(Task task) { task.setState(new TodoState()); } @Override public TaskStatus getStatus() { return TaskStatus.IN_PROGRESS; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/state/TaskState.java ================================================ package taskmanagementsystem.state; import taskmanagementsystem.models.Task; import taskmanagementsystem.enums.TaskStatus; public interface TaskState { void startProgress(Task task); void completeTask(Task task); void reopenTask(Task task); TaskStatus getStatus(); } ================================================ FILE: solutions/java/src/taskmanagementsystem/state/TodoState.java ================================================ package taskmanagementsystem.state; import taskmanagementsystem.models.Task; import taskmanagementsystem.enums.TaskStatus; public class TodoState implements TaskState { @Override public void startProgress(Task task) { task.setState(new InProgressState()); } @Override public void completeTask(Task task) { System.out.println("Cannot complete a task that is not in progress."); } @Override public void reopenTask(Task task) { System.out.println("Task is already in TO-DO state."); } @Override public TaskStatus getStatus() { return TaskStatus.TODO; } } ================================================ FILE: solutions/java/src/taskmanagementsystem/strategy/SortByDueDate.java ================================================ package taskmanagementsystem.strategy; import taskmanagementsystem.models.Task; import java.util.Comparator; import java.util.List; public class SortByDueDate implements TaskSortStrategy { @Override public void sort(List tasks) { tasks.sort(Comparator.comparing(Task::getDueDate)); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/strategy/SortByPriority.java ================================================ package taskmanagementsystem.strategy; import taskmanagementsystem.models.Task; import java.util.Comparator; import java.util.List; public class SortByPriority implements TaskSortStrategy { @Override public void sort(List tasks) { // Higher priority (lower enum ordinal) comes first tasks.sort(Comparator.comparing(Task::getPriority).reversed()); } } ================================================ FILE: solutions/java/src/taskmanagementsystem/strategy/TaskSortStrategy.java ================================================ package taskmanagementsystem.strategy; import taskmanagementsystem.models.Task; import java.util.List; public interface TaskSortStrategy { void sort(List tasks); } ================================================ FILE: solutions/java/src/tictactoe/Game.java ================================================ package tictactoe; import tictactoe.enums.GameStatus; import tictactoe.models.Board; import tictactoe.models.Player; import tictactoe.observer.GameSubject; import tictactoe.state.GameState; import tictactoe.state.InProgressState; import tictactoe.strategy.ColumnWinningStrategy; import tictactoe.strategy.DiagonalWinningStrategy; import tictactoe.strategy.RowWinningStrategy; import tictactoe.strategy.WinningStrategy; import java.util.List; public class Game extends GameSubject { private final Board board; private final Player player1; private final Player player2; private Player currentPlayer; private Player winner; private GameStatus status; private GameState state; private final List winningStrategies; public Game(Player player1, Player player2) { this.board = new Board(3); this.player1 = player1; this.player2 = player2; this.currentPlayer = player1; // Player 1 starts this.status = GameStatus.IN_PROGRESS; this.state = new InProgressState(); this.winningStrategies = List.of( new RowWinningStrategy(), new ColumnWinningStrategy(), new DiagonalWinningStrategy() ); } public void makeMove(Player player, int row, int col) { state.handleMove(this, player, row, col); } public boolean checkWinner(Player player) { for (WinningStrategy strategy : winningStrategies) { if (strategy.checkWinner(board, player)) { return true; } } return false; } public void switchPlayer() { this.currentPlayer = (currentPlayer == player1) ? player2 : player1; } public Board getBoard() { return board; } public Player getCurrentPlayer() { return currentPlayer; } public Player getWinner() { return winner; } public void setWinner(Player winner) { this.winner = winner; } public GameStatus getStatus() { return status; } public void setState(GameState state) { this.state = state; } public void setStatus(GameStatus status) { this.status = status; // Notify observers when the status changes to a finished state if (status != GameStatus.IN_PROGRESS) { notifyObservers(); } } } ================================================ FILE: solutions/java/src/tictactoe/README.md ================================================ # Tic Tac Toe (LLD) ## Problem Statement Design and implement a Tic Tac Toe game that allows two players to play on a NxN board, alternating turns, and determines the winner or a draw. --- ## Requirements - **Two Players:** The game is played between two players. - **Board:** The game uses a NxN board. - **Turns:** Players take turns to place their symbol (X or O) on the board. - **Win Condition:** The game detects when a player has won (three in a row, column, or diagonal). - **Draw Condition:** The game detects when the board is full and the game is a draw. - **Input Validation:** The game prevents moves to already occupied cells. - **Extensibility:** Easy to change the board size or add new features. --- ## Core Entities - **Game:** Manages the game flow, player turns, and game status. - **Board:** Represents the NxN grid and provides methods to update and check the board. - **Cell:** Represents a single cell on the board. - **Player:** Represents a player with a name and symbol. - **Symbol:** Enum for X and O. - **GameStatus:** Enum for IN_PROGRESS, DRAW, WIN. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/tictactoe-class-diagram.png) ### 1. Game - **Fields:** Board board, Player[] players, int currentPlayerIndex, GameStatus status - **Methods:** play(), makeMove(int row, int col), checkWin(), checkDraw(), switchPlayer(), getCurrentPlayer() ### 2. Board - **Fields:** Cell[][] grid, int size - **Methods:** isCellEmpty(int row, int col), setCell(int row, int col, Symbol), printBoard(), isFull(), checkWin(Symbol) ### 3. Cell - **Fields:** int row, int col, Symbol symbol - **Methods:** getSymbol(), setSymbol(Symbol) ### 4. Player - **Fields:** String name, Symbol symbol ### 5. Symbol (enum) - Values: X, O ### 6. GameStatus (enum) - Values: IN_PROGRESS, DRAW, WIN --- ## Example Usage ```java Player p1 = new Player("Alice", Symbol.X); Player p2 = new Player("Bob", Symbol.O); Game game = new Game(p1, p2); game.play(); ``` --- ## Demo See `TicTacToeDemo.java` for a sample usage and simulation of the Tic Tac Toe game. --- ## Extending the Design - **Change board size:** Update the `Board` class to support different sizes. - **Add AI player:** Implement a computer player for single-player mode. - **Add GUI:** Build a graphical interface for the game. --- ================================================ FILE: solutions/java/src/tictactoe/TicTacToeDemo.java ================================================ package tictactoe; import tictactoe.enums.Symbol; import tictactoe.models.Player; public class TicTacToeDemo { public static void main(String[] args) { TicTacToeSystem system = TicTacToeSystem.getInstance(); Player alice = new Player("Alice", Symbol.X); Player bob = new Player("Bob", Symbol.O); // --- GAME 1: Alice wins --- System.out.println("--- GAME 1: Alice (X) vs. Bob (O) ---"); system.createGame(alice, bob); system.printBoard(); system.makeMove(alice, 0, 0); system.makeMove(bob, 1, 0); system.makeMove(alice, 0, 1); system.makeMove(bob, 1, 1); system.makeMove(alice, 0, 2); // Alice wins, scoreboard is notified System.out.println("----------------------------------------\n"); // --- GAME 2: Bob wins --- System.out.println("--- GAME 2: Alice (X) vs. Bob (O) ---"); system.createGame(alice, bob); // A new game instance system.printBoard(); system.makeMove(alice, 0, 0); system.makeMove(bob, 1, 0); system.makeMove(alice, 0, 1); system.makeMove(bob, 1, 1); system.makeMove(alice, 2, 2); system.makeMove(bob, 1, 2); // Bob wins, scoreboard is notified System.out.println("----------------------------------------\n"); // --- GAME 3: A Draw --- System.out.println("--- GAME 3: Alice (X) vs. Bob (O) - Draw ---"); system.createGame(alice, bob); system.printBoard(); system.makeMove(alice, 0, 0); system.makeMove(bob, 0, 1); system.makeMove(alice, 0, 2); system.makeMove(bob, 1, 1); system.makeMove(alice, 1, 0); system.makeMove(bob, 1, 2); system.makeMove(alice, 2, 1); system.makeMove(bob, 2, 0); system.makeMove(alice, 2, 2); // Draw, scoreboard is not notified of a winner System.out.println("----------------------------------------\n"); // --- Final Scoreboard --- // We get the scoreboard from the system and print its final state system.printScoreBoard(); } } ================================================ FILE: solutions/java/src/tictactoe/TicTacToeSystem.java ================================================ package tictactoe; import tictactoe.exceptions.InvalidMoveException; import tictactoe.models.Player; import tictactoe.observer.Scoreboard; public class TicTacToeSystem { private static volatile TicTacToeSystem instance; private Game game; private final Scoreboard scoreboard; // The system now manages a scoreboard private TicTacToeSystem() { this.scoreboard = new Scoreboard(); // Create the scoreboard on initialization } public static synchronized TicTacToeSystem getInstance() { if (instance == null) { instance = new TicTacToeSystem(); } return instance; } public void createGame(Player player1, Player player2) { this.game = new Game(player1, player2); // Register the scoreboard as an observer for this new game this.game.addObserver(this.scoreboard); System.out.printf("Game started between %s (X) and %s (O).%n", player1.getName(), player2.getName()); } public void makeMove(Player player, int row, int col) { if (game == null) { System.out.println("No game in progress. Please create a game first."); return; } try { System.out.printf("%s plays at (%d, %d)%n", player.getName(), row, col); game.makeMove(player, row, col); printBoard(); System.out.println("Game Status: " + game.getStatus()); if (game.getWinner() != null) { System.out.println("Winner: " + game.getWinner().getName()); } } catch (InvalidMoveException e) { System.out.println("Error: " + e.getMessage()); } } public void printBoard() { game.getBoard().printBoard(); } public void printScoreBoard() { scoreboard.printScores(); } } ================================================ FILE: solutions/java/src/tictactoe/enums/GameStatus.java ================================================ package tictactoe.enums; public enum GameStatus { IN_PROGRESS, WINNER_X, WINNER_O, DRAW } ================================================ FILE: solutions/java/src/tictactoe/enums/Symbol.java ================================================ package tictactoe.enums; public enum Symbol { X('X'), O('O'), EMPTY('_'); private final char symbol; Symbol(char symbol) { this.symbol = symbol; } public char getChar() { return symbol; } } ================================================ FILE: solutions/java/src/tictactoe/exceptions/InvalidMoveException.java ================================================ package tictactoe.exceptions; public class InvalidMoveException extends RuntimeException { public InvalidMoveException(String message) { super(message); } } ================================================ FILE: solutions/java/src/tictactoe/models/Board.java ================================================ package tictactoe.models; import tictactoe.enums.Symbol; import tictactoe.exceptions.InvalidMoveException; public class Board { private final int size; private int movesCount; private final Cell[][] board; public Board(int size) { this.size = size; this.board = new Cell[size][size]; movesCount = 0; initializeBoard(); } private void initializeBoard() { for (int row = 0; row < size; row++) { for (int col = 0; col < size; col++) { board[row][col] = new Cell(); } } } public boolean placeSymbol(int row, int col, Symbol symbol) { if (row < 0 || row >= size || col < 0 || col >= size) { throw new InvalidMoveException("Invalid position: out of bounds."); } if (board[row][col].getSymbol() != Symbol.EMPTY) { throw new InvalidMoveException("Invalid position: cell is already occupied."); } board[row][col].setSymbol(symbol); movesCount++; return true; } public Cell getCell(int row, int col) { if (row < 0 || row >= size || col < 0 || col >= size) { return null; } return board[row][col]; } public boolean isFull() { return movesCount == size * size; } public void printBoard() { System.out.println("-------------"); for (int i = 0; i < size; i++) { System.out.print("| "); for (int j = 0; j < size; j++) { Symbol symbol = board[i][j].getSymbol(); System.out.print(symbol.getChar() + " | "); } System.out.println("\n-------------"); } } public int getSize() { return size; } } ================================================ FILE: solutions/java/src/tictactoe/models/Cell.java ================================================ package tictactoe.models; import tictactoe.enums.Symbol; public class Cell { private Symbol symbol; public Cell() { this.symbol = Symbol.EMPTY; } public Symbol getSymbol() { return symbol; } public void setSymbol(Symbol symbol) { this.symbol = symbol; } } ================================================ FILE: solutions/java/src/tictactoe/models/Player.java ================================================ package tictactoe.models; import tictactoe.enums.Symbol; public class Player { private final String name; private final Symbol symbol; public Player(String name, Symbol symbol) { this.name = name; this.symbol = symbol; } public String getName() { return name; } public Symbol getSymbol() { return symbol; } } ================================================ FILE: solutions/java/src/tictactoe/observer/GameObserver.java ================================================ package tictactoe.observer; import tictactoe.Game; public interface GameObserver { void update(Game game); } ================================================ FILE: solutions/java/src/tictactoe/observer/GameSubject.java ================================================ package tictactoe.observer; import tictactoe.Game; import java.util.ArrayList; import java.util.List; public abstract class GameSubject { private final List observers = new ArrayList<>(); public void addObserver(GameObserver observer) { observers.add(observer); } public void removeObserver(GameObserver observer) { observers.remove(observer); } public void notifyObservers() { for (GameObserver observer : observers) { // Pass 'this' which is the Game instance observer.update((Game) this); } } } ================================================ FILE: solutions/java/src/tictactoe/observer/Scoreboard.java ================================================ package tictactoe.observer; import tictactoe.Game; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Scoreboard implements GameObserver { private final Map scores; public Scoreboard() { this.scores = new ConcurrentHashMap<>(); } @Override public void update(Game game) { // The scoreboard only cares about finished games with a winner if (game.getWinner() != null) { String winnerName = game.getWinner().getName(); scores.put(winnerName, scores.getOrDefault(winnerName, 0) + 1); System.out.printf("[Scoreboard] %s wins! Their new score is %d.%n", winnerName, scores.get(winnerName)); } } public void printScores() { System.out.println("\n--- Overall Scoreboard ---"); if (scores.isEmpty()) { System.out.println("No games with a winner have been played yet."); return; } scores.forEach((playerName, score) -> System.out.printf("Player: %-10s | Wins: %d%n", playerName, score) ); System.out.println("--------------------------\n"); } } ================================================ FILE: solutions/java/src/tictactoe/state/DrawState.java ================================================ package tictactoe.state; import tictactoe.Game; import tictactoe.exceptions.InvalidMoveException; import tictactoe.models.Player; public class DrawState implements GameState { @Override public void handleMove(Game game, Player player, int row, int col) { throw new InvalidMoveException("Game is already over. It was a draw."); } } ================================================ FILE: solutions/java/src/tictactoe/state/GameState.java ================================================ package tictactoe.state; import tictactoe.Game; import tictactoe.models.Player; public interface GameState { void handleMove(Game game, Player player, int row, int col); } ================================================ FILE: solutions/java/src/tictactoe/state/InProgressState.java ================================================ package tictactoe.state; import tictactoe.Game; import tictactoe.enums.GameStatus; import tictactoe.enums.Symbol; import tictactoe.exceptions.InvalidMoveException; import tictactoe.models.Player; public class InProgressState implements GameState { @Override public void handleMove(Game game, Player player, int row, int col) { if (game.getCurrentPlayer() != player) { throw new InvalidMoveException("Not your turn!"); } // Place the piece on the board game.getBoard().placeSymbol(row, col, player.getSymbol()); // Check for a winner or a draw if (game.checkWinner(player)) { game.setWinner(player); game.setStatus(player.getSymbol() == Symbol.X ? GameStatus.WINNER_X : GameStatus.WINNER_O); game.setState(new WinnerState()); } else if (game.getBoard().isFull()) { game.setStatus(GameStatus.DRAW); game.setState(new DrawState()); } else { // If the game is still in progress, switch players game.switchPlayer(); } } } ================================================ FILE: solutions/java/src/tictactoe/state/WinnerState.java ================================================ package tictactoe.state; import tictactoe.Game; import tictactoe.exceptions.InvalidMoveException; import tictactoe.models.Player; public class WinnerState implements GameState { @Override public void handleMove(Game game, Player player, int row, int col) { throw new InvalidMoveException("Game is already over. " + game.getWinner().getName() + " has won."); } } ================================================ FILE: solutions/java/src/tictactoe/strategy/ColumnWinningStrategy.java ================================================ package tictactoe.strategy; import tictactoe.models.Board; import tictactoe.models.Player; public class ColumnWinningStrategy implements WinningStrategy { @Override public boolean checkWinner(Board board, Player player) { for (int col = 0; col < board.getSize(); col++) { boolean colWin = true; for (int row = 0; row < board.getSize(); row++) { if (board.getCell(row, col).getSymbol() != player.getSymbol()) { colWin = false; break; } } if (colWin) return true; } return false; } } ================================================ FILE: solutions/java/src/tictactoe/strategy/DiagonalWinningStrategy.java ================================================ package tictactoe.strategy; import tictactoe.models.Board; import tictactoe.models.Player; public class DiagonalWinningStrategy implements WinningStrategy { @Override public boolean checkWinner(Board board, Player player) { // Main diagonal boolean mainDiagWin = true; for (int i = 0; i < board.getSize(); i++) { if (board.getCell(i, i).getSymbol() != player.getSymbol()) { mainDiagWin = false; break; } } if (mainDiagWin) return true; // Anti-diagonal boolean antiDiagWin = true; for (int i = 0; i < board.getSize(); i++) { if (board.getCell(i, board.getSize() - 1 - i).getSymbol() != player.getSymbol()) { antiDiagWin = false; break; } } return antiDiagWin; } } ================================================ FILE: solutions/java/src/tictactoe/strategy/RowWinningStrategy.java ================================================ package tictactoe.strategy; import tictactoe.models.Board; import tictactoe.models.Player; public class RowWinningStrategy implements WinningStrategy { @Override public boolean checkWinner(Board board, Player player) { for (int row = 0; row < board.getSize(); row++) { boolean rowWin = true; for (int col = 0; col < board.getSize(); col++) { if (board.getCell(row, col).getSymbol() != player.getSymbol()) { rowWin = false; break; } } if (rowWin) return true; } return false; } } ================================================ FILE: solutions/java/src/tictactoe/strategy/WinningStrategy.java ================================================ package tictactoe.strategy; import tictactoe.models.Board; import tictactoe.models.Player; public interface WinningStrategy { boolean checkWinner(Board board, Player player); } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/IntersectionController.java ================================================ package trafficsignalcontrolsystem; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.observer.TrafficObserver; import trafficsignalcontrolsystem.states.intersection.IntersectionState; import trafficsignalcontrolsystem.states.intersection.NorthSouthGreenState; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class IntersectionController implements Runnable { private final int id; private final Map trafficLights; private IntersectionState currentState; private final long greenDuration; private final long yellowDuration; private volatile boolean running = true; // Private constructor to be used by the builder private IntersectionController(int id, Map trafficLights, long greenDuration, long yellowDuration) { this.id = id; this.trafficLights = trafficLights; this.greenDuration = greenDuration; this.yellowDuration = yellowDuration; // Initial state for the intersection this.currentState = new NorthSouthGreenState(); } public int getId() { return id; } public long getGreenDuration() { return greenDuration; } public long getYellowDuration() { return yellowDuration; } public TrafficLight getLight(Direction direction) { return trafficLights.get(direction); } public void setState(IntersectionState state) { this.currentState = state; } public void start() { new Thread(this).start(); } public void stop() { this.running = false; } @Override public void run() { while (running) { try { currentState.handle(this); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Intersection " + id + " was interrupted."); running = false; } } } // --- Builder Pattern Starts Here --- public static class Builder { private final int id; private long greenDuration = 5000; // default 5s private long yellowDuration = 2000; // default 2s private final List observers = new ArrayList<>(); public Builder(int id) { this.id = id; } public Builder withDurations(long green, long yellow) { this.greenDuration = green; this.yellowDuration = yellow; return this; } public Builder addObserver(TrafficObserver observer) { this.observers.add(observer); return this; } public IntersectionController build() { Map lights = new HashMap<>(); for (Direction dir : Direction.values()) { TrafficLight light = new TrafficLight(id, dir); // Attach all registered observers to each light observers.forEach(light::addObserver); lights.put(dir, light); } return new IntersectionController(id, lights, greenDuration, yellowDuration); } } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/README.md ================================================ # Traffic Signal System (LLD) ## Problem Statement Design and implement a Traffic Signal System to manage the traffic lights at an intersection. The system should support configurable signal durations for each direction and vendingMachineState, automatic cycling of signals using the State design pattern, and the ability to manually override signals as needed. --- ## Requirements - **Multiple Directions:** The intersection supports multiple directions (e.g., NORTH, SOUTH, EAST, WEST). - **Traffic Light States:** Each direction has a traffic light with states: GREEN, YELLOW, RED. - **Configurable Durations:** Each direction and vendingMachineState can have its own configurable duration. - **Automatic Cycling:** The system automatically cycles through the states for each direction in a round-robin fashion. - **Manual Override:** The system allows manual override to set a specific direction to GREEN at any time. - **Extensibility:** Easy to add new directions or states if needed. - **State Pattern:** Use the State design pattern to encapsulate vendingMachineState-specific behavior and transitions. --- ## Core Entities - **Direction:** Enum representing the directions at the intersection (NORTH, SOUTH, EAST, WEST). - **SignalState (interface):** Represents the vendingMachineState of a traffic light (GREEN, YELLOW, RED), with vendingMachineState-specific behavior. - **GreenState, YellowState, RedState:** Concrete implementations of `SignalState` for each light vendingMachineState. - **TrafficLight:** Represents a traffic light for a direction, maintains its current vendingMachineState and delegates behavior to the vendingMachineState. - **Intersection:** Represents the intersection, holds all traffic lights and their configurations, and exposes the manual override. - **TrafficSignalController:** Controls the cycling and overriding of traffic signals, manages timing and transitions using a scheduler. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/trafficsignalsystem-class-diagram.png) ### 1. Direction - Enum: NORTH, SOUTH, EAST, WEST ### 2. SignalState (interface) - **Methods:** `void handle(TrafficLight, TrafficSignalController, Direction)`, `String getName()` ### 3. GreenState, YellowState, RedState - Implement `SignalState` - Each handles its own transition logic and duration ### 4. TrafficLight - **Fields:** currentState, direction - **Methods:** setState(SignalState), getState(), getDirection(), handle(TrafficSignalController) ### 5. Intersection - **Fields:** id, Map signals, Map> signalDurations, TrafficSignalController controller - **Methods:** start(Direction), manualOverride(Direction), getSignal(Direction) ### 6. TrafficSignalController - **Fields:** Map signals, Map> signalDurations, scheduler - **Methods:** start(Direction), scheduleStateChange(...), getSignalDuration(...), getNextDirection(...), getTrafficLight(...), manualOverride(Direction) --- ## Design Patterns Used - **State Pattern:** Each signal vendingMachineState (GREEN, YELLOW, RED) encapsulates its own behavior and transition logic. - **Scheduler/Timer:** For handling timed transitions between states. - **Strategy Pattern:** (Conceptually) for supporting different timing strategies per direction/vendingMachineState. --- ## Example Usage ```java // Configure durations per direction and vendingMachineState Map> signalDurations = new EnumMap<>(Direction.class); signalDurations.put(Direction.NORTH, Map.of("GREEN", 4, "YELLOW", 2, "RED", 3)); signalDurations.put(Direction.SOUTH, Map.of("GREEN", 3, "YELLOW", 2, "RED", 4)); signalDurations.put(Direction.EAST, Map.of("GREEN", 5, "YELLOW", 2, "RED", 3)); signalDurations.put(Direction.WEST, Map.of("GREEN", 2, "YELLOW", 2, "RED", 5)); // Initialize traffic lights Map signals = new EnumMap<>(Direction.class); for (Direction direction : Direction.values()) { signals.put(direction, new TrafficLight(direction)); } // Create and start the intersection Intersection intersection = new Intersection("1", signals, signalDurations); intersection.start(Direction.NORTH); // Manual override example intersection.manualOverride(Direction.EAST); ``` --- ## Demo See `TrafficSignalSystemDemo.java` for a sample usage and simulation of the traffic signal system. --- ## Extending the Framework - **Add new directions:** Add to the `Direction` enum and update configuration. - **Add new states:** Add to the `SignalState` interface and implement new vendingMachineState classes. - **Custom timing strategies:** Implement new strategies for special intersections or adaptive signals. --- ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/TrafficControlSystem.java ================================================ package trafficsignalcontrolsystem; import trafficsignalcontrolsystem.observer.CentralMonitor; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class TrafficControlSystem { private static final TrafficControlSystem INSTANCE = new TrafficControlSystem(); private final List intersections = new ArrayList<>(); private ExecutorService executorService; private TrafficControlSystem() {} public static TrafficControlSystem getInstance() { return INSTANCE; } public void addIntersection(int intersectionId, int greenDuration, int yellowDuration) { IntersectionController intersection = new IntersectionController.Builder(intersectionId) .withDurations(greenDuration, yellowDuration) .addObserver(new CentralMonitor()) .build(); intersections.add(intersection); } public void startSystem() { if (intersections.isEmpty()) { System.out.println("No intersections to manage. System not starting."); return; } System.out.println("--- Starting Traffic Control System ---"); executorService = Executors.newFixedThreadPool(intersections.size()); intersections.forEach(executorService::submit); } public void stopSystem() { System.out.println("\n--- Shutting Down Traffic Control System ---"); intersections.forEach(IntersectionController::stop); executorService.shutdown(); try { if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { executorService.shutdownNow(); } } catch (InterruptedException e) { executorService.shutdownNow(); } System.out.println("All intersections stopped. System shut down."); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/TrafficLight.java ================================================ package trafficsignalcontrolsystem; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.enums.LightColor; import trafficsignalcontrolsystem.observer.TrafficObserver; import trafficsignalcontrolsystem.states.light.GreenState; import trafficsignalcontrolsystem.states.light.RedState; import trafficsignalcontrolsystem.states.light.SignalState; import java.util.ArrayList; import java.util.List; public class TrafficLight { private final Direction direction; private LightColor currentColor; private SignalState currentState; private SignalState nextState; // The state to transition to after a timer elapses private final List observers = new ArrayList<>(); private final int intersectionId; public TrafficLight(int intersectionId, Direction direction) { this.intersectionId = intersectionId; this.direction = direction; this.currentState = new RedState(); // Default state is Red this.currentState.handle(this); } // This is called by the IntersectionController to initiate a G-Y-R cycle public void startGreen() { this.currentState = new GreenState(); this.currentState.handle(this); } // This is called by the IntersectionController to transition from G->Y or Y->R public void transition() { this.currentState = this.nextState; this.currentState.handle(this); } public void setColor(LightColor color) { if (this.currentColor != color) { this.currentColor = color; notifyObservers(); } } public void setNextState(SignalState state) { this.nextState = state; } public LightColor getCurrentColor() { return currentColor; } public Direction getDirection() { return direction; } // Observer pattern methods public void addObserver(TrafficObserver observer) { observers.add(observer); } public void removeObserver(TrafficObserver observer) { observers.remove(observer); } private void notifyObservers() { for (TrafficObserver observer : observers) { observer.update(intersectionId, direction, currentColor); } } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/TrafficSystemDemo.java ================================================ package trafficsignalcontrolsystem; import java.util.concurrent.TimeUnit; public class TrafficSystemDemo { public static void main(String[] args) { // 1. Get the singleton TrafficControlSystem instance TrafficControlSystem system = TrafficControlSystem.getInstance(); // 2. Add intersections to the system system.addIntersection(1, 500, 200); system.addIntersection(2, 700, 150); // 3. Start the system system.startSystem(); // 4. Let the simulation run for a while (e.g., 5 seconds) try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 5. Stop the system gracefully system.stopSystem(); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/enums/Direction.java ================================================ package trafficsignalcontrolsystem.enums; public enum Direction { NORTH, SOUTH, EAST, WEST } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/enums/LightColor.java ================================================ package trafficsignalcontrolsystem.enums; public enum LightColor { GREEN, YELLOW, RED } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/observer/CentralMonitor.java ================================================ package trafficsignalcontrolsystem.observer; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.enums.LightColor; public class CentralMonitor implements TrafficObserver { @Override public void update(int intersectionId, Direction direction, LightColor color) { System.out.printf("[MONITOR] Intersection %d: Light for %s direction changed to %s.\n", intersectionId, direction, color); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/observer/TrafficObserver.java ================================================ package trafficsignalcontrolsystem.observer; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.enums.LightColor; public interface TrafficObserver { void update(int intersectionId, Direction direction, LightColor color); } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/intersection/EastWestGreenState.java ================================================ package trafficsignalcontrolsystem.states.intersection; import trafficsignalcontrolsystem.IntersectionController; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.enums.LightColor; public class EastWestGreenState implements IntersectionState { @Override public void handle(IntersectionController context) throws InterruptedException { System.out.printf("\n--- INTERSECTION %d: Cycle -> East-West GREEN ---\n", context.getId()); // Turn East and West green, ensure North and South are red context.getLight(Direction.EAST).startGreen(); context.getLight(Direction.WEST).startGreen(); context.getLight(Direction.NORTH).setColor(LightColor.RED); context.getLight(Direction.SOUTH).setColor(LightColor.RED); // Wait for green light duration Thread.sleep(context.getGreenDuration()); // Transition East and West to Yellow context.getLight(Direction.EAST).transition(); context.getLight(Direction.WEST).transition(); // Wait for yellow light duration Thread.sleep(context.getYellowDuration()); // Transition East and West to Red context.getLight(Direction.EAST).transition(); context.getLight(Direction.WEST).transition(); // Change the intersection's state back to let North-South go context.setState(new NorthSouthGreenState()); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/intersection/IntersectionState.java ================================================ package trafficsignalcontrolsystem.states.intersection; import trafficsignalcontrolsystem.IntersectionController; public interface IntersectionState { void handle(IntersectionController context) throws InterruptedException; } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/intersection/NorthSouthGreenState.java ================================================ package trafficsignalcontrolsystem.states.intersection; import trafficsignalcontrolsystem.IntersectionController; import trafficsignalcontrolsystem.enums.Direction; import trafficsignalcontrolsystem.enums.LightColor; public class NorthSouthGreenState implements IntersectionState { @Override public void handle(IntersectionController context) throws InterruptedException { System.out.printf("\n--- INTERSECTION %d: Cycle Start -> North-South GREEN ---\n", context.getId()); // Turn North and South green, ensure East and West are red context.getLight(Direction.NORTH).startGreen(); context.getLight(Direction.SOUTH).startGreen(); context.getLight(Direction.EAST).setColor(LightColor.RED); context.getLight(Direction.WEST).setColor(LightColor.RED); // Wait for green light duration Thread.sleep(context.getGreenDuration()); // Transition North and South to Yellow context.getLight(Direction.NORTH).transition(); context.getLight(Direction.SOUTH).transition(); // Wait for yellow light duration Thread.sleep(context.getYellowDuration()); // Transition North and South to Red context.getLight(Direction.NORTH).transition(); context.getLight(Direction.SOUTH).transition(); // Change the intersection's state to let East-West go context.setState(new EastWestGreenState()); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/light/GreenState.java ================================================ package trafficsignalcontrolsystem.states.light; import trafficsignalcontrolsystem.TrafficLight; import trafficsignalcontrolsystem.enums.LightColor; public class GreenState implements SignalState { @Override public void handle(TrafficLight context) { context.setColor(LightColor.GREEN); // After being green, the next state is yellow. context.setNextState(new YellowState()); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/light/RedState.java ================================================ package trafficsignalcontrolsystem.states.light; import trafficsignalcontrolsystem.TrafficLight; import trafficsignalcontrolsystem.enums.LightColor; public class RedState implements SignalState { @Override public void handle(TrafficLight context) { context.setColor(LightColor.RED); // Red is a stable state, it transitions to green only when the intersection controller commands it. // So, the next state is self. context.setNextState(new RedState()); } } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/light/SignalState.java ================================================ package trafficsignalcontrolsystem.states.light; import trafficsignalcontrolsystem.TrafficLight; public interface SignalState { void handle(TrafficLight context); } ================================================ FILE: solutions/java/src/trafficsignalcontrolsystem/states/light/YellowState.java ================================================ package trafficsignalcontrolsystem.states.light; import trafficsignalcontrolsystem.TrafficLight; import trafficsignalcontrolsystem.enums.LightColor; public class YellowState implements SignalState { @Override public void handle(TrafficLight context) { context.setColor(LightColor.YELLOW); // After being yellow, the next state is red. context.setNextState(new RedState()); } } ================================================ FILE: solutions/java/src/vendingmachine/README.md ================================================ # Vending Machine (LLD) ## Problem Statement Design and implement a Vending Machine system that allows users to select products, insert coins/notes, dispense products, and return change. The system should manage inventory, handle payments, and use the State design pattern for its operations. --- ## Requirements - **Product Management:** The system manages a catalog of products, each with a price and available quantity. - **Inventory Management:** The system tracks the quantity of each item and prevents dispensing if out of stock. - **Payment Handling:** The system accepts coins and notes, tracks total payment, and returns change if necessary. - **State Management:** The system uses the State design pattern to manage its operational states (Idle, Ready, Dispense, ReturnChange). - **User Interaction:** Users can select products, insert coins/notes, and receive products and change. - **Extensibility:** Easy to add new item types, payment methods, or states. --- ## Core Entities - **VendingMachine:** Main class that manages inventory, vendingMachineState transitions, item selection, and payment. - **Product:** Represents a item with a name and price. - **Inventory:** Manages the stock of products. - **Coin / Note:** Represents accepted denominations for payment. - **VendingMachineState (interface):** Interface for different machine states. - **IdleState, ReadyState, DispenseState, ReturnChangeState:** Concrete states implementing VendingMachineState. - **Singleton Pattern:** VendingMachine is implemented as a singleton. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/vendingmachine-class-diagram.png) ### 1. VendingMachine - **Fields:** Inventory inventory, VendingMachineState idleState, readyState, dispenseState, returnChangeState, currentState, Product selectedProduct, double totalPayment - **Methods:** addProduct(String, double, int), selectProduct(Product), insertCoin(Coin), insertNote(Note), dispenseProduct(), returnChange(), setState(VendingMachineState), getInstance(), etc. ### 2. Product - **Fields:** String name, double price ### 3. Inventory - **Fields:** Map productQuantities - **Methods:** addProduct(Product, int), getQuantity(Product), reduceQuantity(Product), isAvailable(Product) ### 4. Coin / Note - **Fields:** double value - **Methods:** getValue() ### 5. VendingMachineState (interface) - **Methods:** selectProduct(Product), insertCoin(Coin), insertNote(Note), dispenseProduct(), returnChange() ### 6. IdleState, ReadyState, DispenseState, ReturnChangeState - **Implements:** VendingMachineState - **Behavior:** Each vendingMachineState handles allowed operations and transitions. --- ## Example Usage ```java VendingMachine machine = VendingMachine.getInstance(); Product chips = machine.addProduct("Chips", 1.5, 10); machine.selectProduct(chips); machine.insertCoin(new Coin(1.0)); machine.insertCoin(new Coin(0.5)); machine.dispenseProduct(); machine.returnChange(); ``` --- ## Demo See your main or demo class for a sample usage and simulation of the vending machine. --- ## Extending the Framework - **Add new payment methods:** Support for cards, mobile payments, etc. - **Add new states:** Maintenance, OutOfOrder, etc. - **Add item categories:** Snacks, drinks, etc. --- ## Design Patterns Used - **State Pattern:** For managing machine states and transitions. - **Singleton Pattern:** For ensuring a single instance of the VendingMachine. --- ================================================ FILE: solutions/java/src/vendingmachine/VendingMachine.java ================================================ package vendingmachine; import vendingmachine.entity.Inventory; import vendingmachine.entity.Item; import vendingmachine.enums.Coin; import vendingmachine.state.*; public class VendingMachine { private final static VendingMachine INSTANCE = new VendingMachine(); private final Inventory inventory = new Inventory(); private VendingMachineState currentVendingMachineState; private int balance = 0; private String selectedItemCode; public VendingMachine() { currentVendingMachineState = new IdleState(this); } public static VendingMachine getInstance() { return INSTANCE; } public void insertCoin(Coin coin) { currentVendingMachineState.insertCoin(coin); } public Item addItem(String code, String name, int price, int quantity) { Item item = new Item(code, name, price); inventory.addItem(code, item, quantity); return item; } public void selectItem(String code) { currentVendingMachineState.selectItem(code); } public void dispense() { currentVendingMachineState.dispense(); } public void dispenseItem() { Item item = inventory.getItem(selectedItemCode); if (balance >= item.getPrice()) { inventory.reduceStock(selectedItemCode); balance -= item.getPrice(); System.out.println("Dispensed: " + item.getName()); if (balance > 0) { System.out.println("Returning change: " + balance); } } reset(); setState(new IdleState(this)); } public void refundBalance() { System.out.println("Refunding: " + balance); balance = 0; } public void reset() { selectedItemCode = null; balance = 0; } public void addBalance(int value) { balance += value; } public Item getSelectedItem() { return inventory.getItem(selectedItemCode); } public void setSelectedItemCode(String code) { this.selectedItemCode = code; } public void setState(VendingMachineState vendingMachineState) { this.currentVendingMachineState = vendingMachineState; } // Getters for states and inventory public Inventory getInventory() { return inventory; } public int getBalance() { return balance; } } ================================================ FILE: solutions/java/src/vendingmachine/VendingMachineDemo.java ================================================ package vendingmachine; import vendingmachine.enums.Coin; public class VendingMachineDemo { public static void main(String[] args) { VendingMachine vendingMachine = VendingMachine.getInstance(); // Add products to the inventory vendingMachine.addItem("A1", "Coke", 25, 3); vendingMachine.addItem("A2", "Pepsi", 25, 2); vendingMachine.addItem("B1", "Water", 10, 5); // Select a product System.out.println("\n--- Step 1: Select an item ---"); vendingMachine.selectItem("A1"); // Insert coins System.out.println("\n--- Step 2: Insert coins ---"); vendingMachine.insertCoin(Coin.DIME); // 10 vendingMachine.insertCoin(Coin.DIME); // 10 vendingMachine.insertCoin(Coin.NICKEL); // 5 // Dispense the product System.out.println("\n--- Step 3: Dispense item ---"); vendingMachine.dispense(); // Should dispense Coke // Select another item System.out.println("\n--- Step 4: Select another item ---"); vendingMachine.selectItem("B1"); // Insert more amount System.out.println("\n--- Step 5: Insert more than needed ---"); vendingMachine.insertCoin(Coin.QUARTER); // 25 // Try to dispense the product System.out.println("\n--- Step 6: Dispense and return change ---"); vendingMachine.dispense(); } } ================================================ FILE: solutions/java/src/vendingmachine/entity/Inventory.java ================================================ package vendingmachine.entity; import java.util.HashMap; import java.util.Map; public class Inventory { private final Map itemMap = new HashMap<>(); private final Map stockMap = new HashMap<>(); public void addItem(String code, Item item, int quantity) { itemMap.put(code, item); stockMap.put(code, quantity); } public Item getItem(String code) { return itemMap.get(code); } public boolean isAvailable(String code) { return stockMap.getOrDefault(code, 0) > 0; } public void reduceStock(String code) { stockMap.put(code, stockMap.get(code) - 1); } } ================================================ FILE: solutions/java/src/vendingmachine/entity/Item.java ================================================ package vendingmachine.entity; public class Item { private String code; private String name; private int price; public Item(String code, String name, int price) { this.code = code; this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } } ================================================ FILE: solutions/java/src/vendingmachine/enums/Coin.java ================================================ package vendingmachine.enums; public enum Coin { PENNY(1), NICKEL(5), DIME(10), QUARTER(25); private final int value; Coin(int value) { this.value = value; } public int getValue() { return value; } } ================================================ FILE: solutions/java/src/vendingmachine/state/DispensingState.java ================================================ package vendingmachine.state; import vendingmachine.enums.Coin; import vendingmachine.VendingMachine; public class DispensingState extends VendingMachineState { public DispensingState(VendingMachine machine) { super(machine); } @Override public void insertCoin(Coin coin) { System.out.println("Currently dispensing. Please wait."); } @Override public void selectItem(String code) { System.out.println("Currently dispensing. Please wait."); } @Override public void dispense() { // already triggered by HasMoneyState } @Override public void refund() { System.out.println("Dispensing in progress. Refund not allowed."); } } ================================================ FILE: solutions/java/src/vendingmachine/state/HasMoneyState.java ================================================ package vendingmachine.state; import vendingmachine.enums.Coin; import vendingmachine.VendingMachine; public class HasMoneyState extends VendingMachineState { public HasMoneyState(VendingMachine machine) { super(machine); } @Override public void insertCoin(Coin coin) { System.out.println("Already received full amount."); } @Override public void selectItem(String code) { System.out.println("Item already selected."); } @Override public void dispense() { machine.setState(new DispensingState(machine)); machine.dispenseItem(); } @Override public void refund() { machine.refundBalance(); machine.reset(); machine.setState(new IdleState(machine)); } } ================================================ FILE: solutions/java/src/vendingmachine/state/IdleState.java ================================================ package vendingmachine.state; import vendingmachine.enums.Coin; import vendingmachine.VendingMachine; public class IdleState extends VendingMachineState { public IdleState(VendingMachine machine) { super(machine); } @Override public void insertCoin(Coin coin) { System.out.println("Please select an item before inserting money."); } @Override public void selectItem(String code) { if (!machine.getInventory().isAvailable(code)) { System.out.println("Item not available."); return; } machine.setSelectedItemCode(code); machine.setState(new ItemSelectedState(machine)); System.out.println("Item selected: " + code); } @Override public void dispense() { System.out.println("No item selected."); } @Override public void refund() { System.out.println("No money to refund."); } } ================================================ FILE: solutions/java/src/vendingmachine/state/ItemSelectedState.java ================================================ package vendingmachine.state; import vendingmachine.enums.Coin; import vendingmachine.VendingMachine; public class ItemSelectedState extends VendingMachineState { public ItemSelectedState(VendingMachine machine) { super(machine); } @Override public void insertCoin(Coin coin) { machine.addBalance(coin.getValue()); System.out.println("Coin Inserted: " + coin.getValue()); int price = machine.getSelectedItem().getPrice(); if (machine.getBalance() >= price) { System.out.println("Sufficient money received."); machine.setState(new HasMoneyState(machine)); } } @Override public void selectItem(String code) { System.out.println("Item already selected."); } @Override public void dispense() { System.out.println("Please insert sufficient money."); } @Override public void refund() { machine.reset(); machine.setState(new IdleState(machine)); } } ================================================ FILE: solutions/java/src/vendingmachine/state/VendingMachineState.java ================================================ package vendingmachine.state; import vendingmachine.enums.Coin; import vendingmachine.VendingMachine; public abstract class VendingMachineState { VendingMachine machine; VendingMachineState(VendingMachine machine) { this.machine = machine; } public abstract void insertCoin(Coin coin); public abstract void selectItem(String code); public abstract void dispense(); public abstract void refund(); } ================================================ FILE: solutions/java/src/votingsystem/Candidate.java ================================================ package votingsystem; class Candidate { private final String id; private final String name; private final String party; public Candidate(String id, String name, String party) { this.id = id; this.name = name; this.party = party; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/votingsystem/README.md ================================================ # Voting System (LLD) ## Problem Statement Design and implement a Voting System that allows voters to cast votes for candidates, ensures each voter can vote only once, and provides the ability to tally and display results. --- ## Requirements - **Voter Registration:** The system manages a list of eligible voters. - **Candidate Registration:** The system manages a list of candidates. - **Vote Casting:** Each voter can cast a vote for a candidate, but only once. - **Vote Recording:** The system records each vote and prevents duplicate voting. - **Result Tallying:** The system can tally votes for each candidate and display the results. - **Extensibility:** Easy to add new features such as multiple elections, voting rounds, or different voting methods. --- ## Core Entities - **VotingSystem:** Main class that manages voters, candidates, vote casting, and result tallying. - **Voter:** Represents a voter with a unique ID and name. - **Candidate:** Represents a candidate with a unique ID and name. - **VoteRecord:** Represents a record of a vote cast by a voter for a candidate. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/votingsystem-class-diagram.png) ### 1. VotingSystem - **Fields:** Map voters, Map candidates, Map voteRecords - **Methods:** registerVoter(Voter), registerCandidate(Candidate), castVote(int voterId, int candidateId), tallyResults(), displayResults(), hasVoted(int voterId) ### 2. Voter - **Fields:** int id, String name ### 3. Candidate - **Fields:** int id, String name ### 4. VoteRecord - **Fields:** int voterId, int candidateId --- ## Example Usage ```java VotingSystem votingSystem = new VotingSystem(); votingSystem.registerVoter(new Voter(1, "Alice")); votingSystem.registerVoter(new Voter(2, "Bob")); votingSystem.registerCandidate(new Candidate(1, "John")); votingSystem.registerCandidate(new Candidate(2, "Jane")); votingSystem.castVote(1, 1); // Alice votes for John votingSystem.castVote(2, 2); // Bob votes for Jane votingSystem.displayResults(); ``` --- ## Demo See `VotingSystemDemo.java` for a sample usage and simulation of the voting system. --- ## Extending the Design - **Add multiple elections:** Support for different elections or voting rounds. - **Add voting methods:** Implement ranked-choice, weighted voting, etc. - **Add features:** Such as voter authentication, audit logs, or result export. --- ================================================ FILE: solutions/java/src/votingsystem/VoteRecord.java ================================================ package votingsystem; import java.util.Date; class VoteRecord { private final String voterId; private final String candidateId; private final long timestamp; public VoteRecord(String voterId, String candidateId, long timestamp) { this.voterId = voterId; this.candidateId = candidateId; this.timestamp = timestamp; } @Override public String toString() { return "Vote cast by " + voterId + " for candidate " + candidateId + " at " + new Date(timestamp); } } ================================================ FILE: solutions/java/src/votingsystem/Voter.java ================================================ package votingsystem; class Voter { private final String id; private final String name; private final String password; public Voter(String id, String name, String password) { this.id = id; this.name = name; this.password = password; } public String getId() { return id; } public String getName() { return name; } } ================================================ FILE: solutions/java/src/votingsystem/VotingSystem.java ================================================ package votingsystem; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class VotingSystem { private static volatile VotingSystem instance; private final Map voters; private final Map candidates; private final Map voteCount; private final Set votedVoters; private final ReadWriteLock votingLock; private volatile boolean isVotingOpen; private final BlockingQueue voteAuditLog; private VotingSystem() { this.voters = new ConcurrentHashMap<>(); this.candidates = new ConcurrentHashMap<>(); this.voteCount = new ConcurrentHashMap<>(); this.votedVoters = ConcurrentHashMap.newKeySet(); this.votingLock = new ReentrantReadWriteLock(); this.voteAuditLog = new LinkedBlockingQueue<>(); this.isVotingOpen = false; } public static VotingSystem getInstance() { VotingSystem result = instance; if (result == null) { synchronized (VotingSystem.class) { if (result == null) { instance = result = new VotingSystem(); } } } return result; } public void registerVoter(String voterId, String name, String password) { Voter voter = new Voter(voterId, name, password); voters.putIfAbsent(voterId, voter); } public void registerCandidate(String candidateId, String name, String party) { Candidate candidate = new Candidate(candidateId, name, party); candidates.putIfAbsent(candidateId, candidate); voteCount.putIfAbsent(candidateId, new AtomicInteger(0)); } public void startVoting() { votingLock.writeLock().lock(); try { isVotingOpen = true; System.out.println("Voting has started!"); } finally { votingLock.writeLock().unlock(); } } public void endVoting() { votingLock.writeLock().lock(); try { isVotingOpen = false; System.out.println("Voting has ended!"); } finally { votingLock.writeLock().unlock(); } } public boolean castVote(String voterId, String candidateId) { votingLock.readLock().lock(); try { if (!isVotingOpen) { System.out.println("Voting is not open!"); return false; } Voter voter = voters.get(voterId); Candidate candidate = candidates.get(candidateId); if (voter == null || candidate == null) { System.out.println("Invalid voter or candidate ID!"); return false; } if (!votedVoters.add(voterId)) { System.out.println("Voter has already cast their vote!"); return false; } voteCount.get(candidateId).incrementAndGet(); voteAuditLog.offer(new VoteRecord(voterId, candidateId, System.currentTimeMillis())); return true; } finally { votingLock.readLock().unlock(); } } public Map getCurrentResults() { Map results = new HashMap<>(); votingLock.readLock().lock(); try { for (Map.Entry entry : voteCount.entrySet()) { results.put(candidates.get(entry.getKey()).getName(), entry.getValue().get()); } return results; } finally { votingLock.readLock().unlock(); } } public List getAuditLog() { return new ArrayList<>(voteAuditLog); } } ================================================ FILE: solutions/java/src/votingsystem/VotingSystemDemo.java ================================================ package votingsystem; import java.util.*; import java.util.concurrent.*; public class VotingSystemDemo { public static void run() { VotingSystem votingSystem = VotingSystem.getInstance(); votingSystem.registerCandidate("C1", "John Doe", "Party A"); votingSystem.registerCandidate("C2", "Jane Smith", "Party B"); for (int i = 1; i <= 100; i++) { votingSystem.registerVoter("V" + i, "Voter " + i, "pass" + i); } votingSystem.startVoting(); ExecutorService executor = Executors.newFixedThreadPool(10); List> futures = new ArrayList<>(); for (int i = 1; i <= 100; i++) { final String voterId = "V" + i; final String candidateId = "C" + ((i % 2) + 1); futures.add(executor.submit(() -> { try { Thread.sleep(new Random().nextInt(100)); return votingSystem.castVote(voterId, candidateId); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } })); } for (Future future : futures) { try { future.get(); } catch (Exception e) { e.printStackTrace(); } } votingSystem.endVoting(); Map results = votingSystem.getCurrentResults(); System.out.println("\nVoting Results:"); results.forEach((candidate, votes) -> System.out.println(candidate + ": " + votes + " votes")); System.out.println("\nAudit Log:"); votingSystem.getAuditLog().forEach(System.out::println); executor.shutdown(); } } ================================================ FILE: solutions/java/test/coffeevendingmachine/CoffeeVendingMachineTest.java ================================================ package coffeevendingmachine; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.DisplayName; import static org.junit.jupiter.api.Assertions.*; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Map; public class CoffeeVendingMachineTest { private CoffeeVendingMachine machine; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @BeforeEach void setUp() { machine = CoffeeVendingMachine.getInstance(); System.setOut(new PrintStream(outputStream)); // Reset and refill ingredients for each test machine.refillIngredient("Water", 150); machine.refillIngredient("Coffee", 100); machine.refillIngredient("Milk", 100); } @Test @DisplayName("Test coffee selection") void testSelectCoffee() { CoffeeRecipe espresso = machine.selectCoffee("Espresso"); assertEquals("Espresso", espresso.getName()); assertEquals(2.5, espresso.getPrice()); assertEquals(50, espresso.getRecipe().get("Water")); assertEquals(20, espresso.getRecipe().get("Coffee")); } @Test @DisplayName("Test invalid coffee selection") void testInvalidCoffeeSelection() { Exception exception = assertThrows(RuntimeException.class, () -> { machine.selectCoffee("MochaCoffee"); }); String expectedMessage = "Invalid coffee recipe: MochaCoffee"; String actualMessage = exception.getMessage(); assertTrue(actualMessage.contains(expectedMessage)); } @Test @DisplayName("Test successful coffee dispensing") void testDispenseCoffee() { CoffeeRecipe latte = machine.selectCoffee("Latte"); machine.dispenseCoffee(latte, new Payment(4.0)); String output = outputStream.toString(); assertTrue(output.contains("Dispensing: Latte")); assertTrue(output.contains("Processing Payment")); assertTrue(output.contains("Please collect your change: $1.0")); } @Test @DisplayName("Test insufficient payment") void testInsufficientPayment() { CoffeeRecipe cappuccino = machine.selectCoffee("Cappuccino"); Exception exception = assertThrows(RuntimeException.class, () -> { machine.dispenseCoffee(cappuccino, new Payment(2.0)); }); String expectedMessage = "Insufficient payment for Cappuccino"; String actualMessage = exception.getMessage(); assertTrue(actualMessage.contains(expectedMessage)); } @Test @DisplayName("Test ingredient consumption") void testIngredientConsumption() { CoffeeRecipe latte = machine.selectCoffee("Latte"); // Check initial levels Map beforeLevels = machine.showIngredientsMap(); int initialWaterLevel = beforeLevels.get("Water"); int initialCoffeeLevel = beforeLevels.get("Coffee"); int initialMilkLevel = beforeLevels.get("Milk"); machine.dispenseCoffee(latte, new Payment(3.0)); // Check levels after dispensing Map afterLevels = machine.showIngredientsMap(); assertEquals(initialWaterLevel - 50, afterLevels.get("Water").intValue()); assertEquals(initialCoffeeLevel - 20, afterLevels.get("Coffee").intValue()); assertEquals(initialMilkLevel - 30, afterLevels.get("Milk").intValue()); } @Test @DisplayName("Test ingredient refill") void testIngredientRefill() { // First check initial level Map beforeLevels = machine.showIngredientsMap(); int initialWaterLevel = beforeLevels.get("Water"); // Add more water machine.refillIngredient("Water", 50); // Check after refill Map afterLevels = machine.showIngredientsMap(); assertEquals(initialWaterLevel + 50, afterLevels.get("Water").intValue()); } } ================================================ FILE: solutions/python/.gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # UV # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. #uv.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/latest/usage/project/#working-with-version-control .pdm.toml .pdm-python .pdm-build/ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ # Ruff stuff: .ruff_cache/ # PyPI configuration file .pypirc ================================================ FILE: solutions/python/airlinemanagementsystem/README.md ================================================ # Designing an Airline Management System ## Requirements 1. The airline management system should allow users to search for flights based on source, destination, and date. 2. Users should be able to book flights, select seats, and make payments. 3. The system should manage flight schedules, aircraft assignments, and crew assignments. 4. The system should handle passenger information, including personal details and baggage information. 5. The system should support different types of users, such as passengers, airline staff, and administrators. 6. The system should be able to handle cancellations, refunds, and flight changes. 7. The system should ensure data consistency and handle concurrent access to shared resources. 8. The system should be scalable and extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Flight** class represents a flight in the airline management system, with properties such as flight number, source, destination, departure time, arrival time, and available seats. 2. The **Aircraft** class represents an aircraft, with properties like tail number, model, and total seats. 3. The **Passenger** class represents a passenger, with properties such as ID, name, email, and phone number. 4. The **Booking** class represents a booking made by a passenger for a specific flight and seat, with properties such as booking number, flight, passenger, seat, price, and booking status. 5. The **Seat** class represents a seat on a flight, with properties like seat number, seat type, and seat status. 6. The **Payment** class represents a payment made for a booking, with properties such as payment ID, payment method, amount, and payment status. 7. The **FlightSearch** class provides functionality to search for flights based on source, destination, and date. 8. The **BookingManager** class manages the creation and cancellation of bookings. It follows the Singleton pattern to ensure a single instance of the booking manager. 9. The **PaymentProcessor** class handles the processing of payments. It follows the Singleton pattern to ensure a single instance of the payment processor. 10. The **AirlineManagementSystem** class serves as the main entry point of the system, combining all the components and providing methods for flight management, booking, payment processing, and other operations. ================================================ FILE: solutions/python/atm/README.md ================================================ # Designing an ATM System ## Requirements 1. The ATM system should support basic operations such as balance inquiry, cash withdrawal, and cash deposit. 2. Users should be able to authenticate themselves using a card and a PIN (Personal Identification Number). 3. The system should interact with a bank's backend system to validate user accounts and perform transactions. 4. The ATM should have a cash dispenser to dispense cash to users. 5. The system should handle concurrent access and ensure data consistency. 6. The ATM should have a user-friendly interface for users to interact with. ## Classes, Interfaces and Enumerations 1. The **Card** class represents an ATM card with a card number and PIN. 2. The **Account** class represents a bank account with an account number and balance. It provides methods to debit and credit the account balance. 3. The **Transaction** class is an abstract base class for different types of transactions, such as withdrawal and deposit. It is extended by WithdrawalTransaction and DepositTransaction classes. 4. The **BankingService** class manages the bank accounts and processes transactions. It uses a thread-safe ConcurrentHashMap to store and retrieve account information. 5. The **CashDispenser** class represents the ATM's cash dispenser and handles the dispensing of cash. It uses synchronization to ensure thread safety when dispensing cash. 6. The **ATM** class serves as the main interface for ATM operations. It interacts with the BankingService and CashDispenser to perform user authentication, balance inquiry, cash withdrawal, and cash deposit. 7. The **ATMDriver** class demonstrates the usage of the ATM system by creating sample accounts and performing ATM operations. ================================================ FILE: solutions/python/carrentalsystem/README.md ================================================ # Designing a Car Rental System ## Requirements 1. The car rental system should allow customers to browse and reserve available cars for specific dates. 2. Each car should have details such as make, model, year, license plate number, and rental price per day. 3. Customers should be able to search for cars based on various criteria, such as car type, price range, and availability. 4. The system should handle reservations, including creating, modifying, and canceling reservations. 5. The system should keep track of the availability of cars and update their status accordingly. 6. The system should handle customer information, including name, contact details, and driver's license information. 7. The system should handle payment processing for reservations. 8. The system should be able to handle concurrent reservations and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Car** class represents a car in the rental system, with properties such as make, model, year, license plate number, rental price per day, and availability status. 2. The **Customer** class represents a customer, with properties like name, contact information, and driver's license number. 3. The **Reservation** class represents a reservation made by a customer for a specific car and date range. It includes properties such as reservation ID, customer, car, start date, end date, and total price. 4. The **PaymentProcessor** interface defines the contract for payment processing, and the CreditCardPaymentProcessor and PayPalPaymentProcessor classes are concrete implementations of the payment processor. 5. The **RentalSystem** class is the core of the car rental system and follows the Singleton pattern to ensure a single instance of the rental system. 6. The RentalSystem class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to cars and reservations. 7. The **RentalSystem** class provides methods for adding and removing cars, searching for available cars based on criteria, making reservations, canceling reservations, and processing payments. 8. The **CarRentalSystem** class serves as the entry point of the application and demonstrates the usage of the car rental system. ================================================ FILE: solutions/python/chessgame/README.md ================================================ # Designing a Chess Game ## Requirements 1. The chess game should follow the standard rules of chess. 2. The game should support two players, each controlling their own set of pieces. 3. The game board should be represented as an 8x8 grid, with alternating black and white squares. 4. Each player should have 16 pieces: 1 king, 1 queen, 2 rooks, 2 bishops, 2 knights, and 8 pawns. 5. The game should validate legal moves for each piece and prevent illegal moves. 6. The game should detect checkmate and stalemate conditions. 7. The game should handle player turns and allow players to make moves alternately. 8. The game should provide a user interface for players to interact with the game. ## Classes, Interfaces and Enumerations 1. The **Piece** class is an abstract base class representing a chess piece. It contains common attributes such as color, row, and column, and declares an abstract method canMove to be implemented by each specific piece class. 2. The **King**, **Queen**, **Rook**, **Bishop**, **Knight**, and **Pawn** classes extend the Piece class and implement their respective movement logic in the canMove method. 3. The **Board** class represents the chess board and manages the placement of pieces. It provides methods to get and set pieces on the board, check the validity of moves, and determine checkmate and stalemate conditions. 4. The **Player** class represents a player in the game and has a method to make a move on the board. 5. The Move class represents a move made by a player, containing the piece being moved and the destination coordinates. 6. The **Game** class orchestrates the overall game flow. It initializes the board, handles player turns, and determines the game result. 7. The **ChessGame** class is the entry point of the application and starts the game. ================================================ FILE: solutions/python/coffeevendingmachine/README.md ================================================ # Designing a Coffee Vending Machine ## Requirements 1. The coffee vending machine should support different types of coffee, such as espresso, cappuccino, and latte. 2. Each type of coffee should have a specific price and recipe (ingredients and their quantities). 3. The machine should have a menu to display the available coffee options and their prices. 4. Users should be able to select a coffee type and make a payment. 5. The machine should dispense the selected coffee and provide change if necessary. 6. The machine should track the inventory of ingredients and notify when they are running low. 7. The machine should handle multiple user requests concurrently and ensure thread safety. ## Classes, Interfaces and Enumerations 1. The **Coffee** class represents a coffee type with its name, price, and recipe (ingredients and their quantities). 2. The **Ingredient** class represents an ingredient used in making coffee, with its name and quantity. It provides a synchronized method to update the quantity. 3. The **Payment** class represents a payment made by a user, with the amount paid. 4. The **CoffeeMachine** class is the main class that manages the coffee vending machine. It follows the Singleton pattern to ensure a single instance of the machine. 5. The **CoffeeMachine** class initializes the coffee menu and ingredients in its constructor. It provides methods to display the menu, select a coffee, dispense coffee, and update ingredient quantities. 6. The hasEnoughIngredients method checks if there are sufficient ingredients to make a selected coffee, while the updateIngredients method updates the ingredient quantities after dispensing a coffee. 7. The **CoffeeVendingMachine** class is the entry point of the application and demonstrates the usage of the coffee vending machine. It creates an instance of the machine, displays the menu, and simulates concurrent user requests using an ExecutorService. ================================================ FILE: solutions/python/concertticketbookingsystem/README.md ================================================ # Designing a Concert Ticket Booking System ## Requirements 1. The concert ticket booking system should allow users to view available concerts and their seating arrangements. 2. Users should be able to search for concerts based on various criteria such as artist, venue, date, and time. 3. Users should be able to select seats and purchase tickets for a specific concert. 4. The system should handle concurrent booking requests to avoid double-booking of seats. 5. The system should ensure fair booking opportunities for all users. 6. The system should handle payment processing securely. 7. The system should generate booking confirmations and send them to users via email or SMS. 8. The system should provide a waiting list functionality for sold-out concerts. ## Classes, Interfaces and Enumerations 1. The **Concert** class represents a concert event, with properties such as ID, artist, venue, date and time, and a list of seats. 2. The **Seat** class represents a seat in a concert, with properties like ID, seat number, seat type, price, and status. It provides methods to book and release a seat. 3. The **SeatType** enum represents the different types of seats available, such as regular, premium, and VIP. 4. The **SeatStatus** enum represents the status of a seat, which can be available, booked, or reserved. 5. The **Booking** class represents a booking made by a user for a specific concert and seats. It contains properties such as ID, user, concert, seats, total price, and status. It provides methods to confirm and cancel a booking. 6. The **BookingStatus** enum represents the status of a booking, which can be pending, confirmed, or cancelled. 7. The **User** class represents a user of the concert ticket booking system, with properties like ID, name, and email. 8. The **ConcertTicketBookingSystem** class is the central component of the system. It follows the Singleton pattern to ensure a single instance of the system. It manages concerts, bookings, and provides methods to add concerts, search concerts, book tickets, and cancel bookings. 9. The **SeatNotAvailableException** is a custom exception used to handle cases where a seat is not available for booking. ================================================ FILE: solutions/python/courseregistrationsystem/README.md ================================================ # Designing a University Course Registration System ## Requirements 1. The course registration system should allow students to register for courses and view their registered courses. 2. Each course should have a course code, name, instructor, and maximum enrollment capacity. 3. Students should be able to search for courses based on course code or name. 4. The system should prevent students from registering for courses that have reached their maximum enrollment capacity. 5. The system should handle concurrent registration requests from multiple students. 6. The system should ensure data consistency and prevent race conditions. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Student** class represents a student in the course registration system, with properties such as ID, name, email, and a list of registered courses. 2. The **Course** class represents a course offered in the system, with properties such as code, name, instructor, maximum capacity, and the number of enrolled students. 3. The **Registration** class represents a registration record, associating a student with a course and capturing the registration timestamp. 4. The **CourseRegistrationSystem** class is the main class that manages the course registration system. It follows the Singleton pattern to ensure only one instance of the system exists. 5. The CourseRegistrationSystem class provides methods for adding courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. 6. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as courses and registrations. 7. The registerCourse method is synchronized to ensure thread safety when multiple students are registering for courses simultaneously. 8. The notifyObservers method is a placeholder for notifying observers (e.g., UI components) about updates to course enrollment. 9. The **CourseRegistrationDemo** class demonstrates the usage of the course registration system by creating courses and students, searching for courses, registering students for courses, and retrieving registered courses for a student. ================================================ FILE: solutions/python/cricinfo/README.md ================================================ # Designing a Cricket Information System like CricInfo ## Requirements 1. The Cricinfo system should provide information about cricket matches, teams, players, and live scores. 2. Users should be able to view the schedule of upcoming matches and the results of completed matches. 3. The system should allow users to search for specific matches, teams, or players. 4. Users should be able to view detailed information about a particular match, including the scorecard, commentary, and statistics. 5. The system should support real-time updates of live scores and match information. 6. The system should handle concurrent access to match data and ensure data consistency. 7. The system should be scalable and able to handle a large volume of user requests. 8. The system should be extensible to accommodate new features and enhancements in the future. ## Classes, Interfaces and Enumerations 1. The **Match** class represents a cricket match, with properties such as ID, title, venue, start time, teams, status, and scorecard. 2. The **Team** class represents a cricket team, with properties like ID, name, and a list of players. 3. The **Player** class represents a cricket player, with properties such as ID, name, and role. 4. The **Scorecard** class represents the scorecard of a match, containing team scores and a list of innings. 5. The **Innings** class represents an innings in a match, with properties like ID, batting team, bowling team, and a list of overs. 6. The **Over** class represents an over in an innings, containing a list of balls. 7. The **Ball** class represents a ball bowled in an over, with properties such as ball number, bowler, batsman, and result. 8. The **MatchStatus** enum represents the different statuses of a match, such as scheduled, in progress, completed, or abandoned. 9. The **MatchService** class manages the matches in the system, providing methods to add, retrieve, and update match information. It follows the Singleton pattern to ensure a single instance of the service. 10. The **ScorecardService** class manages the scorecards of matches, allowing the creation, retrieval, and update of scorecards and their associated data, such as innings and scores. It also follows the Singleton pattern. 11. The **CricinfoSystem** class serves as the main entry point of the system, integrating the match and scorecard services and providing high-level methods for interacting with the system. ================================================ FILE: solutions/python/digitalwalletservice/README.md ================================================ # Designing a Digital Wallet System ## Requirements 1. The digital wallet should allow users to create an account and manage their personal information. 2. Users should be able to add and remove payment methods, such as credit cards or bank accounts. 3. The digital wallet should support fund transfers between users and to external accounts. 4. The system should handle transaction history and provide a statement of transactions. 5. The digital wallet should support multiple currencies and perform currency conversions. 6. The system should ensure the security of user information and transactions. 7. The digital wallet should handle concurrent transactions and ensure data consistency. 8. The system should be scalable to handle a large number of users and transactions. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the digital wallet, with properties such as ID, name, email, password, and a list of accounts. 2. The **Account** class represents a user's account within the digital wallet, with properties like ID, user, account number, currency, balance, and a list of transactions. It provides methods to deposit and withdraw funds. 3. The **Transaction** class represents a financial transaction between two accounts, containing properties such as ID, source account, destination account, amount, currency, and timestamp. 4. The **PaymentMethod** class is an abstract base class for different payment methods, such as credit cards and bank accounts. It defines the common properties and methods for processing payments. 5. The **CreditCard** and **BankAccount** classes are concrete implementations of the PaymentMethod class, representing specific payment methods. 6. The **Currency** enum represents different currencies supported by the digital wallet. 7. The **CurrencyConverter** class provides a static method to convert amounts between different currencies based on predefined exchange rates. 8. The **DigitalWallet** class is the central component of the digital wallet system. It follows the Singleton pattern to ensure only one instance of the digital wallet exists. It provides methods to create users, accounts, add payment methods, transfer funds, and retrieve transaction history. It handles concurrent access to shared resources using synchronization. 9. The **DigitalWalletDemo** class demonstrates the usage of the digital wallet system by creating users, accounts, adding payment methods, depositing funds, transferring funds, and retrieving transaction history. ================================================ FILE: solutions/python/elevatorsystem/README.md ================================================ # Designing an Elevator System ## Requirements 1. The elevator system should consist of multiple elevators serving multiple floors. 2. Each elevator should have a capacity limit and should not exceed it. 3. Users should be able to request an elevator from any floor and select a destination floor. 4. The elevator system should efficiently handle user requests and optimize the movement of elevators to minimize waiting time. 5. The system should prioritize requests based on the direction of travel and the proximity of the elevators to the requested floor. 6. The elevators should be able to handle multiple requests concurrently and process them in an optimal order. 7. The system should ensure thread safety and prevent race conditions when multiple threads interact with the elevators. ## Classes, Interfaces and Enumerations 1. The **Direction** enum represents the possible directions of elevator movement (UP or DOWN). 2. The **Request** class represents a user request for an elevator, containing the source floor and destination floor. 3. The **Elevator** class represents an individual elevator in the system. It has a capacity limit and maintains a list of 4. requests. The elevator processes requests concurrently and moves between floors based on the requests. 4. The **ElevatorController** class manages multiple elevators and handles user requests. It finds the optimal elevator to serve a request based on the proximity of the elevators to the requested floor. 5. The **ElevatorSystem** class is the entry point of the application and demonstrates the usage of the elevator system. ================================================ FILE: solutions/python/fooddeliveryservice/README.md ================================================ # Designing an Online Food Delivery Service Like Swiggy ## Requirements 1. The food delivery service should allow customers to browse restaurants, view menus, and place orders. 2. Restaurants should be able to manage their menus, prices, and availability. 3. Delivery agents should be able to accept and fulfill orders. 4. The system should handle order tracking and status updates. 5. The system should support multiple payment methods. 6. The system should handle concurrent orders and ensure data consistency. 7. The system should be scalable and handle a high volume of orders. 8. The system should provide real-time notifications to customers, restaurants, and delivery agents. ## Classes, Interfaces and Enumerations 1. The **Customer** class represents a customer who can place orders. It contains customer details such as ID, name, email, and phone number. 2. The **Restaurant** class represents a restaurant that offers menu items. It contains restaurant details such as ID, name, address, and a list of menu items. It provides methods to add and remove menu items. 3. The **MenuItem** class represents an item on a restaurant's menu. It contains details such as ID, name, description, price, and availability status. 4. The **Order** class represents an order placed by a customer. It contains order details such as ID, customer, restaurant, list of order items, status, and assigned delivery agent. It provides methods to add and remove order items, update order status, and assign a delivery agent. 5. The **OrderItem** class represents an item within an order. It contains the selected menu item and the quantity ordered. 6. The **OrderStatus** enum represents the different statuses an order can have, such as PENDING, CONFIRMED, PREPARING, OUT_FOR_DELIVERY, DELIVERED, and CANCELLED. 7. The **DeliveryAgent** class represents a delivery agent who fulfills orders. It contains details such as ID, name, phone number, and availability status. 8. The **FoodDeliveryService** class is the main class that manages the food delivery service. It follows the Singleton pattern to ensure only one instance of the service exists. It provides methods to register customers, restaurants, and delivery agents, retrieve available restaurants and menus, place orders, update order status, cancel orders, and assign delivery agents to orders. It also handles notifications to customers, restaurants, and delivery agents. ================================================ FILE: solutions/python/hotelmanagementsystem/README.md ================================================ # Designing a Hotel Management System ## Requirements 1. The hotel management system should allow guests to book rooms, check-in, and check-out. 2. The system should manage different types of rooms, such as single, double, deluxe, and suite. 3. The system should handle room availability and reservation status. 4. The system should allow the hotel staff to manage guest information, room assignments, and billing. 5. The system should support multiple payment methods, such as cash, credit card, and online payment. 6. The system should handle concurrent bookings and ensure data consistency. 7. The system should provide reporting and analytics features for hotel management. 8. The system should be scalable and handle a large number of rooms and guests. ## Classes, Interfaces and Enumerations 1. The **Guest** class represents a guest of the hotel, with properties such as ID, name, email, and phone number. 2. The **Room** class represents a room in the hotel, with properties like ID, room type, price, and status. It provides methods to book, check-in, and check-out a room. 3. The **RoomType** enum represents the different types of rooms available in the hotel. 4. The **RoomStatus** enum represents the status of a room, which can be available, booked, or occupied. 5. The **Reservation** class represents a reservation made by a guest for a specific room and date range. It contains properties such as ID, guest, room, check-in date, check-out date, and status. It provides a method to cancel a reservation. 6. The **ReservationStatus** enum represents the status of a reservation, which can be confirmed or cancelled. 7. The **Payment** interface defines the contract for processing payments. It is implemented by concrete payment classes like CashPayment and CreditCardPayment. 8. The **HotelManagementSystem** class is the central component of the hotel management system. It follows the Singleton pattern to ensure only one instance of the system exists. It provides methods to add guests and rooms, book rooms, cancel reservations, check-in, check-out, and process payments. It also handles concurrent access to shared resources using synchronization. 9. The **HotelManagementSystemDemo** class demonstrates the usage of the hotel management system by creating guests, rooms, booking a room, checking in, checking out, and cancelling a reservation. ================================================ FILE: solutions/python/librarymanagementsystem/README.md ================================================ # Designing a Library Management System ## Requirements 1. The library management system should allow librarians to manage books, members, and borrowing activities. 2. The system should support adding, updating, and removing books from the library catalog. 3. Each book should have details such as title, author, ISBN, publication year, and availability status. 4. The system should allow members to borrow and return books. 5. Each member should have details such as name, member ID, contact information, and borrowing history. 6. The system should enforce borrowing rules, such as a maximum number of books that can be borrowed at a time and loan duration. 7. The system should handle concurrent access to the library catalog and member records. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **Book** class represents a book in the library catalog, with properties such as ISBN, title, author, publication year, and availability status. 2. The **Member** class represents a library member, with properties like member ID, name, contact information, and a list of borrowed books. 3. The **LibraryManager** class is the core of the library management system and follows the Singleton pattern to ensure a single instance of the library manager. 4. The LibraryManager class uses concurrent data structures (ConcurrentHashMap) to handle concurrent access to the library catalog and member records. 5. The LibraryManager class provides methods for adding and removing books, registering and unregistering members, borrowing and returning books, and searching for books based on keywords. 6. The **LibraryManagementSystemDemo** class serves as the entry point of the application and demonstrates the usage of the library management system. ================================================ FILE: solutions/python/linkedin/README.md ================================================ # Designing a Professional Networking Platform like LinkedIn ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their professional information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their professional information, such as profile picture, headline, summary, experience, education, and skills. - Users should be able to update their profile information. #### Connections: - Users should be able to send connection requests to other users. - Users should be able to accept or decline connection requests. - Users should be able to view their list of connections. #### Messaging: - Users should be able to send messages to their connections. - Users should be able to view their inbox and sent messages. #### Job Postings: - Employers should be able to post job listings with details such as title, description, requirements, and location. - Users should be able to view and apply for job postings. #### Search Functionality: - Users should be able to search for other users, companies, and job postings based on relevant criteria. - Search results should be ranked based on relevance and user preferences. #### Notifications: - Users should receive notifications for events such as connection requests, messages, and job postings. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the LinkedIn system, containing properties such as ID, name, email, password, profile, connections, inbox, and sent messages. 2. The **Profile** class represents a user's profile, containing properties such as profile picture, headline, summary, experiences, educations, and skills. 3. The **Experience**, **Education**, and **Skill** classes represent different components of a user's profile. 4. The **Connection** class represents a connection between two users, containing the user and the connection date. 5. The **Message** class represents a message sent between users, containing properties such as ID, sender, receiver, content, and timestamp. 6. The **JobPosting** class represents a job listing posted by an employer, containing properties such as ID, title, description, requirements, location, and post date. 7. The **Notification** class represents a notification generated for a user, containing properties such as ID, user, notification type, content, and timestamp. 8. The **NotificationType** enum defines the different types of notifications, such as connection request, message, and job posting. 9. The **LinkedInService** class is the main class that manages the LinkedIn system. It follows the Singleton pattern to ensure only one instance of the service exists. 10. The **LinkedInService** class provides methods for user registration, login, profile updates, connection requests, job postings, user and job search, messaging, and notifications. 11. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 12. The **LinkedInDemo** class demonstrates the usage of the LinkedIn system by registering users, logging in, updating profiles, sending connection requests, posting job listings, searching for users and jobs, sending messages, and retrieving notifications. ================================================ FILE: solutions/python/loggingframework/README.md ================================================ # Designing a Logging Framework ## Requirements 1. The logging framework should support different log levels, such as DEBUG, INFO, WARNING, ERROR, and FATAL. 2. It should allow logging messages with a timestamp, log level, and message content. 3. The framework should support multiple output destinations, such as console, file, and database. 4. It should provide a configuration mechanism to set the log level and output destination. 5. The logging framework should be thread-safe to handle concurrent logging from multiple threads. 6. It should be extensible to accommodate new log levels and output destinations in the future. ## Classes, Interfaces and Enumerations 1. The **LogLevel** enum defines the different log levels supported by the logging framework. 2. The **LogMessage** class represents a log message with a timestamp, log level, and message content. 3. The **LogAppender** interface defines the contract for appending log messages to different output destinations. 4. The **ConsoleAppender**, **FileAppender**, and **DatabaseAppender** classes are concrete implementations of the LogAppender interface, supporting logging to the console, file, and database, respectively. 5. The **LoggerConfig** class holds the configuration settings for the logger, including the log level and the selected log appender. 6. The **Logger** class is a singleton that provides the main logging functionality. It allows setting the configuration, logging messages at different levels, and provides convenience methods for each log level. 7. The **LoggingExample** class demonstrates the usage of the logging framework, showcasing different log levels, changing the configuration, and logging from multiple threads. ================================================ FILE: solutions/python/lrucache/README.md ================================================ # Designing a LRU Cache ## Requirements 1. The LRU cache should support the following operations: - put(key, value): Insert a key-value pair into the cache. If the cache is at capacity, remove the least recently used item before inserting the new item. - get(key): Get the value associated with the given key. If the key exists in the cache, move it to the front of the cache (most recently used) and return its value. If the key does not exist, return -1. 2. The cache should have a fixed capacity, specified during initialization. 3. The cache should be thread-safe, allowing concurrent access from multiple threads. 4. The cache should be efficient in terms of time complexity for both put and get operations, ideally O(1). ## Classes, Interfaces and Enumerations 1. The **Node** class represents a node in the doubly linked list, containing the key, value, and references to the previous and next nodes. 2. The **LRUCache** class implements the LRU cache functionality using a combination of a hash map (cache) and a doubly linked list (head and tail). 3. The get method retrieves the value associated with a given key. If the key exists in the cache, it is moved to the head of the linked list (most recently used) and its value is returned. If the key does not exist, null is returned. 4. The put method inserts a key-value pair into the cache. If the key already exists, its value is updated, and the node is moved to the head of the linked list. If the key does not exist and the cache is at capacity, the least recently used item (at the tail of the linked list) is removed, and the new item is inserted at the head. 5. The addToHead, removeNode, moveToHead, and removeTail methods are helper methods to manipulate the doubly linked list. 6. The synchronized keyword is used on the get and put methods to ensure thread safety, allowing concurrent access from multiple threads. 7. The **LRUCacheDemo** class demonstrates the usage of the LRU cache by creating an instance of LRUCache with a capacity of 3, performing various put and get operations, and printing the results. ================================================ FILE: solutions/python/movieticketbookingsystem/README.md ================================================ # Designing a Movie Ticket Booking System like BookMyShow ## Requirements 1. The system should allow users to view the list of movies playing in different theaters. 2. Users should be able to select a movie, theater, and show timing to book tickets. 3. The system should display the seating arrangement of the selected show and allow users to choose seats. 4. Users should be able to make payments and confirm their booking. 5. The system should handle concurrent bookings and ensure seat availability is updated in real-time. 6. The system should support different types of seats (e.g., normal, premium) and pricing. 7. The system should allow theater administrators to add, update, and remove movies, shows, and seating arrangements. 8. The system should be scalable to handle a large number of concurrent users and bookings. ## Classes, Interfaces and Enumerations 1. The **Movie** class represents a movie with properties such as ID, title, description, and duration. 2. The **Theater** class represents a theater with properties such as ID, name, location, and a list of shows. 3. The **Show** class represents a movie show in a theater, with properties such as ID, movie, theater, start time, end time, and a map of seats. 4. The **Seat** class represents a seat in a show, with properties such as ID, row, column, type, price, and status. 5. The **SeatType** enum defines the different types of seats (normal or premium). 6. The **SeatStatus** enum defines the different statuses of a seat (available or booked). 7. The **Booking** class represents a booking made by a user, with properties such as ID, user, show, selected seats, total price, and status. 8. The **BookingStatus** enum defines the different statuses of a booking (pending, confirmed, or cancelled). 9. The **User** class represents a user of the booking system, with properties such as ID, name, and email. 10. The **MovieTicketBookingSystem** class is the main class that manages the movie ticket booking system. It follows the Singleton pattern to ensure only one instance of the system exists. 11. The MovieTicketBookingSystem class provides methods for adding movies, theaters, and shows, as well as booking tickets, confirming bookings, and cancelling bookings. 12. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap to handle concurrent access to shared resources like shows and bookings. 13. The **MovieTicketBookingDemo** class demonstrates the usage of the movie ticket booking system by adding movies, theaters, shows, booking tickets, and confirming or cancelling bookings. ================================================ FILE: solutions/python/musicstreamingservice/README.md ================================================ # Designing an Online Music Streaming Service Like Spotify ## Requirements 1. The music streaming service should allow users to browse and search for songs, albums, and artists. 2. Users should be able to create and manage playlists. 3. The system should support user authentication and authorization. 4. Users should be able to play, pause, skip, and seek within songs. 5. The system should recommend songs and playlists based on user preferences and listening history. 6. The system should handle concurrent requests and ensure smooth streaming experience for multiple users. 7. The system should be scalable and handle a large volume of songs and users. 8. The system should be extensible to support additional features such as social sharing and offline playback. ## Classes, Interfaces and Enumerations 1. The **Song**, **Album**, and **Artist** classes represent the basic entities in the music streaming service, with properties such as ID, title, artist, album, duration, and relationships between them. 2. The **User** class represents a user of the music streaming service, with properties like ID, username, password, and a list of playlists. 3. The **Playlist** class represents a user-created playlist, containing a list of songs. 4. The **MusicLibrary** class serves as a central repository for storing and managing songs, albums, and artists. It follows the Singleton pattern to ensure a single instance of the music library. 5. The **UserManager** class handles user registration, login, and other user-related operations. It also follows the Singleton pattern. 6. The **MusicPlayer** class represents the music playback functionality, allowing users to play, pause, skip, and seek within songs. 7. The **MusicRecommender** class generates song recommendations based on user preferences and listening history. It follows the Singleton pattern. 8. The **MusicStreamingService** class is the main entry point of the music streaming service. It initializes the necessary components, handles user requests, and manages the overall functionality of the service. ================================================ FILE: solutions/python/onlineauctionsystem/README.md ================================================ # Designing an Online Auction System In this article, we delve into the object-oriented design and implementation of an Online Auction System using Java. This system allows for the creation and management of auctions, user participation in bidding, and handling transactions. ## Requirements 1. The online auction system should allow users to register and log in to their accounts. 2. Users should be able to create new auction listings with details such as item name, description, starting price, and auction duration. 3. Users should be able to browse and search for auction listings based on various criteria (e.g., item name, category, price range). 4. Users should be able to place bids on active auction listings. 5. The system should automatically update the current highest bid and notify the bidders accordingly. 6. The auction should end when the specified duration is reached, and the highest bidder should be declared the winner. 7. The system should handle concurrent access to auction listings and ensure data consistency. 8. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the online auction system, with properties such as id, username, and email. 2. The **AuctionStatus** enum defines the possible states of an auction listing, such as active and closed. 3. The **AuctionListing** class represents an auction listing in the system, with properties like id, item name, description, starting price, duration, seller, current highest bid, and a list of bids. 4. The **Bid** class represents a bid placed by a user on an auction listing, with properties such as id, bidder, amount, and timestamp. 5. The **AuctionSystem** class is the core of the online auction system and follows the Singleton pattern to ensure a single instance of the auction system. 6. The AuctionSystem class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to auction listings and ensure thread safety. 7. The AuctionSystem class provides methods for registering users, creating auction listings, searching auction listings, and placing bids. 8. The **AuctionSystemDemo** class serves as the entry point of the application and demonstrates the usage of the online auction system. ================================================ FILE: solutions/python/onlinestockbrokeragesystem/README.md ================================================ # Designing an Online Stock Brokerage System ## Requirements 1. The online stock brokerage system should allow users to create and manage their trading accounts. 2. Users should be able to buy and sell stocks, as well as view their portfolio and transaction history. 3. The system should provide real-time stock quotes and market data to users. 4. The system should handle order placement, execution, and settlement processes. 5. The system should enforce various business rules and validations, such as checking account balances and stock availability. 6. The system should handle concurrent user requests and ensure data consistency and integrity. 7. The system should be scalable and able to handle a large number of users and transactions. 8. The system should be secure and protect sensitive user information. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the stock brokerage system, with properties such as user ID, name, and email. 2. The **Account** class represents a user's trading account, with properties like account ID, associated user, and balance. It provides methods for depositing and withdrawing funds. 3. The **Stock** class represents a stock that can be traded, with properties such as symbol, name, and price. It provides a method for updating the stock price. 4. The **Order** class is an abstract base class representing an order placed by a user. It contains common properties such as order ID, associated account, stock, quantity, price, and order status. The execute() method is declared as abstract, to be implemented by concrete order classes. 5. The **BuyOrder** and **SellOrder** classes are concrete implementations of the Order class, representing buy and sell orders respectively. They provide the implementation for the execute() method specific to each order type. 6. The **OrderStatus** enum represents the possible statuses of an order, such as PENDING, EXECUTED, or REJECTED. 7. The **Portfolio** class represents a user's portfolio, which holds the stocks owned by the user. It provides methods for adding and removing stocks from the portfolio. 8. The **StockBroker** class is the central component of the stock brokerage system. It follows the Singleton pattern to ensure a single instance of the stock broker. It manages user accounts, stocks, and order processing. It provides methods for creating accounts, adding stocks, placing orders, and processing orders. 9. The **InsufficientFundsException** and **InsufficientStockException** classes are custom exceptions used to handle insufficient funds and insufficient stock scenarios respectively. 10. The **StockBrokerageSystem** class serves as the entry point of the application and demonstrates the usage of the stock brokerage system. ================================================ FILE: solutions/python/parkinglot/README.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot should have multiple levels, each level with a certain number of parking spots. 2. The parking lot should support different types of vehicles, such as cars, motorcycles, and trucks. 3. Each parking spot should be able to accommodate a specific type of vehicle. 4. The system should assign a parking spot to a vehicle upon entry and release it when the vehicle exits. 5. The system should track the availability of parking spots and provide real-time information to customers. 6. The system should handle multiple entry and exit points and support concurrent access. ## Classes, Interfaces and Enumerations 1. The **ParkingLot** class follows the Singleton pattern to ensure only one instance of the parking lot exists. It maintains a list of levels and provides methods to park and unpark vehicles. 2. The **ParkingFloor** class represents a level in the parking lot and contains a list of parking spots. It handles parking and unparking of vehicles within the level. 3. The **ParkingSpot** class represents an individual parking spot and tracks the availability and the parked vehicle. 4. The **Vehicle** class is an abstract base class for different types of vehicles. It is extended by Car, Motorcycle, and Truck classes. 5. The **VehicleType** enum defines the different types of vehicles supported by the parking lot. 6. Multi-threading is achieved through the use of synchronized keyword on critical sections to ensure thread safety. 7. The **Main** class demonstrates the usage of the parking lot system. ## Design Patterns Used: 1. Singleton Pattern: Ensures only one instance of the ParkingLot class. 2. Factory Pattern (optional extension): Could be used for creating vehicles based on input. 3. Observer Pattern (optional extension): Could notify customers about available spots. ================================================ FILE: solutions/python/pubsubsystem/README.md ================================================ # Designing a Pub-Sub System in Java ## Requirements 1. The Pub-Sub system should allow publishers to publish messages to specific topics. 2. Subscribers should be able to subscribe to topics of interest and receive messages published to those topics. 3. The system should support multiple publishers and subscribers. 4. Messages should be delivered to all subscribers of a topic in real-time. 5. The system should handle concurrent access and ensure thread safety. 6. The Pub-Sub system should be scalable and efficient in terms of message delivery. ## Classes, Interfaces and Enumerations 1. The **Message** class represents a message that can be published and received by subscribers. It contains the message content. 2. The **Topic** class represents a topic to which messages can be published. It maintains a set of subscribers and provides methods to add and remove subscribers, as well as publish messages to all subscribers. 3. The **Subscriber** interface defines the contract for subscribers. It declares the onMessage method that is invoked when a subscriber receives a message. 4. The **PrintSubscriber** class is a concrete implementation of the Subscriber interface. It receives messages and prints them to the console. 5. The **Publisher** class represents a publisher that publishes messages to a specific topic. 6. The **PubSubSystem** class is the main class that manages topics, subscribers, and message publishing. It uses a ConcurrentHashMap to store topics and an ExecutorService to handle concurrent message publishing. 7. The **PubSubDemo** class demonstrates the usage of the Pub-Sub system by creating topics, subscribers, and publishers, and publishing messages. ================================================ FILE: solutions/python/restaurantmanagementsystem/README.md ================================================ # Designing Restaurant Management System ## Requirements 1. The restaurant management system should allow customers to place orders, view the menu, and make reservations. 2. The system should manage the restaurant's inventory, including ingredients and menu items. 3. The system should handle order processing, including order preparation, billing, and payment. 4. The system should support multiple payment methods, such as cash, credit card, and mobile payments. 5. The system should manage staff information, including roles, schedules, and performance tracking. 6. The system should generate reports and analytics for management, such as sales reports and inventory analysis. 7. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **MenuItem** class represents a menu item in the restaurant, with properties such as ID, name, description, price, and availability. 2. The **Order** class represents an order placed by a customer, with properties such as ID, list of menu items, total amount, order status, and timestamp. 3. The **OrderStatus** enum represents the different statuses an order can have, such as pending, preparing, ready, completed, or cancelled. 4. The **Reservation** class represents a reservation made by a customer, with properties such as ID, customer name, contact number, party size, and reservation time. 5. The **Payment** class represents a payment made for an order, with properties such as ID, amount, payment method, and payment status. 6. The **PaymentMethod** enum represents the different payment methods supported by the restaurant, such as cash, credit card, or mobile payment. 7. The **PaymentStatus** enum represents the status of a payment, which can be pending, completed, or failed. 8. The Staff class represents a staff member of the restaurant, with properties such as ID, name, role, and contact number. 9. The **Restaurant** class is the main class that manages the restaurant operations. It follows the Singleton pattern to ensure only one instance of the restaurant exists. 10. The Restaurant class provides methods for managing menu items, placing orders, updating order status, making reservations, processing payments, and managing staff. 11. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to shared data, such as orders and reservations. 12. The notifyKitchen and notifyStaff methods are placeholders for notifying relevant staff about order updates and status changes. 13. The **RestaurantManagementDemo** class demonstrates the usage of the restaurant management system by adding menu items, placing an order, making a reservation, processing a payment, updating order status, adding staff, and retrieving the menu. ================================================ FILE: solutions/python/ridesharingservice/README.md ================================================ # Designing a Ride-Sharing Service Like Uber ## Requirements 1. The ride sharing service should allow passengers to request rides and drivers to accept and fulfill those ride requests. 2. Passengers should be able to specify their pickup location, destination, and desired ride type (e.g., regular, premium). 3. Drivers should be able to see available ride requests and choose to accept or decline them. 4. The system should match ride requests with available drivers based on proximity and other factors. 5. The system should calculate the fare for each ride based on distance, time, and ride type. 6. The system should handle payments and process transactions between passengers and drivers. 7. The system should provide real-time tracking of ongoing rides and notify passengers and drivers about ride status updates. 8. The system should handle concurrent requests and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **Passenger** class represents a passenger in the ride sharing service, with properties such as ID, name, contact information, and location. 2. The **Driver** class represents a driver in the ride sharing service, with properties such as ID, name, contact information, license plate, location, and status (available or busy). 3. The **Ride** class represents a ride requested by a passenger and accepted by a driver, with properties such as ID, passenger, driver, source location, destination location, status, and fare. 4. The **Location** class represents a geographical location with latitude and longitude coordinates. 5. The **Payment** class represents a payment made for a ride, with properties such as ID, ride, amount, and payment status. 6. The **RideService** class is the main class that manages the ride sharing service. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The RideService class provides methods for adding passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. 8. Multi-threading is implemented using concurrent data structures (ConcurrentHashMap and ConcurrentLinkedQueue) to handle concurrent access to shared data, such as ride requests and driver availability. 9. The notifyDrivers, notifyPassenger, and notifyDriver methods are placeholders for notifying relevant parties about ride status updates. 10. The calculateFare and processPayment methods are placeholders for calculating ride fares and processing payments, respectively. 11. The **RideSharingDemo** class demonstrates the usage of the ride sharing service by creating passengers and drivers, requesting rides, accepting rides, starting rides, completing rides, and canceling rides. ================================================ FILE: solutions/python/snakeandladdergame/README.md ================================================ # Designing Snake and Ladder Game ## Requirements 1. The game should be played on a board with numbered cells, typically with 100 cells. 2. The board should have a predefined set of snakes and ladders, connecting certain cells. 3. The game should support multiple players, each represented by a unique game piece. 4. Players should take turns rolling a dice to determine the number of cells to move forward. 5. If a player lands on a cell with the head of a snake, they should slide down to the cell with the tail of the snake. 6. If a player lands on a cell with the base of a ladder, they should climb up to the cell at the top of the ladder. 7. The game should continue until one of the players reaches the final cell on the board. 8. The game should handle multiple game sessions concurrently, allowing different groups of players to play independently. ## Classes, Interfaces and Enumerations 1. The **Board** class represents the game board with a fixed size (e.g., 100 cells). It contains the positions of snakes and ladders and provides methods to initialize them and retrieve the new position after encountering a snake or ladder. 2. The **Player** class represents a player in the game, with properties such as name and current position on the board. 3. The **Snake** class represents a snake on the board, with properties for the start and end positions. 4. The **Ladder** class represents a ladder on the board, with properties for the start and end positions. 5. The **Dice** class represents a dice used in the game, with a method to roll the dice and return a random value between 1 and 6. 6. The **SnakeAndLadderGame** class represents a single game session. It initializes the game with a board, a list of players, and a dice. The play method handles the game loop, where players take turns rolling the dice and moving their positions on the board. It checks for snakes and ladders and updates the player's position accordingly. The game continues until a player reaches the final position on the board. 7. The **GameManager** class is a singleton that manages multiple game sessions. It maintains a list of active games and provides a method to start a new game with a list of player names. Each game is started in a separate thread to allow concurrent game sessions. 8. The **SnakeAndLadderDemo** class demonstrates the usage of the game by creating an instance of the GameManager and starting two separate game sessions with different sets of players. ================================================ FILE: solutions/python/socialnetworkingservice/README.md ================================================ # Designing a Social Network Like Facebook ## Requirements #### User Registration and Authentication: - Users should be able to create an account with their personal information, such as name, email, and password. - Users should be able to log in and log out of their accounts securely. #### User Profiles: - Each user should have a profile with their information, such as profile picture, bio, and interests. - Users should be able to update their profile information. #### Friend Connections: - Users should be able to send friend requests to other users. - Users should be able to accept or decline friend requests. - Users should be able to view their list of friends. #### Posts and Newsfeed: - Users should be able to create posts with text, images, or videos. - Users should be able to view a newsfeed consisting of posts from their friends and their own posts. - The newsfeed should be sorted in reverse chronological order. #### Likes and Comments: - Users should be able to like and comment on posts. - Users should be able to view the list of likes and comments on a post. #### Privacy and Security: - Users should be able to control the visibility of their posts and profile information. - The system should enforce secure access control to ensure data privacy. #### Notifications: - Users should receive notifications for events such as friend requests, likes, comments, and mentions. - Notifications should be delivered in real-time. #### Scalability and Performance: - The system should be designed to handle a large number of concurrent users and high traffic load. - The system should be scalable and efficient in terms of resource utilization. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the social networking system, containing properties such as ID, name, email, password, profile picture, bio, list of friends, and list of posts. 2. The **Post** class represents a post created by a user, containing properties such as ID, user ID, content, image URLs, video URLs, timestamp, likes, and comments. 3. The **Comment** class represents a comment made by a user on a post, containing properties such as ID, user ID, post ID, content, and timestamp. 4. The **Notification** class represents a notification generated for a user, containing properties such as ID, user ID, notification type, content, and timestamp. 5. The **NotificationType** enum defines the different types of notifications, such as friend request, friend request accepted, like, comment, and mention. 6. The **SocialNetworkingService** class is the main class that manages the social networking system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SocialNetworkingService class provides methods for user registration, login, profile updates, friend requests, post creation, newsfeed generation, likes, comments, and notifications. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SocialNetworkingDemo** class demonstrates the usage of the social networking system by registering users, logging in, sending friend requests, creating posts, liking posts, commenting on posts, and retrieving newsfeed and notifications. ================================================ FILE: solutions/python/splitwise/README.md ================================================ # Designing Splitwise ## Requirements 1. The system should allow users to create accounts and manage their profile information. 2. Users should be able to create groups and add other users to the groups. 3. Users should be able to add expenses within a group, specifying the amount, description, and participants. 4. The system should automatically split the expenses among the participants based on their share. 5. Users should be able to view their individual balances with other users and settle up the balances. 6. The system should support different split methods, such as equal split, percentage split, and exact amounts. 7. Users should be able to view their transaction history and group expenses. 8. The system should handle concurrent transactions and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the Splitwise system, with properties such as ID, name, email, and a map to store balances with other users. 2. The **Group** class represents a group in Splitwise, containing a list of member users and a list of expenses. 3. The **Expense** class represents an expense within a group, with properties such as ID, amount, description, the user who paid, and a list of splits. 4. The **Split** class is an abstract class representing the split of an expense. It is extended by EqualSplit, PercentSplit, and ExactSplit classes to handle different split methods. 5. The **Transaction** class represents a transaction between two users, with properties such as ID, sender, receiver, and amount. 6. The **SplitwiseService** class is the main class that manages the Splitwise system. It follows the Singleton pattern to ensure only one instance of the service exists. 7. The SplitwiseService class provides methods for adding users, groups, and expenses, splitting expenses, updating balances, settling balances, and creating transactions. 8. Multi-threading is achieved using concurrent data structures such as ConcurrentHashMap and CopyOnWriteArrayList to handle concurrent access to shared resources. 9. The **SplitwiseDemo** class demonstrates the usage of the Splitwise system by creating users, a group, adding an expense, settling balances, and printing user balances. ================================================ FILE: solutions/python/stackoverflow/README.md ================================================ # Designing Stack Overflow ## Requirements 1. Users can post questions, answer questions, and comment on questions and answers. 2. Users can vote on questions and answers. 3. Questions should have tags associated with them. 4. Users can search for questions based on keywords, tags, or user profiles. 5. The system should assign reputation score to users based on their activity and the quality of their contributions. 6. The system should handle concurrent access and ensure data consistency. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user of the Stack Overflow system, with properties such as id, username, email, and reputation. 2. The **Question** class represents a question posted by a user, with properties such as id, title, content, author, answers, comments, tags, votes and creation date. 3. The **Answer** class represents an answer to a question, with properties such as id, content, author, associated question, comments, votes and creation date. 4. The **Comment** class represents a comment on a question or an answer, with properties such as id, content, author, and creation date. 5. The **Tag** class represents a tag associated with a question, with properties such as id and name. 6. The **Vote** class represents vote associated with a question/answer. 7. The **StackOverflow** class is the main class that manages the Stack Overflow system. It provides methods for creating user, posting questions, answers, and comments, voting on questions and answers, searching for questions, and retrieving questions by tags and users. 8. The **StackOverflowDemo** class demonstrates the usage of the Stack Overflow system by creating users, posting questions and answers, voting, searching for questions, and retrieving questions by tags and users. ================================================ FILE: solutions/python/taskmanagementsystem/README.md ================================================ # Designing a Task Management System ## Requirements 1. The task management system should allow users to create, update, and delete tasks. 2. Each task should have a title, description, due date, priority, and status (e.g., pending, in progress, completed). 3. Users should be able to assign tasks to other users and set reminders for tasks. 4. The system should support searching and filtering tasks based on various criteria (e.g., priority, due date, assigned user). 5. Users should be able to mark tasks as completed and view their task history. 6. The system should handle concurrent access to tasks and ensure data consistency. 7. The system should be extensible to accommodate future enhancements and new features. ## Classes, Interfaces and Enumerations 1. The **User** class represents a user in the task management system, with properties such as id, name, and email. 2. The **TaskStatus** enum defines the possible states of a task, such as pending, in progress, and completed. 3. The **Task** class represents a task in the system, with properties like id, title, description, due date, priority, status, and assigned user. 4. The **TaskManager** class is the core of the task management system and follows the Singleton pattern to ensure a single instance of the task manager. 5. The TaskManager class uses concurrent data structures (ConcurrentHashMap and CopyOnWriteArrayList) to handle concurrent access to tasks and ensure thread safety. 6. The TaskManager class provides methods for creating, updating, deleting, searching, and filtering tasks, as well as marking tasks as completed and retrieving task history for a user. 7. The **TaskManagementSystem** class serves as the entry point of the application and demonstrates the usage of the task management system. ================================================ FILE: solutions/python/tictactoe/README.md ================================================ # Designing a Tic Tac Toe Game ## Requirements 1. The Tic-Tac-Toe game should be played on a 3x3 grid. 2. Two players take turns marking their symbols (X or O) on the grid. 3. The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins the game. 4. If all the cells on the grid are filled and no player has won, the game ends in a draw. 5. The game should have a user interface to display the grid and allow players to make their moves. 6. The game should handle player turns and validate moves to ensure they are legal. 7. The game should detect and announce the winner or a draw at the end of the game. ## Classes, Interfaces and Enumerations 1. The **Player** class represents a player in the game, with a name and a symbol (X or O). 2. The **Board** class represents the game board, which is a 3x3 grid. It provides methods to make moves, check for a winner, and check if the board is full. 3. The **Game** class manages the game flow and player interactions. It handles player turns, validates moves, and determines the winner or a draw. 4. The **TicTacToe** class is the entry point of the application and creates instances of the players and the game. ================================================ FILE: solutions/python/trafficsignalsystem/README.md ================================================ # Designing a Traffic Signal Control System ## Requirements 1. The traffic signal system should control the flow of traffic at an intersection with multiple roads. 2. The system should support different types of signals, such as red, yellow, and green. 3. The duration of each signal should be configurable and adjustable based on traffic conditions. 4. The system should handle the transition between signals smoothly, ensuring safe and efficient traffic flow. 5. The system should be able to detect and handle emergency situations, such as an ambulance or fire truck approaching the intersection. 6. The system should be scalable and extensible to support additional features and functionality. ## Classes, Interfaces and Enumerations 1. The **Signal** enum represents the different states of a traffic light: red, yellow, and green. 2. The **Road** class represents a road in the traffic signal system, with properties such as ID, name, and an associated traffic light. 3. The **TrafficLight** class represents a traffic light, with properties such as ID, current signal, and durations for each signal state. It provides methods to change the signal and notify observers (e.g., roads) about signal changes. 4. The **TrafficController** class serves as the central controller for the traffic signal system. It follows the Singleton pattern to ensure a single instance of the controller. It manages the roads and their associated traffic lights, starts the traffic control process, and handles emergency situations. 5. The **TrafficSignalSystemDemo** class is the main entry point of the application. It demonstrates the usage of the traffic signal system by creating roads, traffic lights, assigning traffic lights to roads, and starting the traffic control process. ================================================ FILE: solutions/python/vendingmachine/README.md ================================================ # Designing a Vending Machine ## Requirements 1. The vending machine should support multiple products with different prices and quantities. 1. The machine should accept coins and notes of different denominations. 1. The machine should dispense the selected product and return change if necessary. 1. The machine should keep track of the available products and their quantities. 1. The machine should handle multiple transactions concurrently and ensure data consistency. 1. The machine should provide an interface for restocking products and collecting money. 1. The machine should handle exceptional scenarios, such as insufficient funds or out-of-stock products. ## Classes, Interfaces and Enumerations 1. The **Product** class represents a product in the vending machine, with properties such as name and price. 2. The **Coin** and **Note** enums represent the different denominations of coins and notes accepted by the vending machine. 3. The **Inventory** class manages the available products and their quantities in the vending machine. It uses a concurrent hash map to ensure thread safety. 4. The **VendingMachineState** interface defines the behavior of the vending machine in different states, such as idle, ready, and dispense. 5. The **IdleState**, **ReadyState**, and **DispenseState** classes implement the VendingMachineState interface and define the specific behaviors for each state. 6. The **VendingMachine** class is the main class that represents the vending machine. It follows the Singleton pattern to ensure only one instance of the vending machine exists. 7. The VendingMachine class maintains the current state, selected product, total payment, and provides methods for state transitions and payment handling. 8. The **VendingMachineDemo** class demonstrates the usage of the vending machine by adding products to the inventory, selecting products, inserting coins and notes, dispensing products, and returning change. ================================================ FILE: solutions/python/votingsystem/README.md ================================================ ### Airline Management System This is a simple airline management system that allows you to manage flights, passengers, and bookings. ================================================ FILE: solutions/typescript/.gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional stylelint cache .stylelintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variable files .env .env.development.local .env.test.local .env.production.local .env.local # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache # Next.js build output .next out # Nuxt.js build / generate output .nuxt dist # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # vuepress v2.x temp and cache directory .temp .cache # Docusaurus cache and generated files .docusaurus # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port # Stores VSCode versions used for testing VSCode extensions .vscode-test # yarn v2 .yarn/cache .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz .pnp.* ================================================ FILE: solutions/typescript/README.md ================================================ ## How to use ```bash npm i npx tsx src/lldrunner.ts ``` ================================================ FILE: solutions/typescript/package.json ================================================ { "name": "nodejs-typescript", "version": "1.0.0", "description": "", "main": "src/LLDRunner.ts", "scripts": { "dev": "tsx src/LLDRunner.ts", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "node-fetch": "^3.3.1", "uuid": "^11.1.0" }, "devDependencies": { "@types/node": "^20.10.0", "tsx": "^4.7.1" } } ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/CoffeeRecipe.ts ================================================ class CoffeeRecipe { private name: string; private price: number; private recipe: Map; constructor(name: string, price: number, recipe: Map) { this.name = name; this.price = price; this.recipe = recipe; } public getName(): string { return this.name; } public getPrice(): number { return this.price; } public getRecipe() { return this.recipe; } } export default CoffeeRecipe; ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/CoffeeVendingMachine.ts ================================================ import CoffeeRecipe from "./CoffeeRecipe"; import Dispenser from "./Dispenser"; import IngredientStore from "./IngredientStore"; import Payment from "./Payment"; import PaymentProcessor from "./PaymentProcessor"; class CoffeeVendingMachine { private static instance: CoffeeVendingMachine | null; private recipes: Map; private ingredientStore: IngredientStore; private dispenser: Dispenser; private paymentProcessor: PaymentProcessor; private constructor() { this.ingredientStore = new IngredientStore(); this.dispenser = new Dispenser(); this.paymentProcessor = new PaymentProcessor(); this.recipes = new Map(); this.addDefaultRecipes(); } private addDefaultRecipes(): void { this.recipes.set( "Latte", new CoffeeRecipe( "Latte", 3.0, new Map([ ["Water", 50], ["Coffee", 20], ["Milk", 30], ]), ), ); this.recipes.set( "Espresso", new CoffeeRecipe( "Espresso", 3.5, new Map([ ["Water", 50], ["Coffee", 20], ]), ), ); this.recipes.set( "Cappuccino", new CoffeeRecipe( "Cappuccino", 3.5, new Map([ ["Water", 50], ["Coffee", 20], ["Milk", 40], ]), ), ); } public static getInstance(): CoffeeVendingMachine { if (!CoffeeVendingMachine.instance) { CoffeeVendingMachine.instance = new CoffeeVendingMachine(); } return CoffeeVendingMachine.instance; } public displayMenu(): void { console.log("Coffee Menu:"); for (const recipe of this.recipes.keys()) { console.log(recipe + " - $" + this.recipes.get(recipe)?.getPrice()); } } public selectCoffee(coffeeName: string): CoffeeRecipe { const recipe = this.recipes.get(coffeeName); if (!recipe) throw new Error(`Invalid coffee recipe: ${coffeeName}`); console.log('Selected Coffee : ',coffeeName) return recipe; } public dispenseCoffee(recipe: CoffeeRecipe, payment: Payment): void { if (payment.getAmount() < recipe.getPrice()) { console.error( `Insufficient payment for ${recipe.getName()}. Required: ${recipe.getPrice()}`, ); return; } if (!this.ingredientStore.hasEnoughIngredient(recipe.getRecipe())) { console.error(`Insufficient ingredients to make ${recipe.getName()}`); return; } this.ingredientStore.consume(recipe.getRecipe()); this.dispenser.prepareDrink(recipe); const change = this.paymentProcessor.process( recipe.getPrice(), payment.getAmount(), ); if (change > 0) { console.log(`Please collect your change: $${change}`); } } public refillIngredient(ingredient: string, quantity: number): void { this.ingredientStore.refill(ingredient, quantity); } public showIngredients(): void { console.log("Ingredient Levels:"); const ingredients = this.ingredientStore.getAllIngredients(); for (const [name, quantity] of Object.entries(ingredients)) { console.log(`${name}: ${quantity}`); } } } export default CoffeeVendingMachine; ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/CoffeeVendingMachineDemo.ts ================================================ import CoffeeVendingMachine from "./CoffeeVendingMachine"; import Payment from "./Payment"; export default class CoffeeVendingMachineDemo { static run() { const coffeeVendingMachine = CoffeeVendingMachine.getInstance(); coffeeVendingMachine.refillIngredient("Water", 120); coffeeVendingMachine.refillIngredient("Milk", 70); coffeeVendingMachine.refillIngredient("Coffee", 150); coffeeVendingMachine.displayMenu(); const espresso = coffeeVendingMachine.selectCoffee("Espresso"); coffeeVendingMachine.dispenseCoffee(espresso, new Payment(3.0)); const cappuccino = coffeeVendingMachine.selectCoffee("Cappuccino"); coffeeVendingMachine.dispenseCoffee(cappuccino, new Payment(3.5)); const latte = coffeeVendingMachine.selectCoffee("Latte"); coffeeVendingMachine.dispenseCoffee(latte, new Payment(4.0)); } } ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/Dispenser.ts ================================================ import CoffeeRecipe from "./CoffeeRecipe"; class Dispenser { public prepareDrink(recipe: CoffeeRecipe): void { console.log(`Dispensing: ${recipe.getName()}`); } } export default Dispenser; ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/IngredientStore.ts ================================================ class IngredientStore { private inventory: Map; constructor() { this.inventory = new Map(); } public refill(ingredient: string, quantity: number): void { this.inventory.set( ingredient, (this.inventory.get(ingredient) || 0) + quantity, ); } public hasEnoughIngredient(required: Map): boolean { for (const [ingredient, quantity] of required) { if ((this.inventory.get(ingredient) || 0) < quantity) return false; } return true; } public consume(required: Map): void { for (const [ingredient, quantity] of required) { const currentStock = this.inventory.get(ingredient) || 0; if (currentStock < quantity) { throw new Error(`Not enough ${ingredient} to consume`); } this.inventory.set(ingredient, currentStock - quantity); } } public getLevel(ingredient: string): number { return this.inventory.get(ingredient) || 0; } public getAllIngredients(): Map { return { ...this.inventory }; } } export default IngredientStore; ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/Payment.ts ================================================ export default class Payment { private amount: number; constructor(amount: number) { this.amount = amount; } public getAmount(): number { return this.amount; } } ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/PaymentProcessor.ts ================================================ class PaymentProcessor { public process(price: number, paid: number): number { console.log("Processing Payment..."); return paid - price; } } export default PaymentProcessor; ================================================ FILE: solutions/typescript/src/CoffeeVendingMachine/README.md ================================================ # Coffee Vending Machine (LLD) ## Problem Statement Design and implement a Coffee Vending Machine system that can serve different types of coffee, manage ingredient inventory, process payments, and handle user interactions such as selecting coffee and refilling ingredients. --- ## Requirements - **Multiple Coffee Types:** The machine should support multiple coffee recipes (e.g., Espresso, Latte, Cappuccino). - **Ingredient Management:** The machine should track and manage ingredient levels, and prevent dispensing if ingredients are insufficient. - **Payment Processing:** The machine should process payments before dispensing coffee. - **Refill Ingredients:** The machine should allow refilling of ingredients. - **Extensibility:** Easy to add new coffee types or payment methods. --- ## Core Entities - **CoffeeVendingMachine:** Main class that manages the overall operation, user interaction, and coordinates other components. - **CoffeeRecipe:** Represents a coffee recipe, including required ingredients and their quantities. - **IngredientStore:** Manages the inventory of ingredients, supports checking and refilling. - **Dispenser:** Handles the dispensing of coffee after successful payment and ingredient check. - **PaymentProcessor:** Handles payment logic and validation. - **Payment:** Represents a payment transaction. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/coffeevendingmachine-class-diagram.png) ### 1. CoffeeVendingMachine - **Fields:** ingredientStore, paymentProcessor, Map recipes, Dispenser - **Methods:** selectCoffee(String), makeCoffee(String, Payment), refillIngredient(String, int), addRecipe(CoffeeRecipe), etc. ### 2. CoffeeRecipe - **Fields:** name, Map ingredients - **Methods:** getName(), getIngredients() ### 3. IngredientStore - **Fields:** Map ingredientLevels - **Methods:** hasIngredients(Map), useIngredients(Map), refill(String, int), getLevel(String) ### 4. Dispenser - **Methods:** dispense(String) ### 5. PaymentProcessor - **Methods:** processPayment(Payment) ### 6. Payment - **Fields:** amount, paymentType, etc. --- ## Design Patterns Used - **Strategy Pattern:** (Conceptually) for supporting different payment methods or coffee recipes. - **Separation of Concerns:** Each class has a single responsibility (inventory, payment, dispensing, etc.). --- ## Example Usage ```ts const coffeeVendingMachine = CoffeeVendingMachine.getInstance(); coffeeVendingMachine.refillIngredient("Milk", 70); coffeeVendingMachine.refillIngredient("Coffee", 150); coffeeVendingMachine.displayMenu(); const espresso = coffeeVendingMachine.selectCoffee("Espresso"); coffeeVendingMachine.dispenseCoffee(espresso, new Payment(3.0)); ``` --- ## Demo See `CoffeeVendingMachineDemo.ts` for a sample usage and simulation of the coffee vending machine. --- ## Extending the Framework - **Add new coffee types:** Create new `CoffeeRecipe` instances and add them to the machine. - **Add new payment methods:** Extend `PaymentProcessor` to support new payment types. - **Add new ingredients:** Update `IngredientStore` and recipes as needed. --- ================================================ FILE: solutions/typescript/src/LoggingFramework/Appender/ConsoleLogAppender.ts ================================================ import LogFormatter from "../LogFormatter/LogFormatter"; import LogMessage from "../LogMessage"; import LogAppender from "./LogAppender"; export default class ConsoleLogAppender implements LogAppender { private formatter: LogFormatter; constructor(formatter: LogFormatter) { this.formatter = formatter; } append(logMessage: LogMessage) { console.log(this.formatter.format(logMessage)); } } ================================================ FILE: solutions/typescript/src/LoggingFramework/Appender/FileLogAppender.ts ================================================ import * as fs from "fs"; import * as path from "path"; import LogAppender from "./LogAppender"; import LogMessage from "../LogMessage"; import LogFormatter from "../LogFormatter/LogFormatter"; export default class FileLogAppender implements LogAppender { private writer!: fs.WriteStream; private formatter: LogFormatter; constructor(filePath: string, formatter: LogFormatter) { this.formatter = formatter; const dir = path.dirname(filePath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } try { this.writer = fs.createWriteStream(filePath, { flags: "a" }); } catch (e) { console.error("Failed to create writer for file logs, exception:", e); } } public append(logMessage: LogMessage): void { try { const formattedMessage = this.formatter.format(logMessage); this.writer.write(formattedMessage + "\n"); } catch (e) { console.error("Failed to write logs to file, exception:", e); } } } ================================================ FILE: solutions/typescript/src/LoggingFramework/Appender/LogAppender.ts ================================================ import LogMessage from "../LogMessage"; export default interface LogAppender { append(logMessage: LogMessage): void; } ================================================ FILE: solutions/typescript/src/LoggingFramework/LogFormatter/LogFormatter.ts ================================================ import LogMessage from "../LogMessage"; export default interface LogFormatter { format(message: LogMessage): string; } ================================================ FILE: solutions/typescript/src/LoggingFramework/LogFormatter/SimpleLogFormatter.ts ================================================ import LogMessage from "../LogMessage"; import LogFormatter from "./LogFormatter"; export default class SimpleLogFormatter implements LogFormatter { format(message: LogMessage): string { return `[${message.getTimeStamp()}] - [${message.getLogLevel()}] - [${message.getMessage()}]`; } } ================================================ FILE: solutions/typescript/src/LoggingFramework/LogLevel.ts ================================================ export enum LogLevelEnum { DEBUG, // 0 INFO, // 1 WARN, // 2 ERROR, // 3 FATAL, // 4 } export function isAsSevereAs( level1: LogLevelEnum, level2: LogLevelEnum, ): boolean { return level1 >= level2; } ================================================ FILE: solutions/typescript/src/LoggingFramework/LogManager.ts ================================================ import ConsoleLogAppender from "./Appender/ConsoleLogAppender"; import FileLogAppender from "./Appender/FileLogAppender"; import LogAppender from "./Appender/LogAppender"; import SimpleLogFormatter from "./LogFormatter/SimpleLogFormatter"; import Logger from "./Logger"; import { LogLevelEnum } from "./LogLevel"; export default class LogManager { private static logger: Logger; static getLogger() { if (this.logger == null) { this.logger = new LogManager.LoggerBuilder() .setLevel(LogLevelEnum.DEBUG) .addAppender(new ConsoleLogAppender(new SimpleLogFormatter())) .addAppender( new FileLogAppender("log.txt", new SimpleLogFormatter()), ) .build(); } return this.logger; } static LoggerBuilder = class { private level: LogLevelEnum = LogLevelEnum.INFO; private appenders: LogAppender[] = []; setLevel(level: LogLevelEnum): this { this.level = level; return this; } addAppender(appender: LogAppender): this { this.appenders.push(appender); return this; } build(): Logger { return new Logger(this.level, this.appenders); } }; } ================================================ FILE: solutions/typescript/src/LoggingFramework/LogMessage.ts ================================================ import { LogLevelEnum } from "./LogLevel"; export default class LogMessage { private logLevel: LogLevelEnum; private message: string; private timestamp: number; constructor(logLevel: LogLevelEnum, message: string) { this.logLevel = logLevel; this.message = message; this.timestamp = Date.now(); } getMessage() { return this.message; } getLogLevel() { return this.logLevel; } getTimeStamp() { return this.timestamp; } toString() { return "[" + this.logLevel + "] " + this.timestamp + " - " + this.message; } } ================================================ FILE: solutions/typescript/src/LoggingFramework/Logger.ts ================================================ import LogAppender from "./Appender/LogAppender"; import { isAsSevereAs, LogLevelEnum } from "./LogLevel"; import LogMessage from "./LogMessage"; export default class Logger { private minLevel: LogLevelEnum; private appenders: LogAppender[]; public constructor(minLevel: LogLevelEnum, appenders: LogAppender[]) { this.minLevel = minLevel; this.appenders = appenders; } log(level: LogLevelEnum, msg: string) { if (!isAsSevereAs( level,this.minLevel)) return; const message = new LogMessage(level, msg); this.appenders.forEach((a) => a.append(message)); } setMinLevel(minLevel: LogLevelEnum) { this.minLevel = minLevel; } debug(message: string) { this.log(LogLevelEnum.DEBUG, message); } info(message: string) { this.log(LogLevelEnum.INFO, message); } warn(message: string) { this.log(LogLevelEnum.WARN, message); } error(message: string) { this.log(LogLevelEnum.ERROR, message); } fatal(message: string) { this.log(LogLevelEnum.FATAL, message); } } ================================================ FILE: solutions/typescript/src/LoggingFramework/LoggingFrameworkDemo.ts ================================================ import { LogLevelEnum } from "./LogLevel"; import LogManager from "./LogManager"; export default class LogginFrameworkDemo { static run() { const logger = LogManager.getLogger(); // Logging with default configuration // Should log debug and above log levels logger.info("This is an information message"); logger.warn("This is a warning message"); logger.error("This is an error message"); // Changing log level logger.setMinLevel(LogLevelEnum.WARN); // Should only log warn and above logger.debug("This is a debug message"); logger.info("This is an information message"); logger.warn("This is a warning message"); } } ================================================ FILE: solutions/typescript/src/LoggingFramework/README.md ================================================ # Logging Framework (LLD) ## Problem Statement Design and implement a flexible and extensible logging framework that can be used by applications to log messages at different levels (INFO, DEBUG, ERROR, etc.), support multiple output destinations (console, file, etc.), and allow for custom formatting of log messages. --- ## Requirements - **Log Levels:** Support for multiple log levels (INFO, DEBUG, ERROR, etc.). - **Multiple Appenders:** Ability to log to different destinations (console, file, etc.). - **Custom Formatting:** Support for custom log message formatting. - **Configuration:** Ability to configure loggers and appenders. - **Thread Safety:** Should be thread-safe for concurrent logging. - **Extensibility:** Easy to add new log levels, appenders, or formatters. --- ## Core Entities - **Logger:** Main class used by clients to log messages. - **LogLevel:** Enum representing different log levels. - **LogMessage:** Encapsulates the details of a log event. - **LogFormatter:** Interface for formatting log messages. - **DefaultFormatter:** Default implementation of `LogFormatter`. - **LoggerConfig:** Holds configuration for the logger (appenders, formatters, etc.). - **LogAppender (in `logappender/`):** Interface and implementations for output destinations (e.g., ConsoleAppender, FileAppender). --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/loggingframework-class-diagram.png) ### 1. Logger - **Methods:** - `log(LogLevel level, String message)` - `info(String message)` - `debug(String message)` - `error(String message)` - `setConfig(LoggerConfig config)` ### 2. LogLevel - Enum for log levels (INFO, DEBUG, ERROR, etc.) ### 3. LogMessage - Fields: `level`, `message`, `timestamp`, etc. ### 4. LogFormatter (Interface) - `String format(LogMessage message)` ### 5. DefaultFormatter - Implements `LogFormatter` with a default format. ### 6. LoggerConfig - Holds configuration for loggers (appenders, formatters, log level). ### 7. LogAppender (in `logappender/`) - Interface for appenders. - Implementations: `ConsoleAppender`, `FileAppender`, etc. --- ## Design Patterns Used - **Strategy Pattern:** For interchangeable log formatters and appenders. - **Singleton Pattern:** For global logger instance. - **Factory Pattern:** (Optional) For creating appenders/formatters based on config. - **Observer Pattern:** (Conceptually, for notifying multiple appenders.) --- ## Example Usage ```ts const logger = LogManager.getLogger(); logger.info("This is an information message"); logger.setMinLevel(LogLevelEnum.WARN); logger.warn("This is a warning message"); ``` --- ## Demo See `LoggingFrameworkDemo.ts` for a sample usage of the logging framework. --- ## Extending the Framework - **Add a new log level:** Update `LogLevel.java`. - **Add a new appender:** Implement the `LogAppender` interface in `logappender/`. - **Add a new formatter:** Implement the `LogFormatter` interface. --- ================================================ FILE: solutions/typescript/src/ParkingLot/Floor.ts ================================================ import ParkingSpot from "./Spot"; import { carType } from "./types"; import AbstractVehicle from "./Vehicle"; type carWiseSpot = Record class ParkingFloor { floor: string; spots: ParkingSpot[]; constructor(floor: string) { this.floor = floor this.spots = [] } addSpot(spot: ParkingSpot) { this.spots.push(spot) } reportAvailability(): carWiseSpot { const carWiseSpots: carWiseSpot = { "Car": [], "Truck": [], "Bike": [] } for (let spot of this.spots) { if (spot.isAvailable) { carWiseSpots[spot.getSpotType].push(spot) } } return carWiseSpots } findAvailableSpot(vehicle: AbstractVehicle): ParkingSpot | null { for (let spot of this.spots) { if (spot.canFit(vehicle) && spot.isAvailable) { return spot } } return null } } export default ParkingFloor ================================================ FILE: solutions/typescript/src/ParkingLot/Main.ts ================================================ import ParkingLot from "./ParkingLot" import ParkingFloor from "./Floor" import ParkingSpot from "./Spot" import { Car } from "./Vehicle" const parkYourCar = ParkingLot.getInstance("ParkYourCar") console.log(parkYourCar.name) const car1 = new Car("car-1") const car2 = new Car("car-2") const car3 = new Car("car-3") const car4 = new Car("car-4") const a1 = new ParkingSpot('a-1', "Car") // const a2 = new ParkingSpot('a-2', "Truck") const a3 = new ParkingSpot('a-3', "Bike") const a4 = new ParkingSpot('a-4', "Car") // const a5 = new ParkingSpot('a-5', "Car") const f1 = new ParkingFloor("1") f1.addSpot(a1) // f1.addSpot(a2) f1.addSpot(a3) f1.addSpot(a4) // f1.addSpot(a5) const b1 = new ParkingSpot('b-1', "Car") const b2 = new ParkingSpot('b-2', "Truck") // const b3 = new ParkingSpot('b-3', "Bike") const b4 = new ParkingSpot('b-4', "Car") // const b5 = new ParkingSpot('b-5', "Car") const f2 = new ParkingFloor("2") f2.addSpot(b1) f2.addSpot(b2) // f2.addSpot(b3) f2.addSpot(b4) // f2.addSpot(b5) parkYourCar.addFloor(f1) parkYourCar.addFloor(f2) parkYourCar.spotAvailability() parkYourCar.parkCar(car1) parkYourCar.parkCar(car2) parkYourCar.spotAvailability() ================================================ FILE: solutions/typescript/src/ParkingLot/ParkingLot.ts ================================================ import ParkingFloor from "./Floor"; import ParkingSpot from "./Spot"; import AbstractVehicle from "./Vehicle"; class ParkingLot { private static instance: ParkingLot; private floors: ParkingFloor[] name : string; protected carSpotMap: Record constructor(name: string){ this.name = name this.floors = [] this.carSpotMap = {} } static getInstance(name: string = "Default"): ParkingLot{ if(!ParkingLot.instance){ this.instance = new ParkingLot(name) } return ParkingLot.instance } parkCar(vehicle: AbstractVehicle): void{ for(let floor of this.floors){ const availableSpot = floor.findAvailableSpot(vehicle) if(availableSpot){ availableSpot.parkCar(vehicle) console.log(`${vehicle.getNumber()} parked on ${availableSpot.spotName}`) return } } } unparkCar(vehicle: AbstractVehicle){ const spot = this.carSpotMap[vehicle.getNumber()] if(!spot){ throw new Error(`${vehicle.getNumber()} is not Parked.`) } spot.unparkCar() delete this.carSpotMap[vehicle.getNumber()]; } spotAvailability(){ for(let floor of this.floors){ const availability = floor.reportAvailability() console.log(`${floor.floor} : `, availability) } } addFloor(floor : ParkingFloor){ this.floors.push(floor) } } export default ParkingLot ================================================ FILE: solutions/typescript/src/ParkingLot/Spot.ts ================================================ import { carType } from "./types"; import AbstractVehicle from "./Vehicle"; class ParkingSpot { spotName: string; protected type: carType; protected parkedCar: AbstractVehicle | null; constructor(spotName: string, type: carType) { this.spotName = spotName; this.type = type; } get isAvailable(): boolean { return !this.parkedCar; } canFit(car: AbstractVehicle): boolean { return car.getType() === this.type; } parkCar(car: AbstractVehicle): void { if (!this.isAvailable) { throw new Error("Spot already occupied."); } if (!this.canFit(car)) { throw new Error(`${car.getNumber()} can't fit in this spot.`); } this.parkedCar = car; console.log(`Parked car${car.getNumber()}.`); } unparkCar(): void { this.parkedCar = null; } getVehicle(): AbstractVehicle | null { return this.parkedCar; } get getSpotType(): carType { return this.type; } } export default ParkingSpot; ================================================ FILE: solutions/typescript/src/ParkingLot/Vehicle.ts ================================================ import { carType } from "./types"; interface Vehicle { getNumber(): string; getType(): carType; } abstract class AbstractVehicle implements Vehicle { protected number: string; protected type: carType; constructor(number: string, type: carType) { this.number = number; this.type = type; } getNumber(): string { return this.number; } getType(): carType { return this.type; } } class Car extends AbstractVehicle { constructor(number: string) { super(number, "Car"); } } class Bike extends AbstractVehicle { constructor(number: string) { super(number, "Bike"); } } class Truck extends AbstractVehicle { constructor(number: string) { super(number, "Truck"); } } export default AbstractVehicle export {Car, Bike, Truck} ================================================ FILE: solutions/typescript/src/ParkingLot/readme.md ================================================ # Designing a Parking Lot System ## Requirements 1. The parking lot consists of multiple levels, and each level has a configurable number of parking spots. 2. The system must support various types of vehicles: Car, Motorcycle, and Truck. 3. Each parking spot supports a specific vehicle type. 4. The system should be able to: 5. Assign a parking spot to an incoming vehicle. 6. Free a spot when a vehicle exits. 7. Track and report spot availability in real time. 8. The system should support multiple entry and exit points with concurrent access handling (simulate multi-threading behavior where needed). 9. The design must showcase solid TypeScript OOP principles: classes, interfaces, abstract classes, and enums. ## Design Patterns Used: 1. Use TypeScript with classes, interfaces, and enums. * `Singleton`: Ensure only one instance of the ParkingLot exists. * `Factory(optional)`: For creating vehicles dynamically. * `Observer(optional)`: To notify users when a spot becomes available. 2. Ensure thread-safety where required using appropriate concurrency-safe constructs (e.g., Mutex simulation, Promise control). 3. Build a simple `Main.ts` file or script to demonstrate usage. ================================================ FILE: solutions/typescript/src/ParkingLot/types.ts ================================================ export type carType = "Car" | "Truck" | "Bike"; ================================================ FILE: solutions/typescript/src/StackOverflow/Answer.ts ================================================ import { v4 as uuidv4 } from "uuid"; import User from "./User"; import Question from "./Question"; import Comment from "./Comment"; import Vote from "./Vote"; import Votable from "./Votable"; import Commentable from "./Commentable"; import { VoteTypeEnum } from "./VoteTypeEnum"; import { ReputationTypeEnum } from "./ReputationType"; export default class Answer implements Votable, Commentable { private id: string; private content: string; private author: User; private question: Question; private isAccepted: boolean; private creationDate: Date; private comments: Comment[]; private votes: Vote[]; constructor(author: User, question: Question, content: string) { this.id = uuidv4(); this.author = author; this.question = question; this.content = content; this.creationDate = new Date(); this.votes = []; this.comments = []; this.isAccepted = false; } vote(voter: User, type: VoteTypeEnum) { this.votes = this.votes.filter( (v) => v.getVoter().getUserId() != voter.getUserId(), ); this.votes.push(new Vote(voter, type)); this.author.updateReputation( type == VoteTypeEnum.UPVOTE ? ReputationTypeEnum.ANSWER_UPVOTE : ReputationTypeEnum.ANSWER_DOWNVOTE, ); } getVoteCount() { return this.votes.reduce((sum, vote) => sum + vote.getVoteType(), 0); } addComment(comment: Comment) { this.comments.push(comment); } getComments() { return this.comments; } getQuestion() { return this.question; } markAsAccepted() { if (this.isAccepted) { throw new Error("This answer is already accepted"); } this.isAccepted = true; this.author.updateReputation(ReputationTypeEnum.ANSWER_ACCEPTED); } getId() { return this.id; } getAuthor() { return this.author; } getContent() { return this.content; } getIsAccepted() { return this.isAccepted; } } ================================================ FILE: solutions/typescript/src/StackOverflow/Comment.ts ================================================ import User from "./User"; import { v4 as uuidv4 } from "uuid"; export default class Comment { private id: string; private content: string; private author: User; private creationDate: Date; constructor(author: User, content: string) { this.id = uuidv4(); this.author = author; this.content = content; this.creationDate = new Date(); } getId() { return this.id; } getAuthor() { return this.author; } getContent() { return this.content; } } ================================================ FILE: solutions/typescript/src/StackOverflow/Commentable.ts ================================================ import Comment from "./Comment"; export default interface Commentable { addComment(comment: Comment): void; getComments(): Comment[]; } ================================================ FILE: solutions/typescript/src/StackOverflow/Question.ts ================================================ import Answer from "./Answer"; import User from "./User"; import Vote from "./Vote"; import { VoteTypeEnum } from "./VoteTypeEnum"; import Comment from "./Comment"; import Tag from "./Tag"; import { v4 as uuidv4 } from "uuid"; import { ReputationTypeEnum } from "./ReputationType"; export default class Question { private id: string; private title: string; private content: string; private author: User; private creationDate: Date; private answers: Answer[]; private comments: Comment[]; private tags: Tag[]; private votes: Vote[]; private acceptedAnswer: Answer | null; constructor(author: User, title: string, content: string, tags: Tag[]) { this.id = uuidv4(); this.author = author; this.title = title; this.content = content; this.creationDate = new Date(); this.answers = []; this.votes = []; this.comments = []; this.tags = tags; this.acceptedAnswer = null; } addAnswer(answer: Answer) { this.answers.push(answer); } acceptAnswer(answer: Answer) { this.acceptedAnswer = answer; } vote(voter: User, type: VoteTypeEnum) { this.votes = this.votes.filter( (v) => v.getVoter().getUserId() != voter.getUserId(), ); this.votes.push(new Vote(voter, type)); this.author.updateReputation( type == VoteTypeEnum.UPVOTE ? ReputationTypeEnum.QUESTION_UPVOTE : ReputationTypeEnum.QUESTION_DOWNVOTE, ); } getVoteCount() { return this.votes.reduce((sum, vote) => sum + vote.getVoteType(), 0); } addComment(comment: Comment) { this.comments.push(comment); } getComments() { return this.comments; } getId() { return this.id; } getAuthor() { return this.author; } getTitle() { return this.title; } getContent() { return this.content; } getTags() { return this.tags; } } ================================================ FILE: solutions/typescript/src/StackOverflow/README.md ================================================ # StackOverflow System (LLD) ## Problem Statement Design and implement a simplified StackOverflow-like Q&A platform. The system should allow users to post questions and answers, vote on them, comment, tag questions, and track user reputation. --- ## Requirements - **User Management:** Users can ask questions, answer, comment, and vote. - **Questions & Answers:** Users can post questions and answers. Each question can have multiple answers, and one accepted answer. - **Voting:** Users can upvote or downvote questions and answers. Reputation is updated accordingly. - **Comments:** Users can comment on both questions and answers. - **Tags:** Questions can be tagged for categorization. - **Reputation:** Users gain or lose reputation based on votes and accepted answers. - **Accepted Answer:** The question author can mark one answer as accepted. --- ## Core Entities - **User:** Represents a user, tracks reputation and user details. - **Question:** Represents a question, holds answers, comments, tags, votes, and accepted answer. - **Answer:** Represents an answer to a question, holds comments, votes, and accepted status. - **Comment:** Represents a comment on a question or answer. - **Tag:** Represents a tag for categorizing questions. - **Vote:** Represents a vote (upvote/downvote) by a user on a question or answer. - **VoteType:** Enum for UPVOTE and DOWNVOTE. - **Votable (interface):** For entities that can be voted on. - **Commentable (interface):** For entities that can be commented on. --- ## Class Design ## UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/stackoverflow-class-diagram.png) ### 1. User - **Fields:** id, name, reputation, etc. - **Methods:** updateReputation(int delta), getReputation(), etc. ### 2. Question - **Fields:** id, title, content, author, creationDate, answers, comments, tags, votes, acceptedAnswer - **Methods:** addAnswer(Answer), acceptAnswer(Answer), vote(User, VoteType), getVoteCount(), addComment(Comment), getComments(), etc. ### 3. Answer - **Fields:** id, content, author, question, isAccepted, creationDate, comments, votes - **Methods:** vote(User, VoteType), getVoteCount(), addComment(Comment), getComments(), markAsAccepted(), etc. ### 4. Comment - **Fields:** id, content, author, creationDate ### 5. Tag - **Fields:** name ### 6. Vote - **Fields:** voter, type (VoteType) - **Methods:** getVoter(), getType() ### 7. VoteType - Enum: UPVOTE, DOWNVOTE ### 8. Votable (interface) - **Methods:** vote(User, VoteType), getVoteCount() ### 9. Commentable (interface) - **Methods:** addComment(Comment), getComments() --- ## Design Patterns Used - **Strategy Pattern:** For voting and commenting behaviors via interfaces. - **Observer Pattern:** (Conceptually) for reputation updates on votes and accepted answers. --- ## Example Usage ```ts const stackOverflow = StackOverflow.getInstance(); const alice = stackOverflow.createUser("Alice", "alice@example.com"); const q = stackOverflow.postQuestion(alice, "What is JavaScript?", "Explain JavaScript basics.", ["javascript", "basics"]); const bob = stackOverflow.createUser("Bob", "bob@example.com"); const a = stackOverflow.postAnswer(bob.getUserId(), q.getId(), "JavaScript is a programming language."); stackOverflow.vote(bob.getUserId(), q, VoteTypeEnum.UPVOTE); stackOverflow.acceptAnswer(a.getId()); ``` --- ## Demo See `StackOverflowDemo.ts` for a sample usage of the StackOverflow system. --- ## Extending the Framework - **Add new features:** Such as badges, user profiles, or advanced search. - **Add new vote types:** Extend `VoteType` and update logic in `vote()` methods. - **Add moderation:** Implement admin/moderator roles for content management. --- ================================================ FILE: solutions/typescript/src/StackOverflow/ReputationType.ts ================================================ export enum ReputationTypeEnum { QUESTION_UPVOTE = 5, QUESTION_DOWNVOTE = -2, ANSWER_UPVOTE = 10, ANSWER_DOWNVOTE = -2, ANSWER_ACCEPTED = 15, } ================================================ FILE: solutions/typescript/src/StackOverflow/StackOverflow.ts ================================================ import Answer from "./Answer"; import Comment from "./Comment"; import Commentable from "./Commentable"; import Question from "./Question"; import Tag from "./Tag"; import User from "./User"; import Votable from "./Votable"; import { VoteTypeEnum } from "./VoteTypeEnum"; export default class StackOverflow { private static instance: StackOverflow; private users: Map; private questions: Map; private answers: Map; private tags: Map; private constructor() { this.users = new Map(); this.questions = new Map(); this.answers = new Map(); this.tags = new Map(); } static getInstance() { if (StackOverflow.instance == null) { StackOverflow.instance = new StackOverflow(); } return StackOverflow.instance; } createUser(username: string, email: string) { const user = new User(username, email); this.users.set(user.getUserId(), user); return user; } postQuestion( userId: string, title: string, content: string, questionTags: string[], ) { const author = this.getUser(userId); const tagList = []; for (const qTag of questionTags) { let tag = this.tags.get(qTag); // Check if tag already exists if (!tag) { tag = new Tag(qTag); // Create new Tag if not found } tagList.push(tag); this.tags.set(tag.getId(), tag); } const question = new Question(author, title, content, tagList); this.questions.set(question.getId(), question); return question; } postAnswer(userId: string, questionId: string, content: string) { const author = this.getUser(userId); const question = this.questions.get(questionId); if (!question) throw new Error("Question Does Not Exist"); const answer = new Answer(author, question, content); question.addAnswer(answer); this.answers.set(answer.getId(), answer); return answer; } getUser(userId: string) { const user = this.users.get(userId); if (!user) throw new Error("User Does Not Exist"); return user; } addComment(userId: string, commentable: Commentable, content: string) { const author = this.getUser(userId); const comment = new Comment(author, content); commentable.addComment(new Comment(author, content)); return comment; } vote(userId: string, votable: Votable, voteType: VoteTypeEnum) { const user = this.getUser(userId); votable.vote(user, voteType); } acceptAnswer(answerId: string) { const answer = this.answers.get(answerId); if (!answer) throw new Error("Answer Not Found"); const question = answer.getQuestion(); answer.markAsAccepted(); question.acceptAnswer(answer); } searchQuestions(query: string) { const lowerQuery = query.toLowerCase(); return [...this.questions.values()].filter( (q) => q.getTitle().toLowerCase().includes(lowerQuery) || q.getContent().toLowerCase().includes(lowerQuery) || q.getTags().some((t) => t.getName().toLowerCase() === lowerQuery), ); } getQuestionsByUser(userId: string) { return [...this.questions.values()].filter( (q) => q.getAuthor().getUserId() === userId, ); } } ================================================ FILE: solutions/typescript/src/StackOverflow/StackOverflowDemo.ts ================================================ import StackOverflow from "./StackOverflow"; import { VoteTypeEnum } from "./VoteTypeEnum"; export default class StackOverflowDemo { static run() { const stackOverflow = StackOverflow.getInstance(); // Create users const alice = stackOverflow.createUser("Alice", "alice@example.com"); const bob = stackOverflow.createUser("Bob", "bob@example.com"); const charlie = stackOverflow.createUser("Charlie", "charlie@example.com"); // Alice asks a question const javaQuestion = stackOverflow.postQuestion( alice.getUserId(), "Why does typeof null return 'object'?", "I tried `typeof null` and got 'object'. I expected 'null'. Is this a bug or feature?", ["javascript", "typeof", "null"], ); // Bob answers Alice's question const bobAnswer = stackOverflow.postAnswer( bob.getUserId(), javaQuestion.getId(), "`typeof null` returns 'object' due to a bug in JavaScript's early implementation. It’s now a legacy quirk, and changing it would break existing code.", ); // Charlie comments on the question stackOverflow.addComment( charlie.getUserId(), javaQuestion, "Welcome to JavaScript! Where 'null' is an object and 'undefined' means everything and nothing. 😅", ); // Alice comments on Bob's answer stackOverflow.addComment( alice.getUserId(), bobAnswer, "Wow, that's weird but helpful. Thanks Bob!", ); // Charlie votes on the question and answer stackOverflow.vote(charlie.getUserId(), javaQuestion, VoteTypeEnum.UPVOTE); stackOverflow.vote(charlie.getUserId(), bobAnswer, VoteTypeEnum.UPVOTE); // Alice accepts Bob's answer stackOverflow.acceptAnswer(bobAnswer.getId()); // Print out the current state console.log("Question: " + javaQuestion.getTitle()); console.log("Asked by: " + javaQuestion.getAuthor().getName()); console.log( "Tags: " + javaQuestion .getTags() .map((tag) => tag.getName()) .join(", "), ); console.log("Votes: " + javaQuestion.getVoteCount()); console.log("Comments: " + javaQuestion.getComments().length); console.log("\nAnswer by " + bobAnswer.getAuthor().getName() + ":"); console.log(bobAnswer.getContent()); console.log("Votes: " + bobAnswer.getVoteCount()); console.log("Accepted: " + bobAnswer.getIsAccepted()); console.log("Comments: " + bobAnswer.getComments().length); console.log("\nUser Reputations:"); console.log("Alice: " + alice.getReputation()); console.log("Bob: " + bob.getReputation()); console.log("Charlie: " + charlie.getReputation()); // Search questions by keyword console.log("\nSearch Results for 'javascript':"); const searchResults = stackOverflow.searchQuestions("javascript"); for (const q of searchResults) { console.log(q.getTitle()); } // Search questions by user console.log("\nAlice's Questions:"); const bobQuestions = stackOverflow.getQuestionsByUser(alice.getUserId()); for (const q of bobQuestions) { console.log(q.getTitle()); } } } ================================================ FILE: solutions/typescript/src/StackOverflow/Tag.ts ================================================ import { v4 as uuidv4 } from "uuid"; export default class Tag { private id: string; private name: string; constructor(name: string) { this.id = uuidv4(); this.name = name; } getId() { return this.id; } getName() { return this.name; } } ================================================ FILE: solutions/typescript/src/StackOverflow/User.ts ================================================ import { v4 as uuidv4 } from "uuid"; export default class User { private userId: string; private name: string; private email: string; private reputation: number; constructor(name: string, email: string) { this.userId = uuidv4(); this.name = name; this.email = email; this.reputation = 0; } updateReputation(value: number) { this.reputation += value; if (this.reputation < 0) { this.reputation = 0; } } getUserId() { return this.userId; } getName() { return this.name; } getReputation() { return this.reputation; } getEmail() { return this.email; } } ================================================ FILE: solutions/typescript/src/StackOverflow/Votable.ts ================================================ import User from "./User"; import { VoteTypeEnum } from "./VoteTypeEnum"; export default interface Votable { vote(voter: User, type: VoteTypeEnum): void; getVoteCount(): number; } ================================================ FILE: solutions/typescript/src/StackOverflow/Vote.ts ================================================ import User from "./User"; import { VoteTypeEnum } from "./VoteTypeEnum"; export default class Vote { private voter: User; private type: VoteTypeEnum; constructor(voter: User, type: VoteTypeEnum) { this.voter = voter; this.type = type; } getVoter() { return this.voter; } getVoteType() { return this.type; } } ================================================ FILE: solutions/typescript/src/StackOverflow/VoteTypeEnum.ts ================================================ export enum VoteTypeEnum { UPVOTE = 1, DOWNVOTE = -1, } ================================================ FILE: solutions/typescript/src/TaskManagement/ActivityLog.ts ================================================ import User from "./User"; import { v4 as uuidv4 } from "uuid"; export default class ActivityLog { private logId: string; private action: string; private performedBy: User; private timestamp: Date; constructor(action: string, performedBy: User) { this.logId = uuidv4(); this.action = action; this.performedBy = performedBy; this.timestamp = new Date(); } } ================================================ FILE: solutions/typescript/src/TaskManagement/Comment.ts ================================================ import User from "./User"; import { v4 as uuidv4 } from "uuid"; export default class Comment { private id: string; private content: string; private author: User; private timestamp: Date; constructor(content: string, author: User) { this.id = uuidv4(); this.content = content; this.author = author; this.timestamp = new Date(); } getAuthor() { return this.author; } } ================================================ FILE: solutions/typescript/src/TaskManagement/README.md ================================================ # Task Management System (LLD) ## Problem Statement Design and implement a Task Management System that allows users to create, assign, update, and track tasks. The system should support task priorities, statuses, comments, and user assignment. --- ## Requirements - **Task Creation:** Users can create tasks with a title, description, priority, and assignee. - **Task Assignment:** Tasks can be assigned to users and reassigned as needed. - **Task Status:** Tasks can have statuses such as TODO, IN_PROGRESS, DONE, etc. - **Task Priority:** Tasks can have priorities such as LOW, MEDIUM, HIGH. - **Comments:** Users can add comments to tasks. - **Task Updates:** Tasks can be updated (status, priority, assignee, etc.). - **Task Listing:** List all tasks, or filter by status, priority, or assignee. - **Extensibility:** Easy to add new statuses, priorities, or features. --- ## Core Entities - **Task:** Represents a task with title, description, status, priority, assignee, and comments. - **User:** Represents a user who can create, assign, and be assigned tasks. - **Comment:** Represents a comment on a task. - **TaskStatus:** Enum for task statuses (TODO, IN_PROGRESS, DONE, etc.). - **TaskPriority:** Enum for task priorities (LOW, MEDIUM, HIGH). - **TaskManager:** Manages the collection of tasks and provides methods for task operations. --- ## Class Design ### UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/taskmanagementsystem-class-diagram.png) ### 1. Task - **Fields:** id, title, description, status, priority, assignee (User), List - **Methods:** updateStatus(TaskStatus), updatePriority(TaskPriority), assignUser(User), addComment(Comment), etc. ### 2. User - **Fields:** id, name - **Methods:** getId(), getName() ### 3. Comment - **Fields:** id, content, author (User), timestamp ### 4. TaskStatus (enum) - Values: TODO, IN_PROGRESS, DONE, etc. ### 5. TaskPriority (enum) - Values: LOW, MEDIUM, HIGH ### 6. TaskManager - **Fields:** List - **Methods:** createTask(...), assignTask(...), updateTaskStatus(...), updateTaskPriority(...), addCommentToTask(...), listTasks(), listTasksByStatus(...), listTasksByAssignee(...), etc. --- ## Design Patterns Used - **Separation of Concerns:** Each class has a single responsibility (task, user, comment, management). - **Manager Pattern:** `TaskManager` acts as a service/manager for all task operations. --- ## Example Usage ```ts const taskManagementSystem = TaskManagementSystem.getInstance(); User alice = taskManagementSystem.createUser("Alice","alice@example.com"); User bob = taskManagementSystem.createUser("Bob","bob@example.com"); const taskList = taskManagementSystem.createTaskList("Enhancements"); const task = taskManagementSystem.createTask( taskList.getId(), "Task 1", "Description 1", new Date(), TaskPriorityEnum.LOW, alice.getId()); taskManagementSystem.assignTask(task.getId(), bob.getId()); taskManagementSystem.updateTaskStatus(task.getId(), TaskStatus.IN_PROGRESS); ``` --- ## Demo See `TaskManagementSystemDemo.ts` for a sample usage and simulation of the task management system. --- ## Extending the Framework - **Add new statuses or priorities:** Update the `TaskStatus` or `TaskPriority` enums. - **Add new features:** Such as deadlines, notifications, or task dependencies. --- ================================================ FILE: solutions/typescript/src/TaskManagement/SortingStrategy/SortByDueDate.ts ================================================ import Task from "../Task"; import TaskSortingStrategy from "./TaskSortingStrategy"; export default class SortByDueDate implements TaskSortingStrategy { sort(tasks: Task[]) { tasks.sort((taskA, taskB) => { const dueDateA = taskA.getDueDate(); const dueDateB = taskB.getDueDate(); // Sort in ascending order (earliest due date first) return dueDateA.getTime() - dueDateB.getTime(); }); } } ================================================ FILE: solutions/typescript/src/TaskManagement/SortingStrategy/SortByPriority.ts ================================================ import Task from "../Task"; import TaskSortingStrategy from "./TaskSortingStrategy"; export default class SortByPriority implements TaskSortingStrategy { private priorityOrder = { LOW: 1, MEDIUM: 2, HIGH: 3, CRITICAL: 4, }; sort(tasks: Task[]): void { tasks.sort((taskA, taskB) => { const priorityA = this.priorityOrder[taskA.getPriority()]; const priorityB = this.priorityOrder[taskB.getPriority()]; // Sort in descending order (Critical > High > Medium > Low) return priorityB - priorityA; }); } } ================================================ FILE: solutions/typescript/src/TaskManagement/SortingStrategy/TaskSortingStrategy.ts ================================================ import Task from "../Task"; export default interface TaskSortingStrategy { sort(tasks: Task[]): void; } ================================================ FILE: solutions/typescript/src/TaskManagement/Task.ts ================================================ import { TaskPriorityEnum } from "./TaskPriorityEnum"; import { TaskStatusEnum } from "./TaskStatusEnum"; import { v4 as uuidv4 } from "uuid"; import User from "./User"; import Comment from "./Comment"; import ActivityLog from "./ActivityLog"; export default class Task { private id: string; private title: string; private description: string; private priority: TaskPriorityEnum; private status: TaskStatusEnum; private dueDate: Date; private createdBy: User; private assignedTo: User | null; private comments: Comment[]; private subtasks: Task[]; private history: ActivityLog[]; constructor( title: string, description: string, dueDate: Date, priority: TaskPriorityEnum, createdBy: User, ) { this.id = uuidv4(); // from uuid package this.title = title; this.description = description; this.priority = priority; this.dueDate = dueDate; this.createdBy = createdBy; this.status = TaskStatusEnum.TODO; this.assignedTo = null; this.comments = []; this.subtasks = []; this.history = []; this.logActivity("Created"); } addComment(comment: Comment) { this.comments.push(comment); this.logActivity("Comment added by " + comment.getAuthor().getName()); } addSubtask(subtask: Task) { this.subtasks.push(subtask); this.logActivity("Subtask added: " + subtask.getTitle()); } logActivity(action: string) { this.history.push(new ActivityLog(action, this.createdBy)); } updateStatus(status: TaskStatusEnum) { this.status = status; this.logActivity("Status changed to " + status); } updatePriority(priority: TaskPriorityEnum) { this.priority = priority; this.logActivity("Priority changed to " + priority); } assignUser(user: User) { this.assignedTo = user; this.logActivity("Assigned to " + user.getName()); } getId() { return this.id; } getTitle() { return this.title; } getPriority() { return this.priority; } getDueDate() { return this.dueDate; } getAssignedTo() { return this.assignedTo; } getCreatedBy() { return this.createdBy; } getDescription() { return this.description; } getStatus() { return this.status; } } ================================================ FILE: solutions/typescript/src/TaskManagement/TaskList.ts ================================================ import Task from "./Task"; import { v4 as uuidv4 } from "uuid"; export default class TaskList { private id: string; private name: string; private tasks: Task[]; constructor(name: string) { this.id = uuidv4(); this.name = name; this.tasks = []; } addTask(task: Task) { this.tasks.push(task); } getTasks() { return this.tasks; } getId() { return this.id; } getName() { return this.name; } } ================================================ FILE: solutions/typescript/src/TaskManagement/TaskManagementSystem.ts ================================================ import Task from "./Task"; import { TaskPriorityEnum } from "./TaskPriorityEnum"; import { TaskStatusEnum } from "./TaskStatusEnum"; import User from "./User"; import TaskList from "./TaskList"; import Comment from "./Comment"; import TaskSortingStrategy from "./SortingStrategy/TaskSortingStrategy"; export default class TaskManagementSystem { private static instance: TaskManagementSystem | null; private users: Map; private tasks: Map; private taskLists: Map; private constructor() { this.users = new Map(); this.tasks = new Map(); this.taskLists = new Map(); } static getInstance() { if (!TaskManagementSystem.instance) { TaskManagementSystem.instance = new TaskManagementSystem(); } return TaskManagementSystem.instance; } createUser(name: string, email: string) { const user = new User(name, email); this.users.set(user.getId(), user); return user; } createTaskList(listName: string) { const taskList = new TaskList(listName); this.taskLists.set(taskList.getId(), taskList); return taskList; } createTask( listId: string, title: string, description: string, dueDate: Date, priority: TaskPriorityEnum, createdByUserId: string, ) { const taskList = this.taskLists.get(listId); if (taskList == null) throw new Error("TaskList not found."); const createdBy = this.users.get(createdByUserId); if (createdBy == null) throw new Error("User not found."); const task = new Task(title, description, dueDate, priority, createdBy); this.tasks.set(task.getId(), task); taskList.addTask(task); return task; } getTaskById(taskId: string) { const task = this.tasks.get(taskId); if (!task) { throw new Error("Task not found: " + taskId); } return task; } updateTaskStatus(taskId: string, status: TaskStatusEnum) { this.getTaskById(taskId).updateStatus(status); } updateTaskPriority(taskId: string, priority: TaskPriorityEnum) { this.getTaskById(taskId).updatePriority(priority); } assignTask(taskId: string, userId: string) { const user = this.users.get(userId); if (user == null) throw new Error("User not found."); this.getTaskById(taskId).assignUser(user); } addComment(taskId: string, commentText: string, author: User) { const task = this.getTaskById(taskId); task.addComment(new Comment(commentText, author)); } listTasksByUser(userId: string) { return [...this.tasks.values()].filter( (task) => userId == task.getAssignedTo()?.getId(), ); } listTasksByStatus(status: TaskStatusEnum) { return [...this.tasks.values()].filter( (task) => task.getStatus() == status, ); } deleteTask(taskId: string) { this.tasks.delete(taskId); } searchTasks(keyword: string, sortingStrategy: TaskSortingStrategy) { const matchingTasks = []; for (const task of this.tasks.values()) { if ( task.getTitle().includes(keyword) || task.getDescription().includes(keyword) ) { matchingTasks.push(task); } } sortingStrategy.sort(matchingTasks); return matchingTasks; } } ================================================ FILE: solutions/typescript/src/TaskManagement/TaskManagementSystemDemo.ts ================================================ import SortByDueDate from "./SortingStrategy/SortByDueDate"; import TaskManagementSystem from "./TaskManagementSystem"; import { TaskPriorityEnum } from "./TaskPriorityEnum"; import { TaskStatusEnum } from "./TaskStatusEnum"; export default class TaskManagementDemo { static run() { const taskManagementSystem = TaskManagementSystem.getInstance(); // Create users const user1 = taskManagementSystem.createUser( "John Doe", "john@example.com", ); const user2 = taskManagementSystem.createUser( "Jane Smith", "jane@example.com", ); // Create task lists const taskList1 = taskManagementSystem.createTaskList("Enhancements"); const taskList2 = taskManagementSystem.createTaskList("Bug Fix"); // Create tasks const task1 = taskManagementSystem.createTask( taskList1.getId(), "Task 1", "Description 1", new Date(), TaskPriorityEnum.LOW, user1.getId(), ); const task2 = taskManagementSystem.createTask( taskList1.getId(), "Task 2", "Description 2", new Date(), TaskPriorityEnum.MEDIUM, user1.getId(), ); const task3 = taskManagementSystem.createTask( taskList2.getId(), "Task 3", "Description 3", new Date(), TaskPriorityEnum.HIGH, user2.getId(), ); // Update task status taskManagementSystem.updateTaskStatus( task2.getId(), TaskStatusEnum.IN_PROGRESS, ); // Assign task taskManagementSystem.assignTask(task2.getId(), user2.getId()); // Search tasks const searchResults = taskManagementSystem.searchTasks( "Task", new SortByDueDate(), ); console.log("\nTasks with keyword Task:"); for (const task of searchResults) { console.log(task.getTitle()); } // Filter tasks by status const filteredTasks = taskManagementSystem.listTasksByStatus( TaskStatusEnum.TODO, ); console.log("\nTODO Tasks:"); for (const task of filteredTasks) { console.log(task.getTitle()); } // Mark a task as done taskManagementSystem.updateTaskStatus(task2.getId(), TaskStatusEnum.DONE); // Get tasks assigned to a user const userTaskList = taskManagementSystem.listTasksByUser(user2.getId()); console.log("\nTask for " + user2.getName() + ":"); for (const task of userTaskList) { console.log(task.getTitle()); } // Delete a task taskManagementSystem.deleteTask(task3.getId()); } } ================================================ FILE: solutions/typescript/src/TaskManagement/TaskPriorityEnum.ts ================================================ export enum TaskPriorityEnum { LOW = "LOW", MEDIUM = "MEDIUM", HIGH = "HIGH", CRITICAL = "CRITICAL", } ================================================ FILE: solutions/typescript/src/TaskManagement/TaskStatusEnum.ts ================================================ export enum TaskStatusEnum { TODO = "TODO", IN_PROGRESS = "IN_PROGRESS", DONE = "DONE", BLOCKED = "BLOCKED", } ================================================ FILE: solutions/typescript/src/TaskManagement/User.ts ================================================ import { v4 as uuidv4 } from "uuid"; export default class User { private id: string; private name: string; private email: string; constructor(name: string, email: string) { this.id = uuidv4(); this.name = name; this.email = email; } getName() { return this.name; } getId() { return this.id; } getEmail() { return this.email; } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/Direction.ts ================================================ export enum DirectionEnum { NORTH = "NORTH", SOUTH = "SOUTH", EAST = "EAST", WEST = "WEST", } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/Intersection.ts ================================================ import { DirectionEnum } from "./Direction"; import TrafficLight from "./TrafficLight"; import TrafficSignalController from "./TrafficSignalController"; export default class Intersection { private id: string; private signals: Map; private signalDurations: Map>; private controller: TrafficSignalController; constructor( id: string, signals: Map, signalDurations: Map>, ) { this.id = id; this.signals = signals; this.signalDurations = signalDurations; this.controller = new TrafficSignalController(signals, signalDurations); } start(startDirection: DirectionEnum) { this.controller.start(startDirection); } manualOverride(direction: DirectionEnum) { console.log("Manual override: Setting " + direction + " to GREEN."); this.controller.manualOverride(direction); } getSignal(direction: DirectionEnum) { return this.signals.get(direction); } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/README.md ================================================ # Traffic Signal System (LLD) ## Problem Statement Design and implement a Traffic Signal System to manage the traffic lights at an intersection. The system should support configurable signal durations for each direction and state, automatic cycling of signals using the State design pattern, and the ability to manually override signals as needed. --- ## Requirements - **Multiple Directions:** The intersection supports multiple directions (e.g., NORTH, SOUTH, EAST, WEST). - **Traffic Light States:** Each direction has a traffic light with states: GREEN, YELLOW, RED. - **Configurable Durations:** Each direction and state can have its own configurable duration. - **Automatic Cycling:** The system automatically cycles through the states for each direction in a round-robin fashion. - **Manual Override:** The system allows manual override to set a specific direction to GREEN at any time. - **Extensibility:** Easy to add new directions or states if needed. - **State Pattern:** Use the State design pattern to encapsulate state-specific behavior and transitions. --- ## Core Entities - **Direction:** Enum representing the directions at the intersection (NORTH, SOUTH, EAST, WEST). - **SignalState (interface):** Represents the state of a traffic light (GREEN, YELLOW, RED), with state-specific behavior. - **GreenState, YellowState, RedState:** Concrete implementations of `SignalState` for each light state. - **TrafficLight:** Represents a traffic light for a direction, maintains its current state and delegates behavior to the state. - **Intersection:** Represents the intersection, holds all traffic lights and their configurations, and exposes the manual override. - **TrafficSignalController:** Controls the cycling and overriding of traffic signals, manages timing and transitions using a scheduler. --- ## Class Design ### UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/trafficsignalsystem-class-diagram.png) ### 1. Direction - Enum: NORTH, SOUTH, EAST, WEST ### 2. SignalState (interface) - **Methods:** `void handle(TrafficLight, TrafficSignalController, Direction)`, `String getName()` ### 3. GreenState, YellowState, RedState - Implement `SignalState` - Each handles its own transition logic and duration ### 4. TrafficLight - **Fields:** currentState, direction - **Methods:** setState(SignalState), getState(), getDirection(), handle(TrafficSignalController) ### 5. Intersection - **Fields:** id, Map signals, Map> signalDurations, TrafficSignalController controller - **Methods:** start(Direction), manualOverride(Direction), getSignal(Direction) ### 6. TrafficSignalController - **Fields:** Map signals, Map> signalDurations, scheduler - **Methods:** start(Direction), scheduleStateChange(...), getSignalDuration(...), getNextDirection(...), getTrafficLight(...), manualOverride(Direction) --- ## Design Patterns Used - **State Pattern:** Each signal state (GREEN, YELLOW, RED) encapsulates its own behavior and transition logic. - **Scheduler/Timer:** For handling timed transitions between states. - **Strategy Pattern:** (Conceptually) for supporting different timing strategies per direction/state. --- ## Example Usage ```ts // Configure durations per direction and state const signalDurations = new Map>([ [Direction.NORTH, new Map([["GREEN", 4], ["YELLOW", 2], ["RED", 3]])], [Direction.SOUTH, new Map([["GREEN", 3], ["YELLOW", 2], ["RED", 4]])], [Direction.EAST, new Map([["GREEN", 5], ["YELLOW", 2], ["RED", 3]])], [Direction.WEST, new Map([["GREEN", 2], ["YELLOW", 2], ["RED", 5]])] ]); // Initialize traffic lights const signals = new Map(); for (const direction of Object.values(Direction)) { signals.set(direction, new TrafficLight(direction)); } // Create and start the controller const intersection1 = new Intersection("1", signals, signalDurations); intersection1.start(Direction.NORTH); ``` --- ## Demo See `TrafficSignalSystemDemo.ts` for a sample usage and simulation of the traffic signal system. --- ## Extending the Framework - **Add new directions:** Add to the `Direction` enum and update configuration. - **Add new states:** Add to the `SignalState` interface and implement new state classes. - **Custom timing strategies:** Implement new strategies for special intersections or adaptive signals. --- ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/SignalState/GreenState.ts ================================================ import { DirectionEnum } from "../Direction"; import TrafficLight from "../TrafficLight"; import TrafficSignalController from "../TrafficSignalController"; import SignalState from "./SignalState"; import YellowState from "./YellowState"; export default class GreenState implements SignalState { handle( light: TrafficLight, controller: TrafficSignalController, direction: DirectionEnum, ) { console.log("Direction: " + direction + " | State: GREEN"); const duration = controller.getSignalDuration(direction, this); controller.scheduleStateChange( light, direction, new YellowState(), duration, ); } getName() { return "GREEN"; } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/SignalState/RedState.ts ================================================ import { DirectionEnum } from "../Direction"; import TrafficLight from "../TrafficLight"; import TrafficSignalController from "../TrafficSignalController"; import GreenState from "./GreenState"; import SignalState from "./SignalState"; export default class RedState implements SignalState { handle( light: TrafficLight, controller: TrafficSignalController, direction: DirectionEnum, ) { console.log("Direction: " + direction + " | State: RED"); const duration = controller.getSignalDuration(direction, this); // After RED, move to next direction's GREEN const nextDirection = controller.getNextDirection(direction); controller.scheduleStateChange( controller.getTrafficLight(nextDirection), nextDirection, new GreenState(), duration, ); } getName() { return "RED"; } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/SignalState/SignalState.ts ================================================ import { DirectionEnum } from "../Direction"; import TrafficLight from "../TrafficLight"; import TrafficSignalController from "../TrafficSignalController"; export default interface SignalState { handle( light: TrafficLight, controller: TrafficSignalController, direction: DirectionEnum, ): void; getName(): string; } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/SignalState/YellowState.ts ================================================ import { DirectionEnum } from "../Direction"; import TrafficLight from "../TrafficLight"; import TrafficSignalController from "../TrafficSignalController"; import RedState from "./RedState"; import SignalState from "./SignalState"; export default class YellowState implements SignalState { handle( light: TrafficLight, controller: TrafficSignalController, direction: DirectionEnum, ) { console.log("Direction: " + direction + " | State: YELLOW"); const duration = controller.getSignalDuration(direction, this); controller.scheduleStateChange( light, direction, new RedState(), duration, ); } getName() { return "YELLOW"; } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/TrafficLight.ts ================================================ import { DirectionEnum } from "./Direction"; import RedState from "./SignalState/RedState"; import SignalState from "./SignalState/SignalState"; import TrafficSignalController from "./TrafficSignalController"; export default class TrafficLight { private state: SignalState; private direction: DirectionEnum; constructor(direction: DirectionEnum) { this.direction = direction; this.state = new RedState(); // Default initial state } setState(state: SignalState) { this.state = state; } getState() { return this.state; } getDirection() { return this.direction; } handle(controller: TrafficSignalController) { this.state.handle(this, controller, this.direction); } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/TrafficSignalController.ts ================================================ import { DirectionEnum } from "./Direction"; import GreenState from "./SignalState/GreenState"; import SignalState from "./SignalState/SignalState"; import TrafficLight from "./TrafficLight"; export default class TrafficSignalController { private signals: Map; private signalDurations: Map>; constructor( signals: Map, signalDurations: Map>, ) { this.signals = signals; this.signalDurations = signalDurations; } start(startDirection: DirectionEnum) { const light = this.signals.get(startDirection); if (!light) return; light.setState(new GreenState()); light.handle(this); } scheduleStateChange( light: TrafficLight, direction: DirectionEnum, nextState: SignalState, delaySeconds: number, ) { setTimeout(() => { light.setState(nextState); light.handle(this); // Handle the light after state change }, delaySeconds * 1000); } getSignalDuration(direction: DirectionEnum, state: SignalState) { return this.signalDurations.get(direction)?.get(state.getName()) || 0; } getNextDirection(current: DirectionEnum): DirectionEnum { const directions: DirectionEnum[] = Object.values(DirectionEnum); const next = (directions.indexOf(current) + 1) % directions.length; return directions[next]; } getTrafficLight(direction: DirectionEnum) { const signal = this.signals.get(direction); if (!signal) throw new Error("Signal Not Found."); return signal; } manualOverride(direction: DirectionEnum) { // Immediately set the specified direction to GREEN and start its cycle const light = this.signals.get(direction); if (!light) return; light.setState(new GreenState()); light.handle(this); } } ================================================ FILE: solutions/typescript/src/TrafficSignalSystem/TrafficSignalSystemDemo.ts ================================================ import { DirectionEnum } from "./Direction"; import Intersection from "./Intersection"; import TrafficLight from "./TrafficLight"; export default class TrafficSignalSystemDemo { static run() { // Configure durations per direction and state const signalDurations = new Map>([ [ DirectionEnum.NORTH, new Map([ ["GREEN", 4], ["YELLOW", 2], ["RED", 3], ]), ], [ DirectionEnum.SOUTH, new Map([ ["GREEN", 3], ["YELLOW", 2], ["RED", 4], ]), ], [ DirectionEnum.EAST, new Map([ ["GREEN", 5], ["YELLOW", 2], ["RED", 3], ]), ], [ DirectionEnum.WEST, new Map([ ["GREEN", 2], ["YELLOW", 2], ["RED", 5], ]), ], ]); // Initialize traffic lights const signals = new Map(); for (const direction of Object.values(DirectionEnum)) { signals.set(direction, new TrafficLight(direction)); } // Create and start the controller const intersection1 = new Intersection("1", signals, signalDurations); intersection1.start(DirectionEnum.NORTH); } } ================================================ FILE: solutions/typescript/src/VendingMachine/Coin.ts ================================================ export enum Coin { PENNY = 1, NICKEL = 5, DIME = 10, QUARTER = 25, } ================================================ FILE: solutions/typescript/src/VendingMachine/Inventory.ts ================================================ import Item from "./Item"; export default class Inventory { private itemMap: Map; private stockMap: Map; constructor() { this.itemMap = new Map(); this.stockMap = new Map(); } addItem(code: string, item: Item, quantity: number) { this.itemMap.set(code, item); this.stockMap.set(code, quantity); } getItem(code: string) { return this.itemMap.get(code); } isAvailable(code: string) { return (this.stockMap.get(code) ?? 0) > 0; } reduceStock(code: string) { const stock = this.stockMap.get(code); if (!stock || stock == 0) throw new Error("No Stock"); this.stockMap.set(code, stock - 1); } } ================================================ FILE: solutions/typescript/src/VendingMachine/Item.ts ================================================ export default class Item { private code: string; private name: string; private price: number; constructor(code: string, name: string, price: number) { this.code = code; this.name = name; this.price = price; } getName() { return this.name; } getPrice() { return this.price; } } ================================================ FILE: solutions/typescript/src/VendingMachine/README.md ================================================ # Vending Machine (LLD) ## Problem Statement Design and implement a Vending Machine system that allows users to select products, insert coins/notes, dispense products, and return change. The system should manage inventory, handle payments, and use the State design pattern for its operations. --- ## Requirements - **Product Management:** The system manages a catalog of products, each with a price and available quantity. - **Inventory Management:** The system tracks the quantity of each item and prevents dispensing if out of stock. - **Payment Handling:** The system accepts coins and notes, tracks total payment, and returns change if necessary. - **State Management:** The system uses the State design pattern to manage its operational states (Idle, Ready, Dispense, ReturnChange). - **User Interaction:** Users can select products, insert coins/notes, and receive products and change. - **Extensibility:** Easy to add new item types, payment methods, or states. --- ## Core Entities - **VendingMachine:** Main class that manages inventory, state transitions, item selection, and payment. - **Product:** Represents a item with a name and price. - **Inventory:** Manages the stock of products. - **Coin / Note:** Represents accepted denominations for payment. - **VendingMachineState (interface):** Interface for different machine states. - **IdleState, ReadyState, DispenseState, ReturnChangeState:** Concrete states implementing VendingMachineState. - **Singleton Pattern:** VendingMachine is implemented as a singleton. --- ## Class Design ### UML Class Diagram ![](../../../../uml-diagrams/class-diagrams/vendingmachine-class-diagram.png) ### 1. VendingMachine - **Fields:** Inventory inventory, VendingMachineState idleState, readyState, dispenseState, returnChangeState, currentState, Product selectedProduct, double totalPayment - **Methods:** addProduct(String, double, int), selectProduct(Product), insertCoin(Coin), insertNote(Note), dispenseProduct(), returnChange(), setState(VendingMachineState), getInstance(), etc. ### 2. Product - **Fields:** String name, double price ### 3. Inventory - **Fields:** Map productQuantities - **Methods:** addProduct(Product, int), getQuantity(Product), reduceQuantity(Product), isAvailable(Product) ### 4. Coin / Note - **Fields:** double value - **Methods:** getValue() ### 5. VendingMachineState (interface) - **Methods:** selectProduct(Product), insertCoin(Coin), insertNote(Note), dispenseProduct(), returnChange() ### 6. IdleState, ReadyState, DispenseState, ReturnChangeState - **Implements:** VendingMachineState - **Behavior:** Each state handles allowed operations and transitions. --- ## Example Usage ```ts const machine = VendingMachine.getInstance(); const chips = machine.addItem("A1","Chips", 15, 10); machine.selectItem("A1"); machine.insertCoin(COIN.DIME); machine.insertCoin(COIN.NICKEL); machine.dispense(); ``` --- ## Demo See `VendingMachineDemo` class for a sample usage and simulation of the vending machine. --- ## Extending the Framework - **Add new payment methods:** Support for cards, mobile payments, etc. - **Add new states:** Maintenance, OutOfOrder, etc. - **Add item categories:** Snacks, drinks, etc. --- ## Design Patterns Used - **State Pattern:** For managing machine states and transitions. - **Singleton Pattern:** For ensuring a single instance of the VendingMachine. --- ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachine.ts ================================================ import { Coin } from "./Coin"; import Inventory from "./Inventory"; import Item from "./Item"; import DispensingState from "./VendingMachineState/DispensingState"; import HasMoneyState from "./VendingMachineState/HasMoneyState"; import IdleState from "./VendingMachineState/IdleState"; import ItemSelectedState from "./VendingMachineState/ItemSelectedState"; import VendingMachineState from "./VendingMachineState/VendingMachineState"; export default class VendingMachine { private static instance: VendingMachine | null; private inventory: Inventory; private selectedItemCode: string | null; private balance: number; private currentState: VendingMachineState; private idleState: VendingMachineState; private itemSelectedState: VendingMachineState; private hasMoneyState: VendingMachineState; private dispensingState: VendingMachineState; private constructor() { this.inventory = new Inventory(); this.idleState = new IdleState(this); this.itemSelectedState = new ItemSelectedState(this); this.hasMoneyState = new HasMoneyState(this); this.dispensingState = new DispensingState(this); this.currentState = this.idleState; this.balance = 0; this.selectedItemCode = null; } static getInstance() { if (VendingMachine.instance == null) { VendingMachine.instance = new VendingMachine(); } return VendingMachine.instance; } insertCoin(coin: Coin) { this.currentState.insertCoin(coin); } addItem(code: string, name: string, price: number, quantity: number) { const item = new Item(code, name, price); this.inventory.addItem(code, item, quantity); return item; } selectItem(code: string) { this.currentState.selectItem(code); } dispense() { this.currentState.dispense(); } dispenseItem() { if (!this.selectedItemCode) { throw new Error("No Item Selected Yet"); } const item = this.inventory.getItem(this.selectedItemCode); if (!item) { throw new Error("Item Not In Inventory"); } if (this.balance >= item.getPrice()) { this.inventory.reduceStock(this.selectedItemCode); this.balance -= item.getPrice(); console.log("Dispensed: " + item.getName()); if (this.balance > 0) { console.log("Returning change: " + this.balance); } } this.resetToIdleState(); this.setState(this.getIdleState()); } refundBalance() { console.log("Refunding: " + this.balance); this.balance = 0; } resetToIdleState() { this.selectedItemCode = null; this.balance = 0; } addBalance(value: number) { this.balance += value; } //Getter, Setters getIdleState() { return this.idleState; } getItemSelectedState() { return this.itemSelectedState; } getHasMoneyState() { return this.hasMoneyState; } getDispensingState() { return this.dispensingState; } getInventory() { return this.inventory; } getSelectedItem() { if (!this.selectedItemCode) { throw new Error("No Item Selected Yet"); } return this.inventory.getItem(this.selectedItemCode); } setSelectedItemCode(code: string) { this.selectedItemCode = code; } getBalance() { return this.balance; } setState(state: VendingMachineState) { this.currentState = state; } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineDemo.ts ================================================ import { Coin } from "./Coin"; import VendingMachine from "./VendingMachine"; export default class VendingMachineDemo{ static run(){ const vendingMachine = VendingMachine.getInstance(); // Add products to the inventory vendingMachine.addItem("A1", "Coke", 25, 3); vendingMachine.addItem("A2", "Pepsi", 25, 2); vendingMachine.addItem("B1", "Water", 10, 5); // Select a product console.log("\n--- Step 1: Select an item ---"); vendingMachine.selectItem("A1"); // Insert coins console.log("\n--- Step 2: Insert coins ---"); vendingMachine.insertCoin(Coin.DIME); // 10 vendingMachine.insertCoin(Coin.DIME); // 10 vendingMachine.insertCoin(Coin.NICKEL); // 5 // Dispense the product console.log("\n--- Step 3: Dispense item ---"); vendingMachine.dispense(); // Should dispense Coke // Select another item console.log("\n--- Step 4: Select another item ---"); vendingMachine.selectItem("B1"); // Insert more amount console.log("\n--- Step 5: Insert more than needed ---"); vendingMachine.insertCoin(Coin.QUARTER); // 25 // Try to dispense the product console.log("\n--- Step 6: Dispense and return change ---"); vendingMachine.dispense(); } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineState/DispensingState.ts ================================================ import VendingMachine from "../VendingMachine"; import VendingMachineState from "./VendingMachineState"; export default class DispensingState implements VendingMachineState { private machine: VendingMachine; constructor(machine: VendingMachine) { this.machine = machine; } insertCoin(): void { console.log("Currently dispensing. Please wait."); } selectItem() { console.log("Currently dispensing. Please wait."); } dispense() { // already triggered by HasMoneyState } refund() { console.log("Dispensing in progress. Refund not allowed."); } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineState/HasMoneyState.ts ================================================ import VendingMachine from "../VendingMachine"; import VendingMachineState from "./VendingMachineState"; export default class HasMoneyState implements VendingMachineState { private machine: VendingMachine; constructor(machine: VendingMachine) { this.machine = machine; } insertCoin() { console.log("Already received full amount."); } selectItem() { console.log("Item already selected."); } dispense() { this.machine.setState(this.machine.getDispensingState()); this.machine.dispenseItem(); } refund() { this.machine.refundBalance(); this.machine.resetToIdleState(); this.machine.setState(this.machine.getIdleState()); } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineState/IdleState.ts ================================================ import VendingMachine from "../VendingMachine"; import VendingMachineState from "./VendingMachineState"; export default class IdleState implements VendingMachineState { private machine: VendingMachine; constructor(machine: VendingMachine) { this.machine = machine; } selectItem(code: string): void { if (!this.machine.getInventory().isAvailable(code)) { console.log("Item not available."); return; } this.machine.setSelectedItemCode(code); this.machine.setState(this.machine.getItemSelectedState()); console.log("Item Selected = ", code); } insertCoin(): void { console.log("Please select the product first"); } dispense(): void { console.log("Please select the product first"); } refund(): void { console.log("Please select the product first"); } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineState/ItemSelectedState.ts ================================================ import { Coin } from "../Coin"; import VendingMachine from "../VendingMachine"; import VendingMachineState from "./VendingMachineState"; export default class ItemSelectedState implements VendingMachineState { private machine: VendingMachine; constructor(machine: VendingMachine) { this.machine = machine; } insertCoin(coin: Coin) { const price = this.machine.getSelectedItem()?.getPrice(); if (!price) { throw new Error("Item Not Selected Yet."); } this.machine.addBalance(coin); console.log("Coin Inserted: " + coin); if (this.machine.getBalance() >= price) { console.log("Sufficient money received."); this.machine.setState(this.machine.getHasMoneyState()); } } selectItem() { console.log("Item already selected."); } dispense() { console.log("Please insert sufficient money."); } refund() { this.machine.resetToIdleState(); this.machine.setState(this.machine.getIdleState()); } } ================================================ FILE: solutions/typescript/src/VendingMachine/VendingMachineState/VendingMachineState.ts ================================================ import { Coin } from "../Coin"; export default interface VendingMachineState { insertCoin(coin: Coin): void; selectItem(code: string): void; dispense(): void; refund(): void; } ================================================ FILE: solutions/typescript/src/lldrunner.ts ================================================ import ParkingLotDemo from "./ParkingLot/ParkingLotDemo"; import StackOverflowDemo from "./StackOverflow/StackOverflowDemo"; import VendingMachineDemo from "./VendingMachine/VendingMachineDemo"; import LoggingFrameworkDemo from "./LoggingFramework/LoggingFrameworkDemo"; import TrafficSignalSystemDemo from "./TrafficSignalSystem/TrafficSignalSystemDemo"; import CoffeVendingMachineDemo from "./CoffeeVendingMachine/CoffeeVendingMachineDemo"; import TaskManagementDemo from "./TaskManagement/TaskManagementSystemDemo"; // ParkingLotDemo.run() // StackOverflowDemo.run() // VendingMachineDemo.run() // LoggingFrameworkDemo.run() // TrafficSignalSystemDemo.run() // CoffeVendingMachineDemo.run() TaskManagementDemo.run(); ================================================ FILE: solutions/typescript/tsconfig.json ================================================ { "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ "target": "ESNEXT" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ // "outDir": "./", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ "rootDir": "src", // project root "outDir": "dist", // compiled JS files go here // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ /* Module Resolution Options */ "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["./node_modules/@types"] /* List of folders to include type definitions from. */, // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "skipLibCheck": true /* Skip type checking of declaration files. */, "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, "exclude": ["node_modules", ".build"], "include": ["src/**/*"] }