برنامه نویسی

Refactoring Complex Conditions: Clean Code Solutions for Nested If Statements

Summarize this content to 400 words in Persian Lang
بیاموزید که چگونه عبارات تو در تو را در سی شارپ برای کدهای تمیزتر و قابل نگهداری تر تغییر دهید. برای ساده کردن منطق پیچیده، تکنیک‌های عملی مانند بند نگهبانی، الگوها و استراتژی‌ها را با مثال‌های دقیق کشف کنید.

سناریو: عبارات اگر تودرتو

فرض کنید کد زیر را برای مدیریت منطق دسترسی کاربر دارید. در نگاه اول ساده به نظر می رسد:

if (user != null)
{
if (user.IsActive)
{
if (user.Role == “Admin”)
{
if (user.HasPermission(“View”))
{
Console.WriteLine(“Access granted”);
}
else
{
Console.WriteLine(“Permission denied”);
}
}
else
{
Console.WriteLine(“Role not authorized”);
}
}
else
{
Console.WriteLine(“User is not active”);
}
}
else
{
Console.WriteLine(“User not found”);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چرا Refactor؟

در حالی که این کد کار می کند، مشکلات متعددی با این تودرتو وجود دارد if ساختار:

کاهش خواناییهرچه لانه سازی عمیق تر باشد، درک جریان منطق در یک نگاه دشوارتر می شود. این کار تلاش ذهنی مورد نیاز برای خواندن و درک کد را افزایش می دهد.
افزایش بار شناختیبا چندین لایه از شرایط، توسعه دهندگان باید زمینه هر لایه را پیگیری کنند، و پیگیری و اشکال زدایی منطق را دشوارتر می کند.
قابلیت نگهداری ضعیفاگر نیاز به اصلاح، گسترش یا آزمایش منطق دارید (به عنوان مثال، اضافه کردن یک شرط جدید برای دسترسی)، باید به دقت ساختار تودرتو را پیمایش کنید و خطر خطا را افزایش دهید.
پیچیدگی تستتست‌های واحد برای شرایط عمیق تو در تو می‌تواند دست و پا گیر شود، زیرا هر شرایطی نیاز به تنظیم و تأیید برای سناریوهای متعدد دارد.
نقض اصول کد پاکتو در تو if بلوک‌ها با شیوه‌های کدنویسی تمیز مانند مسئولیت واحد و خروج زودهنگام، که منطق روشن و مختصر را ترویج می کنند.

گزینه های Refactoring

برای پرداختن به این چالش ها، راه های مختلفی برای بازسازی تودرتو وجود دارد if بلوک ها:

بندهای نگهبانیبرای حذف تودرتوهای غیر ضروری و بهبود خوانایی، زودتر از آن خارج شوید.
تغییر عباراتاز عبارات مختصر برای سناریوهای ساده با نتایج متعدد استفاده کنید.
الگوی استراتژیقوانین دسترسی را در استراتژی‌های قابل استفاده مجدد و قابل آزمایش قرار دهید.
الگوی مشخصاتچندین شرایط را در مشخصات واضح و قابل استفاده مجدد ترکیب کنید.
چند شکلیاز اصول شی گرا برای مدیریت پویا منطق خاص کاربر استفاده کنید.

هر یک از این رویکردها مزایای منحصر به فردی را به ارمغان می آورد، از ساده سازی منطق گرفته تا بهبود تست پذیری. بیایید هر گزینه را با مثال های دقیق بررسی کنیم.

1. بازسازی با بندهای نگهبانی

مثال کامل:

public class User
{
public string Name { get; set; }
public bool IsActive { get; set; }
public string Role { get; set; }
public List<string> Permissions { get; set; } = new List<string>();

public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public class Program
{
public static void Main()
{
User user = new User
{
Name = “John Doe”,
IsActive = true,
Role = “Admin”,
Permissions = new List<string> { “View”, “Edit” }
};

CheckAccess(user);
}

public static void CheckAccess(User user)
{
if (user == null)
{
Console.WriteLine(“User not found”);
return;
}

if (!user.IsActive)
{
Console.WriteLine(“User is not active”);
return;
}

if (user.Role != “Admin”)
{
Console.WriteLine(“Role not authorized”);
return;
}

if (!user.HasPermission(“View”))
{
Console.WriteLine(“Permission denied”);
return;
}

Console.WriteLine(“Access granted”);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2. Refactoring با Switch Expression

مثال کامل:

public class User
{
public string Name { get; set; }
public bool IsActive { get; set; }
public string Role { get; set; }
public List<string> Permissions { get; set; } = new List<string>();

public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public class Program
{
public static void Main()
{
User user = new User
{
Name = “John Doe”,
IsActive = true,
Role = “Admin”,
Permissions = new List<string> { “View” }
};

var result = (user != null, user?.IsActive, user?.Role, user?.HasPermission(“View”)) switch
{
(false, _, _, _) => “User not found”,
(true, false, _, _) => “User is not active”,
(true, true, “Admin”, false) => “Permission denied”,
(true, true, “Admin”, true) => “Access granted”,
_ => “Role not authorized”
};

Console.WriteLine(result);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. بازسازی با الگوی استراتژی

مثال کامل:

public class User
{
public string Name { get; set; }
public bool IsActive { get; set; }
public string Role { get; set; }
public List<string> Permissions { get; set; } = new List<string>();

public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public interface IAccessStrategy
{
bool CanAccess(User user);
string Message { get; }
}

public class UserNotFoundStrategy : IAccessStrategy
{
public string Message => “User not found”;
public bool CanAccess(User user) => user == null;
}

public class UserNotActiveStrategy : IAccessStrategy
{
public string Message => “User is not active”;
public bool CanAccess(User user) => user != null && !user.IsActive;
}

public class RoleNotAuthorizedStrategy : IAccessStrategy
{
public string Message => “Role not authorized”;
public bool CanAccess(User user) => user != null && user.IsActive && user.Role != “Admin”;
}

public class PermissionDeniedStrategy : IAccessStrategy
{
public string Message => “Permission denied”;
public bool CanAccess(User user) => user != null && user.IsActive && user.Role == “Admin” && !user.HasPermission(“View”);
}

public class AccessGrantedStrategy : IAccessStrategy
{
public string Message => “Access granted”;
public bool CanAccess(User user) => user != null && user.IsActive && user.Role == “Admin” && user.HasPermission(“View”);
}

public class Program
{
public static void Main()
{
User user = new User
{
Name = “John Doe”,
IsActive = true,
Role = “Admin”,
Permissions = new List<string> { “Edit” }
};

var strategies = new List<IAccessStrategy>
{
new UserNotFoundStrategy(),
new UserNotActiveStrategy(),
new RoleNotAuthorizedStrategy(),
new PermissionDeniedStrategy(),
new AccessGrantedStrategy()
};

var applicableStrategy = strategies.FirstOrDefault(s => s.CanAccess(user));
Console.WriteLine(applicableStrategy?.Message ?? “Unknown error”);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

4. Refactoring با الگوی مشخصات

مثال کامل:

public class User
{
public string Name { get; set; }
public bool IsActive { get; set; }
public string Role { get; set; }
public List<string> Permissions { get; set; } = new List<string>();

public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public interface ISpecification<T>
{
bool IsSatisfiedBy(T entity);
}

public class IsUserActiveSpecification : ISpecification<User>
{
public bool IsSatisfiedBy(User user) => user != null && user.IsActive;
}

public class IsAdminSpecification : ISpecification<User>
{
public bool IsSatisfiedBy(User user) => user != null && user.Role == “Admin”;
}

public class HasPermissionSpecification : ISpecification<User>
{
private readonly string _permission;
public HasPermissionSpecification(string permission) => _permission = permission;

public bool IsSatisfiedBy(User user) => user != null && user.HasPermission(_permission);
}

public class AccessSpecification : ISpecification<User>
{
public bool IsSatisfiedBy(User user) =>
new IsUserActiveSpecification().IsSatisfiedBy(user) &&
new IsAdminSpecification().IsSatisfiedBy(user) &&
new HasPermissionSpecification(“View”).IsSatisfiedBy(user);
}

public class Program
{
public static void Main()
{
User user = new User
{
Name = “John Doe”,
IsActive = true,
Role = “Admin”,
Permissions = new List<string> { “View”, “Edit” }
};

var accessSpec = new AccessSpecification();

if (accessSpec.IsSatisfiedBy(user))
Console.WriteLine(“Access granted”);
else
Console.WriteLine(“Access denied”);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

5. بازسازی با پلی مورفیسم

مثال کامل:

public abstract class User
{
public abstract bool CanAccess();
public abstract string Message { get; }
}

public class GuestUser : User
{
public override bool CanAccess() => false;
public override string Message => “User not found”;
}

public class InactiveUser : User
{
public override bool CanAccess() => false;
public override string Message => “User is not active”;
}

public class AdminUser : User
{
private readonly List<string> _permissions;

public AdminUser(List<string> permissions)
{
_permissions = permissions;
}

public override bool CanAccess() => _permissions.Contains(“View”);
public override string Message => CanAccess() ? “Access granted” : “Permission denied”;
}

public class Program
{
public static void Main()
{
User user = new AdminUser(new List<string> { “Edit” });
Console.WriteLine(user.Message);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر مثال یک راه منحصر به فرد برای refactor تودرتو نشان می دهد if بلوک ها این نمونه ها مستقل، کامل و آماده اجرا هستند. اگر مایل به توضیح بیشتر یا پیشرفت هستید، به من اطلاع دهید!

بیاموزید که چگونه عبارات تو در تو را در سی شارپ برای کدهای تمیزتر و قابل نگهداری تر تغییر دهید. برای ساده کردن منطق پیچیده، تکنیک‌های عملی مانند بند نگهبانی، الگوها و استراتژی‌ها را با مثال‌های دقیق کشف کنید.

سناریو: عبارات اگر تودرتو

فرض کنید کد زیر را برای مدیریت منطق دسترسی کاربر دارید. در نگاه اول ساده به نظر می رسد:

if (user != null)
{
    if (user.IsActive)
    {
        if (user.Role == "Admin")
        {
            if (user.HasPermission("View"))
            {
                Console.WriteLine("Access granted");
            }
            else
            {
                Console.WriteLine("Permission denied");
            }
        }
        else
        {
            Console.WriteLine("Role not authorized");
        }
    }
    else
    {
        Console.WriteLine("User is not active");
    }
}
else
{
    Console.WriteLine("User not found");
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


چرا Refactor؟

در حالی که این کد کار می کند، مشکلات متعددی با این تودرتو وجود دارد if ساختار:

  1. کاهش خوانایی

    هرچه لانه سازی عمیق تر باشد، درک جریان منطق در یک نگاه دشوارتر می شود. این کار تلاش ذهنی مورد نیاز برای خواندن و درک کد را افزایش می دهد.

  2. افزایش بار شناختی

    با چندین لایه از شرایط، توسعه دهندگان باید زمینه هر لایه را پیگیری کنند، و پیگیری و اشکال زدایی منطق را دشوارتر می کند.

  3. قابلیت نگهداری ضعیف

    اگر نیاز به اصلاح، گسترش یا آزمایش منطق دارید (به عنوان مثال، اضافه کردن یک شرط جدید برای دسترسی)، باید به دقت ساختار تودرتو را پیمایش کنید و خطر خطا را افزایش دهید.

  4. پیچیدگی تست

    تست‌های واحد برای شرایط عمیق تو در تو می‌تواند دست و پا گیر شود، زیرا هر شرایطی نیاز به تنظیم و تأیید برای سناریوهای متعدد دارد.

  5. نقض اصول کد پاک

    تو در تو if بلوک‌ها با شیوه‌های کدنویسی تمیز مانند مسئولیت واحد و خروج زودهنگام، که منطق روشن و مختصر را ترویج می کنند.


گزینه های Refactoring

برای پرداختن به این چالش ها، راه های مختلفی برای بازسازی تودرتو وجود دارد if بلوک ها:

  1. بندهای نگهبانی

    برای حذف تودرتوهای غیر ضروری و بهبود خوانایی، زودتر از آن خارج شوید.

  2. تغییر عبارات

    از عبارات مختصر برای سناریوهای ساده با نتایج متعدد استفاده کنید.

  3. الگوی استراتژی

    قوانین دسترسی را در استراتژی‌های قابل استفاده مجدد و قابل آزمایش قرار دهید.

  4. الگوی مشخصات

    چندین شرایط را در مشخصات واضح و قابل استفاده مجدد ترکیب کنید.

  5. چند شکلی

    از اصول شی گرا برای مدیریت پویا منطق خاص کاربر استفاده کنید.

هر یک از این رویکردها مزایای منحصر به فردی را به ارمغان می آورد، از ساده سازی منطق گرفته تا بهبود تست پذیری. بیایید هر گزینه را با مثال های دقیق بررسی کنیم.


1. بازسازی با بندهای نگهبانی

مثال کامل:

public class User
{
    public string Name { get; set; }
    public bool IsActive { get; set; }
    public string Role { get; set; }
    public List<string> Permissions { get; set; } = new List<string>();

    public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public class Program
{
    public static void Main()
    {
        User user = new User
        {
            Name = "John Doe",
            IsActive = true,
            Role = "Admin",
            Permissions = new List<string> { "View", "Edit" }
        };

        CheckAccess(user);
    }

    public static void CheckAccess(User user)
    {
        if (user == null)
        {
            Console.WriteLine("User not found");
            return;
        }

        if (!user.IsActive)
        {
            Console.WriteLine("User is not active");
            return;
        }

        if (user.Role != "Admin")
        {
            Console.WriteLine("Role not authorized");
            return;
        }

        if (!user.HasPermission("View"))
        {
            Console.WriteLine("Permission denied");
            return;
        }

        Console.WriteLine("Access granted");
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


2. Refactoring با Switch Expression

مثال کامل:

public class User
{
    public string Name { get; set; }
    public bool IsActive { get; set; }
    public string Role { get; set; }
    public List<string> Permissions { get; set; } = new List<string>();

    public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public class Program
{
    public static void Main()
    {
        User user = new User
        {
            Name = "John Doe",
            IsActive = true,
            Role = "Admin",
            Permissions = new List<string> { "View" }
        };

        var result = (user != null, user?.IsActive, user?.Role, user?.HasPermission("View")) switch
        {
            (false, _, _, _) => "User not found",
            (true, false, _, _) => "User is not active",
            (true, true, "Admin", false) => "Permission denied",
            (true, true, "Admin", true) => "Access granted",
            _ => "Role not authorized"
        };

        Console.WriteLine(result);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


3. بازسازی با الگوی استراتژی

مثال کامل:

public class User
{
    public string Name { get; set; }
    public bool IsActive { get; set; }
    public string Role { get; set; }
    public List<string> Permissions { get; set; } = new List<string>();

    public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public interface IAccessStrategy
{
    bool CanAccess(User user);
    string Message { get; }
}

public class UserNotFoundStrategy : IAccessStrategy
{
    public string Message => "User not found";
    public bool CanAccess(User user) => user == null;
}

public class UserNotActiveStrategy : IAccessStrategy
{
    public string Message => "User is not active";
    public bool CanAccess(User user) => user != null && !user.IsActive;
}

public class RoleNotAuthorizedStrategy : IAccessStrategy
{
    public string Message => "Role not authorized";
    public bool CanAccess(User user) => user != null && user.IsActive && user.Role != "Admin";
}

public class PermissionDeniedStrategy : IAccessStrategy
{
    public string Message => "Permission denied";
    public bool CanAccess(User user) => user != null && user.IsActive && user.Role == "Admin" && !user.HasPermission("View");
}

public class AccessGrantedStrategy : IAccessStrategy
{
    public string Message => "Access granted";
    public bool CanAccess(User user) => user != null && user.IsActive && user.Role == "Admin" && user.HasPermission("View");
}

public class Program
{
    public static void Main()
    {
        User user = new User
        {
            Name = "John Doe",
            IsActive = true,
            Role = "Admin",
            Permissions = new List<string> { "Edit" }
        };

        var strategies = new List<IAccessStrategy>
        {
            new UserNotFoundStrategy(),
            new UserNotActiveStrategy(),
            new RoleNotAuthorizedStrategy(),
            new PermissionDeniedStrategy(),
            new AccessGrantedStrategy()
        };

        var applicableStrategy = strategies.FirstOrDefault(s => s.CanAccess(user));
        Console.WriteLine(applicableStrategy?.Message ?? "Unknown error");
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


4. Refactoring با الگوی مشخصات

مثال کامل:

public class User
{
    public string Name { get; set; }
    public bool IsActive { get; set; }
    public string Role { get; set; }
    public List<string> Permissions { get; set; } = new List<string>();

    public bool HasPermission(string permission) => Permissions.Contains(permission);
}

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T entity);
}

public class IsUserActiveSpecification : ISpecification<User>
{
    public bool IsSatisfiedBy(User user) => user != null && user.IsActive;
}

public class IsAdminSpecification : ISpecification<User>
{
    public bool IsSatisfiedBy(User user) => user != null && user.Role == "Admin";
}

public class HasPermissionSpecification : ISpecification<User>
{
    private readonly string _permission;
    public HasPermissionSpecification(string permission) => _permission = permission;

    public bool IsSatisfiedBy(User user) => user != null && user.HasPermission(_permission);
}

public class AccessSpecification : ISpecification<User>
{
    public bool IsSatisfiedBy(User user) =>
        new IsUserActiveSpecification().IsSatisfiedBy(user) &&
        new IsAdminSpecification().IsSatisfiedBy(user) &&
        new HasPermissionSpecification("View").IsSatisfiedBy(user);
}

public class Program
{
    public static void Main()
    {
        User user = new User
        {
            Name = "John Doe",
            IsActive = true,
            Role = "Admin",
            Permissions = new List<string> { "View", "Edit" }
        };

        var accessSpec = new AccessSpecification();

        if (accessSpec.IsSatisfiedBy(user))
            Console.WriteLine("Access granted");
        else
            Console.WriteLine("Access denied");
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


5. بازسازی با پلی مورفیسم

مثال کامل:

public abstract class User
{
    public abstract bool CanAccess();
    public abstract string Message { get; }
}

public class GuestUser : User
{
    public override bool CanAccess() => false;
    public override string Message => "User not found";
}

public class InactiveUser : User
{
    public override bool CanAccess() => false;
    public override string Message => "User is not active";
}

public class AdminUser : User
{
    private readonly List<string> _permissions;

    public AdminUser(List<string> permissions)
    {
        _permissions = permissions;
    }

    public override bool CanAccess() => _permissions.Contains("View");
    public override string Message => CanAccess() ? "Access granted" : "Permission denied";
}

public class Program
{
    public static void Main()
    {
        User user = new AdminUser(new List<string> { "Edit" });
        Console.WriteLine(user.Message);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


هر مثال یک راه منحصر به فرد برای refactor تودرتو نشان می دهد if بلوک ها این نمونه ها مستقل، کامل و آماده اجرا هستند. اگر مایل به توضیح بیشتر یا پیشرفت هستید، به من اطلاع دهید!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا