[TIPS] Refactoring - Clean Code - Tip 7 - Encapsulate Data and Behavior in Classes

By JoeVu, at: 09:45 Ngày 15 tháng 8 năm 2024

Thời gian đọc ước tính: 5 min read

[TIPS] Refactoring - Clean Code - Tip 7 - Encapsulate Data and Behavior in Classes
[TIPS] Refactoring - Clean Code - Tip 7 - Encapsulate Data and Behavior in Classes

Refactoring Tip 7: Encapsulate Data and Behavior in Classes

  • Junior: Might use procedural programming without leveraging classes.

  • Senior: Uses classes to encapsulate related data and behavior, following principles of Object-Oriented Programming (OOP).


Encapsulating data and behavior in classes is crucial for writing organized and maintainable code. Here's an example to illustrate the difference between how a junior and a senior developer might approach this principle.

 

Example 1: Handling User Data


Junior Developer's Approach

A junior developer might use procedural programming to handle user data:

users = []

def add_user(name, age):
    users.append({'name': name, 'age': age})

def get_user(name):
    for user in users:
        if user['name'] == name:
            return user
    return None

def update_user(name, age):
    for user in users:
        if user['name'] == name:
            user['age'] = age

# Usage
add_user('Alice', 30)
add_user('Bob', 25)
print(get_user('Alice'))
update_user('Alice', 31)
print(get_user('Alice'))

 

Senior Developer's Approach

A senior developer would use classes to encapsulate user data and behavior:

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def update_age(self, age):
        self.age = age


class UserManager:
    def __init__(self):
        self.users = []

    def add_user(self, name, age):
        self.users.append(User(name, age))

    def get_user(self, name):
        for user in self.users:
            if user.name == name:
                return user
        return None

    def update_user(self, name, age):
        user = self.get_user(name)
        if user:
            user.update_age(age)

# Usage
user_manager = UserManager()
user_manager.add_user('Alice', 30)
user_manager.add_user('Bob', 25)
print(vars(user_manager.get_user('Alice')))
user_manager.update_user('Alice', 31)
print(vars(user_manager.get_user('Alice')))

 

Example 2: Managing a Library System


Junior Developer's Approach

A junior developer might use procedural programming to manage a library system:

books = []

def add_book(title, author):
    books.append({'title': title, 'author': author})

def get_book(title):
    for book in books:
        if book['title'] == title:
            return book
    return None

def remove_book(title):
    global books
    books = [book for book in books if book['title'] != title]

# Usage
add_book('1984', 'George Orwell')
add_book('To Kill a Mockingbird', 'Harper Lee')
print(get_book('1984'))
remove_book('1984')
print(get_book('1984'))


Senior Developer's Approach

A senior developer would use classes to encapsulate book data and library management behavior:

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

class Library:
    def __init__(self):
        self.books = []

    def add_book(self, title, author):
        self.books.append(Book(title, author))

    def get_book(self, title):
        for book in self.books:
            if book.title == title:
                return book
        return None

    def remove_book(self, title):
        self.books = [book for book in self.books if book.title != title]

# Usage
library = Library()
library.add_book('1984', 'George Orwell')
library.add_book('To Kill a Mockingbird', 'Harper Lee')
print(vars(library.get_book('1984')))
library.remove_book('1984')
print(library.get_book('1984'))

 

Example 3: Processing Orders


Junior Developer's Approach

A junior developer might use procedural programming to process orders:

orders = []

def add_order(order_id, amount):
    orders.append({'order_id': order_id, 'amount': amount})

def get_order(order_id):
    for order in orders:
        if order['order_id'] == order_id:
            return order
    return None

def update_order(order_id, amount):
    for order in orders:
        if order['order_id'] == order_id:
            order['amount'] = amount

# Usage
add_order(1, 100)
add_order(2, 150)
print(get_order(1))
update_order(1, 120)
print(get_order(1))

 

Senior Developer's Approach

A senior developer would use classes to encapsulate order data and processing behavior:

class Order:
    def __init__(self, order_id, amount):
        self.order_id = order_id
        self.amount = amount

    def update_amount(self, amount):
        self.amount = amount

class OrderManager:
    def __init__(self):
        self.orders = []

    def add_order(self, order_id, amount):
        self.orders.append(Order(order_id, amount))

    def get_order(self, order_id):
        for order in self.orders:
            if order.order_id == order_id:
                return order
        return None

    def update_order(self, order_id, amount):
        order = self.get_order(order_id)
        if order:
            order.update_amount(amount)

# Usage
order_manager = OrderManager()
order_manager.add_order(1, 100)
order_manager.add_order(2, 150)
print(vars(order_manager.get_order(1)))
order_manager.update_order(1, 120)
print(vars(order_manager.get_order(1)))

 

Key Improvements:

  1. Encapsulation: Group related data and behavior into classes, improving organization and maintainability.
     
  2. Modularity: Encapsulate functionality within classes, making the code easier to understand and extend.
     
  3. Object-Oriented Principles: Follow OOP principles to create reusable and scalable code.
     

Encapsulating data and behavior in classes leads to better organization, easier maintenance, and scalability of the codebase. These examples demonstrate how a senior developer's approach to refactoring can lead to more structured and maintainable code.


Theo dõi

Theo dõi bản tin của chúng tôi và không bao giờ bỏ lỡ những tin tức mới nhất.