کلاس در پایتون
فهرست عناوین
- مقدمهای بر کلاسها و اشیاء در پایتون
- ساختار یک کلاس در پایتون
- مفاهیم کلاسهای دادهمحور و کلاسهای تابعی در پایتون
- استفاده از کلاسها در پروژههای واقعی
- نکات پیشرفته و بهترین شیوهها برای طراحی کلاسها
- چگونه کلاسها میتوانند به افزایش بازدهی کد کمک کنند
- تمرین های مبتدی
- تمرین های متوسط
- تمرین های پیشرفته
در دنیای برنامهنویسی، یکی از ابزارهای قدرتمندی که هر برنامهنویس باید بهخوبی با آن آشنا باشد، کلاس ها در پایتون هستند. شاید تا به حال با مفاهیم پیچیدهای چون اشیاء و شیگرایی روبهرو شده باشی، ولی آیا میدانی که این مفاهیم چطور میتوانند کدهای تو را از حالت یک لیست طولانی و بینظم به یک ساختار منظم، خوانا و کارآمد تبدیل کنند؟ کلاسها نه تنها به تو این امکان را میدهند که دادهها و متدهای مربوط به آنها را در یک بسته واحد نگه داری، بلکه قدرتهایی مثل ارثبری، پلیمورفیسم و کپسولهسازی را به کدهایت میدهند که باعث میشود در دنیای پیچیده نرمافزار، به یک برنامهنویس حرفهای و موثر تبدیل شوی.
در این درس، نه تنها به اصول ابتدایی کلاسها خواهیم پرداخت، بلکه به سراغ تکنیکها و نکات پیشرفتهای خواهیم رفت که در کمتر منابعی پیدا میشوند. پس اگر میخواهی یاد بگیری که چطور میتوانی از کلاسها در پایتون به بهترین شکل استفاده کنی، آماده شو برای یک سفر هیجانانگیز به دنیای شیگرایی. این درس برای تو طراحی شده تا هر مفهومی را بهطور کامل درک کنی و با مثالهای کاربردی، بتوانی در پروژههای واقعی خودت از این مفاهیم استفاده کنی. بیا با هم شروع کنیم!
مقدمهای بر کلاسها و اشیاء در پایتون
برنامهنویسی شیگرا (Object-Oriented Programming یا OOP) یکی از قدرتمندترین و محبوبترین رویکردها برای توسعه نرمافزار است که به شما این امکان را میدهد تا کدهایتان را با ساختار بهتری سازماندهی کنید. در پایتون، این رویکرد از طریق کلاسها و اشیاء پیادهسازی میشود، و اگر بخواهید کدهای خود را در مقیاس بزرگتری نگهداری، گسترش و مدیریت کنید، این مفاهیم جزء ضروریات به حساب میآیند.
کلاسها، آغازی برای سازماندهی کدها
در زبان پایتون، کلاسها شبیه به الگوهایی هستند که میتوانید از آنها برای ساخت اشیاء (Objects) استفاده کنید. یک کلاس به شما این امکان را میدهد که ویژگیها (Properties) و متدها (Methods) را در قالب یک واحد سازماندهی کنید. در واقع، کلاسها یک نوع ابزار طراحی هستند که شما را قادر میسازند ویژگیها و رفتارهای مرتبط با یک موضوع خاص را در یک جا نگهدارید.
مثلاً اگر شما بخواهید مدل یک ماشین را در برنامه خود پیادهسازی کنید، میتوانید یک کلاس با ویژگیهایی مثل «رنگ»، «مدل» و «سرعت» ایجاد کنید، همچنین متدهایی مانند «حرکت» یا «ایست» را نیز به آن اضافه کنید. در این حالت، کلاس شما بهعنوان یک الگو برای ساختن اشیاء مختلف از ماشینها عمل میکند.
اشیاء: موجودیتهای واقعی در دنیای کد
وقتی که یک کلاس را تعریف میکنید، در حقیقت یک الگو برای اشیاء آیندهتان میسازید. حالا هر بار که نیاز داشته باشید یک شی از این کلاس بسازید، میتوانید آن را ایجاد کنید (instantiate). هر شیء که از یک کلاس ساخته میشود، تمام ویژگیها و متدهای آن کلاس را خواهد داشت.
برای مثال، اگر کلاس "ماشین" را تعریف کردهاید، میتوانید اشیاء مختلفی مانند «ماشین قرمز»، «ماشین سبز» یا «ماشین سریع» ایجاد کنید. هر کدام از این اشیاء ویژگیها و متدهای کلاس "ماشین" را بهصورت مجزا دارند، اما از همان الگوی کلی پیروی میکنند.
چرا کلاسها و اشیاء مهماند؟
- ساختاردهی به کد: کلاسها به شما این امکان را میدهند که کدهایتان را در بخشهای جداگانه و منظم دستهبندی کنید. این کار باعث میشود که کد شما قابل فهمتر، نگهداریاش آسانتر و قابلیت گسترش آن راحتتر باشد.
- کاهش تکرار: وقتی از کلاسها استفاده میکنید، میتوانید همان الگو را برای ایجاد اشیاء مختلف استفاده کنید، به این ترتیب از نوشتن کدهای مشابه جلوگیری میشود.
- استفاده از شیگرایی: با استفاده از کلاسها میتوانید ویژگیها و متدهای یک شیء را پنهان کنید (کپسولهسازی)، رفتارهای مختلف اشیاء را با هم ترکیب کنید (پلیمورفیسم) یا حتی از کلاسهای دیگر ویژگیها را به ارث ببرید (ارثبری).
- انعطافپذیری و مقیاسپذیری: هنگامی که کدهای شما پیچیدهتر میشوند، کلاسها این امکان را میدهند که تغییرات را در نقاط خاصی از برنامه اعمال کنید بدون اینکه نیاز باشد تمام برنامه را اصلاح کنید.
از کجا شروع کنیم؟
برای استفاده از کلاسها در پایتون، فقط کافی است که یک کلاس را با استفاده از کلمه کلیدی `class` تعریف کنید. درون این کلاس میتوانید ویژگیها و متدهای مختلف را اضافه کنید. در ادامه، با ایجاد اشیاء از این کلاس، میتوانید ویژگیها و رفتارهای موردنظر را برای هر شیء اعمال کنید.
بیایید با یک مثال ساده شروع کنیم:
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
def bark(self):
print(f"{self.name} says woof!")
# ایجاد یک شیء از کلاس Dog
my_dog = Dog("Buddy", "Golden Retriever")
my_dog.bark() # خروجی: Buddy says woof!
در این مثال، ما یک کلاس به نام Dog تعریف کردهایم که ویژگیهایی مثل «نام» و «نژاد» دارد و متدی به نام bark که صدای «واق واق» میزند. سپس یک شیء از این کلاس به نام my_dog ایجاد میکنیم و متد bark را فراخوانی میکنیم.
ساختار یک کلاس در پایتون
کلاسها در پایتون ساختار سادهای دارند که برای برنامهنویسان مبتدی و پیشرفته به راحتی قابل درک است. در این بخش، قصد داریم بهطور کامل و با جزئیات، ساختار یک کلاس در پایتون را بررسی کنیم و مثالهای مختلفی را برای هر بخش از کلاسها ارائه دهیم. این توضیحات به شما کمک خواهد کرد تا درک عمیقی از نحوه تعریف و استفاده از کلاسها در پروژههای خود پیدا کنید.
1. تعریف کلاس
برای شروع، یک کلاس را با استفاده از کلمه کلیدی class تعریف میکنیم. بعد از نام کلاس، دو نقطه (:) قرار میدهیم و سپس محتویات کلاس را داخل بلوک تو رفتۀ آن قرار میدهیم. در پایتون، این بلوکها با تورفتگی (indentation) مشخص میشوند.
class Car:
pass # کلاس خالی، هیچ ویژگی یا متدی ندارد
در اینجا کلاس Car تعریف شده است، ولی فعلاً هیچ ویژگی یا متدی به آن اضافه نکردهایم. اکنون که ساختار اولیه کلاس را توضیح دادیم، بیایید آن را گسترش دهیم.
2. ویژگیها (Attributes)
ویژگیها، دادههایی هستند که در یک شیء نگهداری میشوند و به آن ویژگیهای خاصی میدهند. ویژگیها معمولاً در داخل متد `__init__` (که سازنده کلاس است) تعریف میشوند. این متد بهطور خودکار هنگام ایجاد یک شیء جدید از کلاس فراخوانی میشود.
در اینجا یک مثال از یک کلاس با ویژگیهای ساده داریم:
class Car:
def __init__(self, brand, model, year):
self.brand = brand # برند خودرو
self.model = model # مدل خودرو
self.year = year # سال تولید خودرو
در این مثال:
- متد __init__ برای تعریف ویژگیهای `brand` (برند)، model (مدل)، و year (سال تولید) به کار رفته است.
- self به شیء خود اشاره میکند و برای دسترسی به ویژگیها و متدهای کلاس استفاده میشود.
3. متدها (Methods)
متدها رفتارهایی هستند که کلاسها دارند و میتوانند برای انجام عملیات خاصی در رابطه با شیء استفاده شوند. متدها بهطور معمول در داخل خود کلاس تعریف میشوند و مانند ویژگیها، از کلمه کلیدی `self` برای دسترسی به شیء استفاده میکنند.
در اینجا یک کلاس Car داریم که یک متد برای نمایش مشخصات خودرو اضافه کردهایم:
class Car:
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
def display_info(self):
print(f"Brand: {self.brand}")
print(f"Model: {self.model}")
print(f"Year: {self.year}")
در این مثال:
- متد display_info مشخصات خودرو را نمایش میدهد.
- هنگامی که شیء از کلاس Car ساخته میشود، میتوان از متد display_info برای نمایش اطلاعات خودرو استفاده کرد.
4. ایجاد شیء از کلاس
برای ایجاد یک شیء از یک کلاس، کافی است که کلاس را مانند یک تابع فراخوانی کرده و پارامترهای موردنیاز را به آن ارسال کنیم. سپس میتوان از ویژگیها و متدهای شیء استفاده کرد.
my_car = Car("Toyota", "Corolla", 2020)
my_car.display_info()
خروجی:
Brand: Toyota
Model: Corolla
Year: 2020
در اینجا، با استفاده از پارامترهای "Toyota"، "Corolla" و "2020" یک شیء جدید به نام my_car از کلاس Car ساختهایم و سپس از متد display_info برای نمایش اطلاعات استفاده کردیم.
5. متدهای ویژه (Special Methods)
در پایتون، برخی متدها وجود دارند که بهطور خودکار توسط سیستم پایتون فراخوانی میشوند. این متدها با `__` (دوتا خط زیر) مشخص میشوند و به آنها متدهای ویژه میگوییم. یکی از مهمترین این متدها، متد __init__ است که برای سازنده کلاس استفاده میشود.
مثال دیگری از متدهای ویژه که کاربرد زیادی دارد، متد __str__ است. این متد وقتی که بخواهید یک شیء را بهطور مستقیم چاپ کنید فراخوانی میشود و میتوانید آن را برای چاپ نمایشی از شیء خود سفارشی کنید.
class Car:
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
def __str__(self):
return f"{self.year} {self.brand} {self.model}"
my_car = Car("Toyota", "Corolla", 2020)
print(my_car)
خروجی:
2020 Toyota Corolla
در اینجا، ما متد __str__ را برای تعیین چگونگی نمایش شیء `Car` هنگام چاپ آن سفارشی کردهایم.
6. ارثبری (Inheritance)
یکی از ویژگیهای قوی شیگرایی در پایتون، امکان ارثبری است. با استفاده از ارثبری، میتوانیم یک کلاس جدید از یک کلاس موجود بسازیم و ویژگیها و متدهای آن را به ارث ببریم. کلاس جدید میتواند ویژگیها و متدهای خود را اضافه کند یا ویژگیهای کلاس پایه را تغییر دهد.
در اینجا یک مثال از ارثبری داریم:
class ElectricCar(Car):
def __init__(self, brand, model, year, battery_size):
super().__init__(brand, model, year) # فراخوانی سازنده کلاس پایه
self.battery_size = battery_size # اضافه کردن ویژگی جدید
def display_battery(self):
print(f"Battery size: {self.battery_size} kWh")
def display_info(self):
super().display_info() # استفاده از متد کلاس پایه
self.display_battery()
my_electric_car = ElectricCar("Tesla", "Model S", 2022, 100)
my_electric_car.display_info()
خروجی:
Brand: Tesla
Model: Model S
Year: 2022
Battery size: 100 kWh
در این مثال:
- کلاس ElectricCar از کلاس Car ارثبری کرده است.
- ویژگی battery_size را به کلاس اضافه کردهایم.
- متد display_info را تغییر دادهایم تا اطلاعات مربوط به باتری را هم نمایش دهد.
مفاهیم کلاسهای دادهمحور و کلاسهای تابعی در پایتون
در پایتون، همانطور که میدانید کلاسها میتوانند به دو سبک اصلی پیادهسازی شوند: کلاسهای دادهمحور (Data-oriented classes) و کلاسهای تابعی (Functional classes). هر یک از این دو سبک ویژگیهای خاص خود را دارند و در شرایط مختلف کاربردهایی دارند. در این بخش، به توضیح هر یک از این مفاهیم با جزئیات و مثالهای متعدد خواهیم پرداخت.
1. کلاسهای دادهمحور (Data-Oriented Classes)
کلاسهای دادهمحور معمولاً بهعنوان ساختارهایی برای ذخیره و مدیریت دادهها استفاده میشوند. این کلاسها بیشتر بر روی ویژگیها (attributes) متمرکز هستند و بهطور معمول برای ذخیرهسازی اطلاعات و انتقال آنها در برنامه استفاده میشوند. این نوع کلاسها بیشتر مانند یک رکورد یا ساختار داده عمل میکنند که ویژگیها (فیلدها) را نگهداری میکنند.
در کلاسهای دادهمحور، معمولاً ویژگیها بهصورت مستقیم توسط متدهای کلاس دستکاری نمیشوند، بلکه از طریق دسترسی مستقیم به آنها یا از طریق متدهای ساده برای تغییر آنها انجام میشود.
ویژگیها و کاربردها:
- بیشتر برای ذخیرهسازی دادهها.
- ویژگیها بهطور مستقیم دستکاری میشوند.
- معمولاً به متدهای پیچیده نیاز ندارند.
- این کلاسها بیشتر بهعنوان نوعی "جعبه داده" عمل میکنند.
مثال:
class Person:
def __init__(self, name, age):
self.name = name # ویژگی دادهای
self.age = age # ویژگی دادهای
def display_info(self):
print(f"Name: {self.name}, Age: {self.age}")
# ایجاد شیء از کلاس
person1 = Person("Ali", 30)
# دسترسی به ویژگیها و استفاده از آنها
print(person1.name) # خروجی: Ali
print(person1.age) # خروجی: 30
# نمایش اطلاعات از طریق متد
person1.display_info() # خروجی: Name: Ali, Age: 30
در این مثال، کلاس Person بهطور واضح دادهها (نام و سن) را ذخیره کرده است و هیچ متد پیچیدهای برای دستکاری آنها وجود ندارد. فقط یک متد display_info() داریم که اطلاعات را نمایش میدهد.
2. کلاسهای تابعی (Functional Classes)
در کلاسهای تابعی، هدف اصلی استفاده از متدها و توابع است. این کلاسها بیشتر بر روی عملکرد و منطق تمرکز دارند تا دادهها. در این نوع کلاسها، ممکن است ویژگیها (attributes) بهطور موقت و فقط برای انجام یک عملیات خاص در یک تابع یا متد ذخیره شوند.
کلاسهای تابعی معمولاً از متدهای بیشتری استفاده میکنند که دادهها را بهطور فعال تغییر میدهند یا پردازش میکنند. در اینجا، بیشتر هدف برنامهنویسی عملکردی است، نه فقط ذخیرهسازی داده.
ویژگیها و کاربردها:
- بیشتر برای انجام محاسبات و پردازش دادهها.
- ویژگیها اغلب بهطور موقت برای انجام عملیات تغییر میکنند.
- از متدهای بیشتری برای اعمال منطق و پردازش دادهها استفاده میشود.
- بیشتر برای پردازش و کار با دادهها و عملگرهای خاص مفید هستند.
مثال:
class Calculator:
def __init__(self):
pass
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
def divide(self, a, b):
if b != 0:
return a / b
else:
return "Cannot divide by zero"
# ایجاد شیء از کلاس
calc = Calculator()
# استفاده از متدهای مختلف برای انجام عملیات ریاضی
print(calc.add(5, 3)) # خروجی: 8
print(calc.subtract(5, 3)) # خروجی: 2
print(calc.multiply(5, 3)) # خروجی: 15
print(calc.divide(5, 3)) # خروجی: 1.666...
print(calc.divide(5, 0)) # خروجی: Cannot divide by zero
در این مثال، کلاس Calculator بیشتر بر روی انجام عملیات ریاضی تمرکز دارد. ویژگیها در این کلاس ذخیره نمیشوند؛ بلکه هر متد بهطور موقت دادهها را برای انجام محاسبات میگیرد و نتایج را برمیگرداند.
تفاوتهای کلیدی بین کلاسهای دادهمحور و تابعی
کلاس های داده محور | کلاس های تابعی | |
تمرکز | بر داده ها و ویژگی ها | بر عملکرد و متدها |
ویژگی | ویژگی ها برای ذخیره سازی داده ها | ویژگی ها برای انجام پردازش خاص |
هدف | ذخیره و نگهداری و اطلاعات | پردازش و انجام و عملیات بر روی داده ها |
پیچیدگی | معمولا ساده و مستقیم | ممکن است پیچیده تر و با منطق بیشتر باشد |
استفاده | زمانی که نیاز به ذخیره سازی داده ها داریم | زمانی که به انجام عملیات و پردازش نیاز داریم |
3. ترکیب کلاسهای دادهمحور و تابعی
در بسیاری از پروژهها، شما ممکن است به ترکیبی از هر دو سبک نیاز داشته باشید. بهعنوانمثال، ممکن است کلاس شما دادههایی را ذخیره کند، اما در عین حال متدهایی نیز داشته باشد که روی این دادهها پردازشهایی انجام دهد.
مثال ترکیبی:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
else:
print("Invalid deposit amount")
def withdraw(self, amount):
if amount > 0 and amount <= self.__balance:
self.__balance -= amount
else:
print("Invalid withdrawal amount")
def get_balance(self):
return self.__balance
def display_account_info(self):
print(f"Account owner: {self.owner}")
print(f"Account balance: {self.get_balance()}")
# ایجاد شیء از کلاس
account = BankAccount("John", 500)
# استفاده از متدها برای انجام عملیات
account.deposit(300)
account.withdraw(200)
account.display_account_info() # نمایش اطلاعات حساب
در این مثال، کلاس BankAccount ترکیبی از دادهمحور و تابعی است. ویژگیها (مثل owner و __balanc) برای ذخیرهسازی دادهها استفاده میشوند، ولی متدهایی مثل deposit(), withdraw(), و display_account_info() برای پردازش و نمایش اطلاعات حساب کاربری ایجاد شدهاند.
کلاسهای دادهمحور و تابعی دو سبک مختلف از طراحی کلاسها هستند که هرکدام کاربردهای خاص خود را دارند. کلاسهای دادهمحور بیشتر بر ذخیرهسازی و انتقال دادهها تمرکز دارند، در حالی که کلاسهای تابعی بیشتر برای پردازش دادهها و انجام عملیات طراحی میشوند. در بسیاری از پروژهها، ممکن است نیاز باشد از ترکیب این دو سبک استفاده کنید تا بتوانید بهترین نتیجه را از کد خود بگیرید.
استفاده از کلاسها در پروژههای واقعی
در پروژههای واقعی برنامهنویسی، کلاسها یکی از مهمترین ابزارها برای سازماندهی کد و مدیریت پیچیدگیها هستند. استفاده از کلاسها نه تنها به کد شما ساختار میدهد، بلکه بهراحتی میتوانید ویژگیها و رفتارهای مختلف را مدیریت کنید. در این بخش، بهطور ساده و با استفاده از مثالهای کاربردی، نشان میدهیم که چگونه میتوانید از کلاسها در پروژههای واقعی استفاده کنید.
1. مدیریت دادهها و ویژگیها در پروژههای واقعی
یکی از کاربردهای اصلی کلاسها در پروژههای واقعی، ذخیره و مدیریت دادهها است. در یک سیستم نرمافزاری معمولی، شما نیاز دارید تا اطلاعاتی مانند کاربران، محصولات، یا سفارشها را مدیریت کنید. استفاده از کلاسها میتواند این دادهها را بهصورت منظم و قابل دسترسی نگهدارد.
مثال: سیستم مدیریت کاربران
فرض کنید میخواهید سیستمی بسازید که کاربران را مدیریت کند. هر کاربر دارای ویژگیهایی مانند نام، ایمیل و تاریخ عضویت است. شما میتوانید این اطلاعات را در یک کلاس User ذخیره کنید.
class User:
def __init__(self, name, email, join_date):
self.name = name
self.email = email
self.join_date = join_date
def display_info(self):
print(f"User: {self.name}, Email: {self.email}, Joined: {self.join_date}")
# ایجاد شیء از کلاس User
user1 = User("Ali", "ali@example.com", "2024-01-01")
user1.display_info() # خروجی: User: Ali, Email: ali@example.com, Joined: 2024-01-01
در این مثال، اطلاعات هر کاربر در شیء `user1` ذخیره شده است و میتوانید بهراحتی اطلاعات آن را با استفاده از متد `display_info()` مشاهده کنید.
2. استفاده از کلاسها برای سازماندهی و مدیریت منطق برنامه
کلاسها فقط برای ذخیرهسازی دادهها نیستند. شما میتوانید منطق و رفتارهای خاصی را نیز در کلاسها قرار دهید. این به شما کمک میکند تا کد خود را تمیزتر و قابل مدیریتتر نگهدارید.
مثال: سیستم خرید آنلاین
فرض کنید میخواهید یک سیستم خرید آنلاین بسازید. هر محصول دارای قیمت و موجودی است، و وقتی یک مشتری محصولی را خریداری میکند، موجودی کاهش مییابد. برای انجام این کار، میتوانید از کلاسها استفاده کنید.
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
def buy(self, quantity):
if self.stock >= quantity:
self.stock -= quantity
print(f"Successfully bought {quantity} {self.name}(s).")
else:
print("Not enough stock.")
def display_info(self):
print(f"Product: {self.name}, Price: {self.price}, Stock: {self.stock}")
# ایجاد شیء از کلاس Product
product1 = Product("Laptop", 1000, 5)
# نمایش اطلاعات محصول
product1.display_info() # خروجی: Product: Laptop, Price: 1000, Stock: 5
# خرید محصول
product1.buy(3) # خروجی: Successfully bought 3 Laptop(s).
product1.display_info() # خروجی: Product: Laptop, Price: 1000, Stock: 2
در این مثال، از کلاس Product برای مدیریت ویژگیهای یک محصول استفاده شده است. متد `buy` بهطور خودکار موجودی محصول را بررسی کرده و آن را پس از خرید کاهش میدهد.
3. استفاده از ارثبری در پروژههای بزرگتر
در پروژههای واقعی، معمولاً نیاز دارید که کلاسها از هم ارثبری کنند تا کد شما تکراری نشود و قابلیت گسترش آسانتر شود. ارثبری یکی از ویژگیهای قدرتمند شیگرایی است که به شما این امکان را میدهد که از ویژگیها و متدهای یک کلاس پایه در کلاسهای فرزند استفاده کنید.
مثال: سیستم پردازش پرداخت
فرض کنید یک سیستم پردازش پرداخت دارید که شامل چند نوع پرداخت مختلف مانند پرداخت کارت اعتباری و پرداخت از طریق کیف پول است. شما میتوانید یک کلاس پایه به نام `Payment` داشته باشید و کلاسهای فرزند برای انواع مختلف پرداخت ایجاد کنید.
class Payment:
def __init__(self, amount):
self.amount = amount
def process_payment(self):
pass # متد پایه برای پردازش پرداخت
class CreditCardPayment(Payment):
def __init__(self, amount, card_number):
super().__init__(amount)
self.card_number = card_number
def process_payment(self):
print(f"Processing credit card payment of {self.amount} using card {self.card_number}")
class WalletPayment(Payment):
def __init__(self, amount, wallet_id):
super().__init__(amount)
self.wallet_id = wallet_id
def process_payment(self):
print(f"Processing wallet payment of {self.amount} using wallet {self.wallet_id}")
# ایجاد شیء از کلاسهای فرزند
credit_payment = CreditCardPayment(100, "1234-5678-9876")
wallet_payment = WalletPayment(50, "user_wallet_123")
# پردازش پرداختها
credit_payment.process_payment() # خروجی: Processing credit card payment of 100 using card 1234-5678-9876
wallet_payment.process_payment() # خروجی: Processing wallet payment of 50 using wallet user_wallet_123
در این مثال، کلاس Payment یک کلاس پایه است و دو کلاس فرزند CreditCardPayment و WalletPayment آن را گسترش میدهند. هر کدام از این کلاسها منطق خاص خود را برای پردازش پرداخت دارند.
4. استفاده از کلاسها برای تعامل با پایگاه داده
در پروژههای واقعی، معمولاً نیاز دارید که با پایگاه دادهها کار کنید. کلاسها میتوانند به شما کمک کنند تا این ارتباط را بهصورت منظم و مقیاسپذیر پیادهسازی کنید.
مثال: مدل کاربر در پایگاه داده
در این مثال، از کلاسها برای مدیریت اطلاعات کاربران و ذخیره آنها در پایگاه داده استفاده میکنیم.
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def save_to_database(self):
# اینجا میتوانید کد ذخیرهسازی دادهها در پایگاه داده را بنویسید
print(f"Saving {self.name} with email {self.email} to the database.")
# ایجاد شیء از کلاس User
user1 = User("Ali", "ali@example.com")
user1.save_to_database() # خروجی: Saving Ali with email ali@example.com to the database.
در اینجا، متد save_to_database یک کلاس ساده برای ذخیره اطلاعات کاربر در پایگاه داده است. در دنیای واقعی، این متد میتواند به پایگاه داده متصل شده و دادهها را ذخیره کند.
استفاده از کلاسها در پروژههای واقعی میتواند کد شما را تمیزتر، مقیاسپذیرتر و قابل نگهداریتر کند. با استفاده از کلاسها، میتوانید دادهها و منطق برنامهتان را بهخوبی سازماندهی کنید و از قابلیتهای پیشرفته شیگرایی مانند ارثبری و کپسولهسازی بهرهبرداری کنید. این ویژگیها به شما کمک میکنند تا کد خود را بهتر مدیریت کنید و در پروژههای بزرگتر به راحتی به گسترش و بهبود سیستم بپردازید.
نکات پیشرفته و بهترین شیوهها برای طراحی کلاسها
در طراحی کلاسها در پایتون، علاوه بر رعایت اصول پایهای، باید به برخی نکات پیشرفته و بهترین شیوهها توجه کنید تا کد شما تمیزتر، مقیاسپذیرتر و راحتتر قابل نگهداری باشد. در این بخش، به بررسی این نکات و شیوهها خواهیم پرداخت و با مثالهایی ساده و کاربردی، این مفاهیم را توضیح خواهیم داد.
1. استفاده از متدهای خاص برای مدیریت منابع (مثل __enter__ و __exit__)
در پایتون، برای مدیریت منابع مانند فایلها یا اتصالهای شبکه، میتوان از مفهوم مدیریت منابع استفاده کرد. این کار معمولاً با استفاده از متدهای ویژه __enter__ و __exit__ انجام میشود. این متدها به شما اجازه میدهند که منابع را بهصورت خودکار مدیریت کنید و در صورت بروز خطا، آنها را بهدرستی آزاد کنید.
مثال: مدیریت فایل
فرض کنید میخواهید فایلی را باز کرده و محتویات آن را پردازش کنید. با استفاده از متدهای __enter__ و __exit__ میتوانید اطمینان حاصل کنید که فایل پس از استفاده بسته میشود.
class FileHandler:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'r')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
# استفاده از کلاس با دستور with
with FileHandler('example.txt') as file:
content = file.read()
print(content)
در اینجا، کلاس FileHandler از متدهای ویژه __enter__ و __exit__ برای باز و بسته کردن فایل استفاده میکند. با استفاده از دستور with، پایتون بهطور خودکار منابع را مدیریت میکند.
2. جلوگیری از تکرار کد با استفاده از وراثت و ترکیب کلاسها
یکی از اصول مهم در طراحی کلاسها، عدم تکرار کد است. این کار را میتوانید با استفاده از وراثت (ارثبری) انجام دهید. اگر دو یا چند کلاس رفتارهای مشابهی دارند، میتوانید این رفتارها را در یک کلاس پایه قرار داده و در کلاسهای فرزند از آنها استفاده کنید.
مثال: سیستم حیوانات
فرض کنید میخواهید یک سیستم برای مدیریت حیوانات ایجاد کنید. میتوانید از یک کلاس پایه به نام `Animal` استفاده کنید و ویژگیهای مشترک میان حیوانات مانند صدا دادن و حرکت کردن را در آن قرار دهید.
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
pass
def move(self):
print(f"{self.name} is moving.")
class Dog(Animal):
def make_sound(self):
print(f"{self.name} says Woof!")
class Cat(Animal):
def make_sound(self):
print(f"{self.name} says Meow!")
# استفاده از کلاسها
dog = Dog("Buddy")
cat = Cat("Whiskers")
dog.make_sound() # خروجی: Buddy says Woof!
dog.move() # خروجی: Buddy is moving.
cat.make_sound() # خروجی: Whiskers says Meow!
cat.move() # خروجی: Whiskers is moving.
در این مثال، کلاس Animal ویژگیها و متدهای مشترک را تعریف میکند، و کلاسهای Dog و Cat رفتارهای خاص خود را در متد make_sound پیادهسازی میکنند.
3. استفاده از کلاسهای خصوصی برای جلوگیری از دسترسی مستقیم
برای جلوگیری از دسترسی غیرمجاز به دادهها، میتوانید از کلاسهای خصوصی استفاده کنید. این کار با قرار دادن ویژگیها و متدها در حالت خصوصی (با پیشوند __) انجام میشود. البته در پایتون، این ویژگیها بهطور کامل مخفی نمیشوند، ولی تلاش برای دسترسی به آنها را دشوارتر میکنند.
مثال: کلاس با ویژگیهای خصوصی
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # ویژگی خصوصی
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited {amount}. New balance: {self.__balance}")
def withdraw(self, amount):
if amount > self.__balance:
print("Insufficient funds!")
else:
self.__balance -= amount
print(f"Withdrew {amount}. New balance: {self.__balance}")
def get_balance(self):
return self.__balance
# ایجاد شیء از کلاس BankAccount
account = BankAccount("Ali", 1000)
account.deposit(500) # خروجی: Deposited 500. New balance: 1500
account.withdraw(200) # خروجی: Withdrew 200. New balance: 1300
# دسترسی به ویژگی خصوصی به صورت مستقیم منجر به خطا میشود
# print(account.__balance) # خطا: AttributeError
در اینجا، ویژگی __balance خصوصی است و نمیتوان به آن دسترسی مستقیم داشت. برای دسترسی به این ویژگی از متد get_balance استفاده میشود.
4. استفاده از کلاسهای ترکیبی و اجزای قابل استفاده مجدد
یکی از بهترین شیوهها در طراحی کلاسها، استفاده از ترکیب به جای ارثبری است. در ترکیب، شما میتوانید کلاسهای مختلف را بهصورت مستقل از هم پیادهسازی کنید و سپس آنها را در کلاسهای دیگر ترکیب کنید. این روش کد شما را انعطافپذیرتر و قابل گسترشتر میکند.
مثال: ترکیب کلاسها
class Engine:
def start(self):
print("Engine started.")
class Car:
def __init__(self):
self.engine = Engine()
def drive(self):
self.engine.start()
print("Car is moving.")
# ایجاد شیء از کلاس Car
car = Car()
car.drive() # خروجی: Engine started. Car is moving.
در این مثال، کلاس Car از کلاس Engine استفاده میکند، بدون اینکه از آن ارثبری کند. این روش به شما این امکان را میدهد که کلاسها را بهصورت جداگانه پیادهسازی کنید و در صورت نیاز آنها را ترکیب کنید.
5. نوشتن مستندات دقیق و استفاده از docstrings
برای آنکه کلاسها و متدهای شما برای دیگران (و حتی خودتان) قابل درک باشد، باید از مستندات (docstrings) استفاده کنید. این مستندات باید توضیح دهند که هر کلاس و متد چه کاری انجام میدهند، ورودیها و خروجیها چیست و چه محدودیتهایی دارند.
مثال: مستندات دقیق
class Calculator:
def add(self, a, b):
"""
Adds two numbers.
:param a: The first number.
:param b: The second number.
:return: The sum of a and b.
"""
return a + b
def subtract(self, a, b):
"""
Subtracts the second number from the first.
:param a: The first number.
:param b: The second number.
:return: The result of a - b.
"""
return a - b
در اینجا، از docstring برای مستندسازی متدهای add و subtract استفاده شده است. این مستندات توضیح میدهند که هر متد چه کاری انجام میدهد و چه پارامترهایی را میپذیرد.
در طراحی کلاسها در پایتون، رعایت بهترین شیوهها و نکات پیشرفته میتواند کد شما را تمیزتر، مقیاسپذیرتر و قابل نگهداریتر کند. با استفاده از مفاهیمی مانند مدیریت منابع، ترکیب کلاسها، کپسولهسازی، و مستندات دقیق، میتوانید پروژههای پیچیده را با طراحی کلاسهای بهینه و قابل فهم مدیریت کنید.
چگونه کلاسها میتوانند به افزایش بازدهی کد کمک کنند
کلاسها در پایتون یکی از ابزارهای قدرتمند برای سازماندهی کد و افزایش بازدهی آن هستند. با استفاده از کلاسها میتوانید کدهای خود را ساختارمندتر، مقیاسپذیرتر و قابل نگهداریتر کنید. در این بخش، خواهیم دید که چگونه استفاده از کلاسها میتواند به بهبود عملکرد و بازدهی کد کمک کند.
1. تقسیمبندی و سازماندهی کد
یکی از بزرگترین مزایای استفاده از کلاسها، امکان **تقسیمبندی و سازماندهی کد** است. بهجای نوشتن کدهای تودرتو و پیچیده، میتوانید عملکردهای مختلف برنامه را در کلاسهای مختلف جای دهید. این امر باعث میشود که کد شما تمیزتر، خواناتر و درک آن راحتتر شود.
مثال: مدیریت موجودی فروشگاه
فرض کنید میخواهید یک سیستم مدیریت موجودی برای یک فروشگاه طراحی کنید. بهجای نوشتن کدهای طولانی و پیچیده، میتوانید از کلاسها برای مدیریت بخشهای مختلف این سیستم استفاده کنید.
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
def update_stock(self, quantity):
self.stock += quantity
print(f"Updated stock for {self.name}: {self.stock} items.")
class Store:
def __init__(self):
self.products = []
def add_product(self, product):
self.products.append(product)
def list_products(self):
for product in self.products:
print(f"{product.name} - {product.price}$ - Stock: {product.stock}")
در اینجا، کلاس Product برای مدیریت محصولات و کلاس Store برای مدیریت فروشگاه استفاده شده است. با استفاده از کلاسها، بخشهای مختلف سیستم بهصورت جداگانه و واضح پیادهسازی شدهاند.
2. بازاستفاده و گسترشپذیری کد
کلاسها به شما این امکان را میدهند که کد را بازاستفاده کنید. وقتی یک کلاس را میسازید، میتوانید از آن در بخشهای مختلف برنامه یا حتی در پروژههای دیگر استفاده کنید. علاوه بر این، با استفاده از مفاهیم شیگرایی مانند وراثت، میتوانید کلاسها را گسترش دهید و ویژگیها یا رفتارهای جدید به آنها اضافه کنید بدون اینکه کدهای قبلی را تغییر دهید.
مثال: وراثت در سیستم فروشگاه
فرض کنید در سیستم مدیریت فروشگاه نیاز دارید تا نوع خاصی از محصول مثل کتابها را مدیریت کنید. میتوانید یک کلاس جدید از کلاس `Product` بسازید که ویژگیهای خاص کتابها را داشته باشد.
class Book(Product):
def __init__(self, name, price, stock, author):
super().__init__(name, price, stock)
self.author = author
def display_info(self):
print(f"Book: {self.name} by {self.author} - {self.price}$")
با این روش، شما کد پایهای Product را بازاستفاده کرده و ویژگیهای جدیدی به کلاس Book اضافه کردهاید.
3. کاهش پیچیدگی و افزایش خوانایی
کلاسها به شما این امکان را میدهند که پیچیدگی کد را کاهش دهید. بهجای نوشتن توابع و متغیرهای متعددی که وظایف مختلف را انجام میدهند، میتوانید تمام ویژگیها و رفتارهای مرتبط را در یک کلاس سازماندهی کنید. این کار باعث میشود که کد شما خواناتر و فهم آن سادهتر باشد.
مثال: مدیریت سفارشات
در یک سیستم مدیریت سفارشات، بهجای داشتن توابع مختلف برای مدیریت اطلاعات مشتری و سفارش، میتوانید یک کلاس Order بسازید که تمام ویژگیها و متدهای مرتبط با یک سفارش را در خود جای دهد.
class Order:
def __init__(self, order_id, customer_name, items):
self.order_id = order_id
self.customer_name = customer_name
self.items = items
self.status = "Pending"
def add_item(self, item):
self.items.append(item)
def remove_item(self, item):
self.items.remove(item)
def calculate_total(self):
return sum(item['price'] for item in self.items)
def complete_order(self):
self.status = "Completed"
print(f"Order {self.order_id} has been completed.")
در این مثال، تمامی ویژگیها و متدهای مرتبط با یک سفارش در کلاس `Order` جمعآوری شده است، که باعث کاهش پیچیدگی کد و افزایش خوانایی آن میشود.
4. افزایش کارایی با استفاده از متدهای خاص
کلاسها میتوانند متدهای خاصی داشته باشند که به بهبود عملکرد و کارایی کد کمک کنند. بهعنوان مثال، متدهای ویژه مانند __str__ یا __repr__ میتوانند به شما در نمایش مناسب اشیاء کمک کنند و از آنها در کدهای دیگر استفاده کنید.
مثال: استفاده از __str__ برای نمایش اطلاعات کلاس
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
def __str__(self):
return f"Product: {self.name}, Price: {self.price}$, Stock: {self.stock}"
product = Product("Laptop", 1000, 5)
print(product) # خروجی: Product: Laptop, Price: 1000$, Stock: 5
در اینجا، با استفاده از متد __str__ میتوانید نمایش دلخواه از شیء Product ایجاد کنید. این کار میتواند در هنگام نمایش اطلاعات به کاربر یا ثبت گزارشها مفید باشد.
5. افزایش قابلیت نگهداری و گسترش پروژه
کلاسها باعث میشوند که پروژههای شما بهراحتی قابل نگهداری و گسترش باشند. بهعنوان مثال، اگر در آینده نیاز به اضافه کردن ویژگیها یا قابلیتهای جدید به سیستم خود دارید، با استفاده از کلاسها میتوانید تغییرات را بهصورت جداگانه اعمال کنید بدون اینکه بخشهای دیگر کد تحت تأثیر قرار گیرند.
مثال: گسترش سیستم مدیریت موجودی
اگر بعداً نیاز به اضافه کردن قابلیتهای جدید مانند تخفیفها یا سیستم پرداخت آنلاین داشته باشید، میتوانید بهراحتی کدهای جدید را به کلاسهای موجود اضافه کنید.
class Discount:
def apply_discount(self, price, discount_rate):
return price * (1 - discount_rate)
class Store:
def __init__(self):
self.products = []
def add_product(self, product):
self.products.append(product)
def apply_discount_to_all(self, discount_rate):
discount = Discount()
for product in self.products:
product.price = discount.apply_discount(product.price, discount_rate)
در اینجا، کلاس جدید Discount به سیستم اضافه شده است بدون اینکه تغییری در کلاس Product یا Store اعمال شود.
استفاده از کلاسها میتواند به افزایش بازدهی کد کمک کند از طریق سازماندهی بهتر، بازاستفاده از کد، کاهش پیچیدگی، و قابلیت گسترش پروژه. کلاسها به شما این امکان را میدهند که کدهای تمیزتر، مقیاسپذیرتر و قابل نگهداریتر بنویسید که در پروژههای بزرگ و پیچیده بسیار مفید خواهد بود.
تمرین های مبتدی
1. یک کلاس به نام Car بسازید که ویژگیهای brand, model, year و color را داشته باشد. سپس یک شیء از این کلاس بسازید و ویژگیهای آن را نمایش دهید.
2. یک کلاس به نام Rectangle بسازید که ویژگیهای length و width را داشته باشد. یک متد در کلاس اضافه کنید که مساحت مستطیل را محاسبه کند.
3. یک کلاس به نام Person بسازید که ویژگیهای name و age را داشته باشد. یک متد در کلاس اضافه کنید که اطلاعات شخص را چاپ کند.
4. یک کلاس به نام BankAccount بسازید که ویژگیهای account_holder و balance را داشته باشد. متدهایی برای واریز و برداشت پول به حساب اضافه کنید.
5. یک کلاس به نام Student بسازید که ویژگیهای name, age, و grades (یک لیست از نمرات) را داشته باشد. متدی بنویسید که میانگین نمرات دانشآموز را محاسبه کند.
6. یک کلاس به نام Circle بسازید که ویژگیهای radius را داشته باشد. یک متد بنویسید که محیط دایره را محاسبه کند.
7. یک کلاس به نام Book بسازید که ویژگیهای title, author, و price را داشته باشد. متدی بنویسید که اطلاعات کتاب را نمایش دهد.
8. یک کلاس به نام Employee بسازید که ویژگیهای name, salary, و position را داشته باشد. متدی بنویسید که افزایش حقوق برای یک کارمند بهصورت درصدی انجام دهد.
9. یک کلاس به نام Movie بسازید که ویژگیهای title, director, year, و rating را داشته باشد. متدی بنویسید که فیلم را بر اساس امتیاز نمایش دهد.
10. یک کلاس به نام Temperature بسازید که ویژگیهای celsius را داشته باشد. متدی بنویسید که دما را به فارنهایت تبدیل کند.
تمرین های متوسط
1. یک کلاس به نام Shape بسازید که یک متد به نام area() داشته باشد. سپس کلاسهای Rectangle و Circle را از آن ارثبری کنید و متد area() را برای هرکدام پیادهسازی کنید.
2. یک کلاس به نام Person بسازید که ویژگیهای name, age, و address را داشته باشد. از آن یک کلاس ارثبری کنید به نام Employee که ویژگی salary را به آن اضافه کند و متدی بنویسید که حقوق کارمند را افزایش دهد.
3. یک کلاس به نام Account بسازید که ویژگیهای account_number و balance را داشته باشد. سپس متدی اضافه کنید که مقدار موجودی حساب را پس از واریز و برداشت بهروزرسانی کند و از روشهای get و set برای دسترسی به موجودی استفاده کنید.
4. یک کلاس به نام Product بسازید که ویژگیهای name, price, و quantity را داشته باشد. سپس متدی بنویسید که تخفیف مشخصی را به قیمت محصول اعمال کند و قیمت جدید را بازگرداند.
5. یک کلاس به نام Student بسازید که ویژگیهای name, age, و subjects (یک دیکشنری شامل نام درسها و نمرات) را داشته باشد. سپس متدی بنویسید که میانگین نمرات دانشآموز را محاسبه کند.
6. یک کلاس به نام Date بسازید که ویژگیهای day, month, و year را داشته باشد. یک متد اضافه کنید که تاریخ را در فرمت "DD/MM/YYYY" نمایش دهد و متدی بنویسید که تاریخ بعدی را محاسبه کند.
7. یک کلاس به نام Movie بسازید که ویژگیهای title, director, year, و rating را داشته باشد. یک متد بنویسید که فیلم را بهصورت خودکار از روی امتیاز مرتب کند.
8. یک کلاس به نام Ticket بسازید که ویژگیهای event_name, price, و seat_number را داشته باشد. سپس متدی اضافه کنید که با توجه به تعداد خریدهای بلیت، قیمت کل را محاسبه کند.
9. یک کلاس به نام BankAccount بسازید که ویژگیهای account_holder و balance را داشته باشد. متدهایی برای واریز و برداشت پول بنویسید که از بررسیهای شرطی برای جلوگیری از موجودی منفی استفاده کنند
10. یک کلاس به نام Product بسازید که ویژگیهای name, price, و category را داشته باشد. سپس متدی بنویسید که محصولات مشابه را در یک دستهبندی خاص مرتب کند و فقط محصولات ارزانتر از یک مقدار مشخص را نمایش دهد.
تمرین های پیشرفته
1. یک سیستم مدیریت دانشآموزی بسازید که کلاسهای Student, Course, و Instructor را داشته باشد. هر کلاس باید ویژگیهای مناسب را داشته باشد و متدهایی برای اضافه کردن دانشآموزان به دروس، ثبت نمرات و محاسبه میانگین نمرات وجود داشته باشد.
2. یک سیستم بانکداری بسازید که شامل کلاسهای Account, Transaction, و Bank باشد. Account باید ویژگیهایی مانند موجودی و تاریخ تراکنشها داشته باشد و Transaction جزئیات تراکنشها را نگهداری کند. Bank باید متدی برای مشاهده تراکنشها و محاسبه موجودی کل سیستم داشته باشد.
3. یک بازی شطرنج مدلسازی کنید که شامل کلاسهایی مانند Piece, Board, Player باشد. کلاس Piece باید ویژگیهایی مانند موقعیت و نوع مهره (پادشاه، وزیر، اسب و غیره) داشته باشد. Board باید امکان چک کردن وضعیت مهرهها و حرکتهای مجاز را فراهم کند.
4. یک کلاس MetaClass ایجاد کنید که به شما این امکان را بدهد که کلاسهای جدید را بهصورت داینامیک بسازید. از آن برای ایجاد کلاسهایی مانند Person و Employee استفاده کنید که ویژگیها و متدهای خود را از آن متغیر دریافت کنند.
5. یک سیستم فایل (File System) ایجاد کنید که شامل کلاسهایی مانند File, Directory, و FileSystem باشد. کلاس File باید ویژگیهایی مانند نام، اندازه، و تاریخ ایجاد داشته باشد. Directory باید امکان اضافه کردن و حذف فایلها را فراهم کند.
6. یک سیستم مدیریت پروژه بسازید که شامل کلاسهای Project, Task, User, و Comment باشد. هر پروژه باید ویژگیهایی مانند نام پروژه، تاریخ شروع و پایان، و کاربرهای مشارکتکننده داشته باشد. Task باید امکان مدیریت وضعیت کارها (مانند در حال انجام، تکمیل شده) را فراهم کند.
7. یک سیستم اعتبارسنجی ورودی بسازید که شامل کلاسهایی مانند Field, Validator, و Form باشد. هر Field باید ویژگیهایی مانند نوع داده (تعداد، رشته، تاریخ و غیره) و مقدار داشته باشد. Validator باید از ویژگیهای مختلف مانند is_required(), is_valid_email() و غیره استفاده کند تا مقادیر را اعتبارسنجی کند.
8. یک سیستم کشف الگو بسازید که شامل کلاسهایی مانند Pattern, Matcher, و Scanner باشد. Pattern باید ویژگیهایی مانند نوع و ساختار الگو را داشته باشد. Matcher باید قابلیت تطبیق الگوها با رشتهها را فراهم کند و Scanner باید متدی برای جستجو در متون با استفاده از الگوها داشته باشد.
9. یک سیستم ایمیل ارسال کن که شامل کلاسهای Email, Attachment, و MailServer باشد. Email باید ویژگیهایی مانند گیرنده، موضوع، و محتوای پیام را داشته باشد. Attachment باید قابلیت پیوست کردن فایلها را فراهم کند و MailServer باید متدی برای ارسال ایمیلها داشته باشد.
10. یک سیستم فروشگاه آنلاین با استفاده از اصول Design Pattern بسازید. از الگوهای مختلف مانند `Singleton` برای مدیریت موجودی، Factory Method برای ساخت محصولات و Observer برای اطلاعرسانی به کاربران استفاده کنید.
11. یک سیستم تجارت الکترونیک بسازید که شامل کلاسهایی مانند Customer, Product, Cart, Discount, و Order باشد. ویژگیهای مختلفی مانند تعداد محصول، وضعیت تخفیف و روشهای پرداخت را مدیریت کرده و یک متد برای محاسبه مجموع نهایی سفارش با تخفیفها بنویسید.