Logo

dev-resources.site

for different kinds of informations.

Refactoring: Moving Features Between Objects

Published at
11/15/2024
Categories
singleresponsibilityprinciple
refactoring
cleancode
Author
moh_moh701
Author
10 person written this
moh_moh701
open
Refactoring: Moving Features Between Objects

Meta Description :Learn how to organize your code effectively with the 'Moving Features Between Objects' refactoring technique. Discover how to use Move Method/Field and Extract Class to align functionality with the right objects, improve readability, and simplify maintenance with detailed examples in C#.

Refactoring is an essential skill for maintaining clean, understandable, and scalable code. One effective refactoring technique is "Moving Features Between Objects", which helps organize code better by placing functionality where it truly belongs. Let's explore this concept, including practical examples of two common sub-techniques: Move Method/Field and Extract Class.

Why Move Features Between Objects?

In object-oriented programming, each class should encapsulate functionality and data that directly relate to its purpose. However, you might find scenarios where:

  • A method or field is more relevant to another class.
  • A class handles responsibilities that belong to two or more separate entities.

In such cases, it's recommended to move or extract features to maintain single responsibility and improve code clarity.


Technique 1: Move Method/Field

Scenario

A method or field is more often used in another class than its current location.

Solution

Move the method or field to the class where it belongs. This improves code readability and aligns functionality with the right object.

Example: Move Method

Imagine we have two classes: Product and ShoppingCart. Initially, the Product class contains a method AddToCart:

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    public void AddToCart(ShoppingCart cart)
    {
        cart.Items.Add(this);
    }
}

public class ShoppingCart
{
    public List<Product> Items { get; set; } = new List<Product>();
}
Enter fullscreen mode Exit fullscreen mode

Here, the Product class is responsible for adding itself to the cart, which isn't appropriate. Adding products to a cart is a responsibility of ShoppingCart.

Refactored Code

We move the AddToCart method to the ShoppingCart class:

public class ShoppingCart
{
    public List<Product> Items { get; set; } = new List<Product>();

    public void AddToCart(Product product)
    {
        Items.Add(product);
    }
}

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

This refactor makes the code more intuitive: the ShoppingCart manages its items, and the Product class focuses solely on representing a product.


Technique 2: Extract Class

Scenario

A class performs the functionality of two or more classes, violating the Single Responsibility Principle.

Solution

Split the functionality into separate classes, so each class is focused on its specific role.

Example: Extract Class

Let's take a Trail class that manages both trail information and activities:

public class Trail
{
    public string Name { get; set; }
    public string Location { get; set; }

    // Trail activities
    private bool hasHiking;
    private bool hasMountainBiking;
    private bool hasCamping;
    private bool hasFishing;
    // ...more activity fields

    public bool HasHiking => hasHiking;
    public bool HasMountainBiking => hasMountainBiking;
    public bool HasCamping => hasCamping;
    public bool HasFishing => hasFishing;
}
Enter fullscreen mode Exit fullscreen mode

The Trail class is cluttered with fields and properties related to activities. These belong in a separate TrailActivities class.

Refactored Code

We create a new TrailActivities class and move the relevant fields:

public struct TrailActivities
{
    public bool HasHiking { get; set; }
    public bool HasMountainBiking { get; set; }
    public bool HasCamping { get; set; }
    public bool HasFishing { get; set; }
    // Add other activities here
}

public class Trail
{
    public string Name { get; set; }
    public string Location { get; set; }
    public TrailActivities Activities { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Now, Trail is cleaner and focuses on its core responsibility, while TrailActivities encapsulates the details of activities.


When Not to Use These Techniques

  • Move Method/Field: Avoid moving functionality if it's frequently used in multiple classes. Instead, consider introducing a helper or utility class.
  • Extract Class: If the class is small and there's no planned expansion, it may not be worth splitting it.

Key Benefits

  • Improved readability: Each class contains only what it should.
  • Simplified maintenance: Changes to functionality are isolated to relevant classes.
  • Better adherence to principles: Encourages the Single Responsibility Principle and promotes clean architecture.

By refactoring methods and fields or extracting classes where necessary, you can create a codebase that's easier to understand, extend, and maintain. These small adjustments lead to significant long-term improvements in code quality.

refactoring Article's
30 articles in total
Favicon
Python: Refactoring to Patterns
Favicon
STOP Writing Dirty Code: Fix The Data Class Code Smell Now!
Favicon
7 Ways to Refactor Your Flutter Application
Favicon
Những Tip đơn giản giúp đoạn code trở nên CLEAR và MAINTAIN dễ hơn
Favicon
Refactoring 021 - Remove Dead Code
Favicon
React v19, unboxing! 📦
Favicon
De software legacy a oportunitat estratègica: El punt de partida (I)
Favicon
The Backend Testing Breakup 💔
Favicon
Simplifying your code: replacing heavy packages with lightweight solutions
Favicon
The Rewrite Trap: A Programmer's Survival Guide
Favicon
Refactoring: The Art of Polishing Code
Favicon
El verdadero valor del software no siempre está en el presente
Favicon
Refactoring 019 - Reify Email Addresses
Favicon
How LLMs Revolutionize Coding Efficiency
Favicon
Effective Strategies for Refactoring a Large Codebase: Best Practices and Approaches
Favicon
Convert a ReactJS app from Vite to Nx
Favicon
Simplifying Conditional Expressions in C#: Tips for Clean and Readable Code
Favicon
Simplifying Method Calls in C#: Techniques for Cleaner and More Maintainable Code
Favicon
Mastering Clean Code: 4 Essential Techniques for Organizing Data in C#
Favicon
Refactoring: Moving Features Between Objects
Favicon
Composing Methods: A Practical Guide to Clean Code
Favicon
Refactoring 017 - Convert Attributes to Sets
Favicon
Como Refatorar Seu Código Com Muitos If-Else? Part 2
Favicon
Stop Re-Implementing Code: Use Extract Method in Rust
Favicon
De lo funcional hasta lo legible con Tidyings
Favicon
The Double-Edged Sword of IEnumerable and yield return in C#
Favicon
In Theory: Self-Correcting Software - Part 2
Favicon
Make your package.json readable again by humans: organizing npm scripts with shell files
Favicon
Transforming DevEx Through Bulk Refactoring (and How AI Can Assist)
Favicon
Refactoring for Efficiency: Tackling Performance Issues in Data-Heavy Pages

Featured ones: