سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

CMS نویس مرجعی برای آموزش برنامه نویسی وب و PHP، توسعه افزونه‌های اختصاصی وردپرس، طراحی ورک‌فلو و اتوماسیون با n8n و توسعه CMS های اختصاصی است. هدف ما ارائه آموزش‌های کاربردی و راهکارهای حرفه‌ای برای توسعه‌دهندگان، کسب‌وکارها و علاقه‌مندان به دنیای برنامه‌نویسی است.

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Null Object Pattern در PHP چیست؟ آموزش الگوی Null Object با مثال عملی

Null Object Pattern در PHP چیست؟ آموزش الگوی Null Object با مثال عملی

ممدیر کل سیستم ۲۲ شهریور ۱۴۰۵ ۱۸ دقیقه مطالعه ۳ بازدید
Null Object Pattern در PHP چیست؟ آموزش الگوی Null Object با مثال عملی

در پروژه‌های PHP معمولاً با متدهایی روبه‌رو می‌شویم که ممکن است یک Object یا مقدار null برگردانند. در چنین شرایطی، کد مصرف‌کننده مجبور می‌شود قبل از هر استفاده، وجود Object را بررسی کند:


if ($user !== null) {

    echo $user->getName();

}

اگر این وضعیت در بخش‌های مختلف برنامه تکرار شود، تعداد شرط‌ها افزایش پیدا می‌کند و خوانایی و نگهداری کد دشوارتر می‌شود.

Null Object Pattern راهکاری است که به‌جای بازگرداندن null، یک Object واقعی با رفتار پیش‌فرض برمی‌گرداند. در نتیجه، کد مصرف‌کننده می‌تواند بدون شرط‌های تکراری با Object کار کند.

این الگو در پروژه‌هایی مانند سیستم لاگ، ارسال اعلان، مدیریت کاربران مهمان، پردازش سفارش و Chain of Responsibility کاربرد دارد. مستندات DesignPatternsPHP نیز Null Object را الگویی برای ساده‌کردن کد Client، کاهش بررسی‌های null و کم‌کردن احتمال خطاهای مربوط به مقدار تهی معرفی می‌کند. <Cite refs={["turn0search0","turn0search12"]} />

Null Object Pattern چیست؟

Null Object Pattern یک الگوی طراحی است که به‌جای مقدار null، یک Object با رفتار مشخص و پیش‌فرض در اختیار کد مصرف‌کننده قرار می‌دهد.

این Object معمولاً همان Interface یا Contract مربوط به Object اصلی را پیاده‌سازی می‌کند؛ اما به‌جای انجام عملیات واقعی، رفتار خنثی یا پیش‌فرض دارد.

برای مثال، فرض کنید برنامه شما یک Logger دارد. در حالت عادی پیام‌ها در فایل ذخیره می‌شوند؛ اما در بعضی محیط‌ها مانند تست یا اجرای محلی، نمی‌خواهید هیچ لاگی ذخیره شود.

به‌جای این کد:


if ($logger !== null) {

    $logger->log('User created');

}

می‌توان از یک NullLogger استفاده کرد:


$logger->log('User created');

در این حالت، اگر Logger واقعی وجود داشته باشد پیام ثبت می‌شود و اگر Logger از نوع Null باشد، عملیات بدون انجام کار خاصی پایان پیدا می‌کند.

نکته مهم این است که Null Object معمولاً به‌عنوان یک الگوی مستقل در فهرست رسمی GoF قرار نمی‌گیرد، اما به دلیل کاربرد گسترده در طراحی شی‌گرا و Refactoring، به‌عنوان یک الگوی رایج شناخته می‌شود. <Cite refs={["turn0search0","turn0search5"]} />

مشکل استفاده مستقیم از null

فرض کنید یک سیستم ارسال اعلان دارید. کاربر ممکن است اعلان‌گر فعال داشته باشد یا نداشته باشد:


<?php



declare(strict_types=1);



final class NotificationService

{

    public function send(string $message): void

    {

        echo "Notification sent: {$message}";

    }

}

در بخش دیگر برنامه:


<?php



$notificationService = null;



if ($notificationService !== null) {

    $notificationService->send('Your order was created.');

}

این کد در ابتدا ساده به نظر می‌رسد؛ اما اگر در چندین کلاس و متد تکرار شود، مشکلات زیر ایجاد می‌شود:

  • شرط‌های null زیاد می‌شوند.
  • منطق اصلی برنامه با بررسی‌های جانبی مخلوط می‌شود.
  • احتمال فراموش‌کردن یک بررسی افزایش پیدا می‌کند.
  • تعداد مسیرهای قابل تست بیشتر می‌شود.
  • کد به مقدار null وابستگی پیدا می‌کند.

هدف Null Object این است که این شرط‌ها را از کد مصرف‌کننده حذف کند.

ساختار Null Object Pattern

این الگو معمولاً از بخش‌های زیر تشکیل می‌شود:

Interface یا Contract

Interface رفتار مشترک Object واقعی و Null Object را مشخص می‌کند.

Real Object

این کلاس عملیات واقعی را انجام می‌دهد.

Null Object

این کلاس همان Interface را پیاده‌سازی می‌کند؛ اما رفتار پیش‌فرض یا خنثی دارد.

Client

کدی است که با Interface کار می‌کند و لازم نیست بداند Object واقعی است یا Null Object.

ساختار کلی به شکل زیر است:


Client

   |

   v

Interface

   |

   +------ Real Object

   |

   +------ Null Object

در این ساختار Client فقط Interface را می‌شناسد. انتخاب Object واقعی یا Null Object معمولاً در مرحله ساخت Object یا در یک Factory انجام می‌شود.

مثال ساده: کاربر واقعی و کاربر مهمان

فرض کنید در سایت، بعضی کاربران وارد حساب خود شده‌اند و بعضی کاربران مهمان هستند. می‌خواهیم نام کاربر را نمایش دهیم.

روش معمول:


<?php



$user = null;



if ($user !== null) {

    echo $user->getName();

} else {

    echo 'Guest';

}

با Null Object می‌توان یک Interface تعریف کرد.

مرحله اول: ساخت Interface


<?php



declare(strict_types=1);



interface UserInterface

{

    public function getName(): string;



    public function isGuest(): bool;

}

این Interface مشخص می‌کند هر نوع User باید دو متد داشته باشد:

  • getName
  • isGuest

مرحله دوم: ساخت User واقعی


<?php



declare(strict_types=1);



final class User implements UserInterface

{

    public function __construct(

        private readonly string $name,

    ) {

    }



    public function getName(): string

    {

        return $this->name;

    }



    public function isGuest(): bool

    {

        return false;

    }

}

کلاس User اطلاعات کاربر واقعی را نگهداری می‌کند.

مرحله سوم: ساخت NullUser


<?php



declare(strict_types=1);



final class NullUser implements UserInterface

{

    public function getName(): string

    {

        return 'Guest';

    }



    public function isGuest(): bool

    {

        return true;

    }

}

کلاس NullUser نیز همان Interface را پیاده‌سازی می‌کند؛ اما نام پیش‌فرض Guest را برمی‌گرداند.

مرحله چهارم: استفاده در Client


<?php



declare(strict_types=1);



function showUserName(UserInterface $user): void

{

    echo $user->getName();

}



showUserName(new User('Saeed'));



// Saeed



showUserName(new NullUser());



// Guest

در این مثال، تابع showUserName دیگر نیازی ندارد بررسی کند که کاربر واقعی است یا خیر.

این همان مزیت اصلی Null Object Pattern است: Client با یک Interface کار می‌کند و از جزئیات نوع Object اطلاع ندارد.

مقایسه روش معمول با Null Object

روش معمول


<?php



$user = findUser();



if ($user !== null) {

    echo $user->getName();

} else {

    echo 'Guest';

}

روش استفاده از Null Object


<?php



$user = findUser() ?? new NullUser();



echo $user->getName();

در این روش فقط هنگام دریافت User تصمیم می‌گیریم که اگر مقدار واقعی وجود نداشت، یک NullUser ساخته شود.

بعد از آن، سایر بخش‌های برنامه می‌توانند بدون شرط از User استفاده کنند.

البته اگر این تصمیم در یک Repository یا Factory انجام شود، کد Client حتی نیازی ندارد از عبارت ?? استفاده کند.

ساخت Repository با Null Object

فرض کنید Repository وظیفه پیدا کردن کاربر را بر عهده دارد:


<?php



declare(strict_types=1);



final class UserRepository

{

    public function findById(int $id): UserInterface

    {

        if ($id === 1) {

            return new User('Saeed');

        }



        return new NullUser();

    }

}

اکنون Client به شکل زیر نوشته می‌شود:


<?php



declare(strict_types=1);



$repository = new UserRepository();



$user = $repository->findById(10);



echo $user->getName();



// Guest

متد findById دیگر null برنمی‌گرداند؛ بلکه همیشه یک Object از نوع UserInterface تحویل می‌دهد.

این روش باعث می‌شود قرارداد متد واضح‌تر شود. مصرف‌کننده می‌داند که همیشه یک User دریافت می‌کند، حتی اگر کاربر واقعی در سیستم وجود نداشته باشد.

استفاده از Null Object برای Logger

یکی از کاربردهای رایج Null Object، ساخت Logger خنثی است.

Interface مربوط به Logger


<?php



declare(strict_types=1);



interface LoggerInterface

{

    public function info(string $message): void;



    public function error(string $message): void;

}

Logger واقعی


<?php



declare(strict_types=1);



final class FileLogger implements LoggerInterface

{

    public function __construct(

        private readonly string $filePath,

    ) {

    }



    public function info(string $message): void

    {

        $this->write('INFO', $message);

    }



    public function error(string $message): void

    {

        $this->write('ERROR', $message);

    }



    private function write(string $level, string $message): void

    {

        $line = sprintf(

            "[%s] %s: %s%s",

            date('Y-m-d H:i:s'),

            $level,

            $message,

            PHP_EOL,

        );



        file_put_contents(

            $this->filePath,

            $line,

            FILE_APPEND,

        );

    }

}

NullLogger


<?php



declare(strict_types=1);



final class NullLogger implements LoggerInterface

{

    public function info(string $message): void

    {

        // عمداً هیچ کاری انجام نمی‌شود.

    }



    public function error(string $message): void

    {

        // عمداً هیچ کاری انجام نمی‌شود.

    }

}

استفاده از Logger


<?php



declare(strict_types=1);



final class OrderService

{

    public function __construct(

        private readonly LoggerInterface $logger,

    ) {

    }



    public function createOrder(): void

    {

        $this->logger->info('Order creation started');



        // منطق ساخت سفارش



        $this->logger->info('Order created successfully');

    }

}

در محیط Production:


<?php



$logger = new FileLogger(__DIR__ . '/app.log');



$orderService = new OrderService($logger);



$orderService->createOrder();

در محیط تست:


<?php



$logger = new NullLogger();



$orderService = new OrderService($logger);



$orderService->createOrder();

در محیط تست، کد OrderService تغییر نمی‌کند. تنها Logger متفاوتی به آن تزریق می‌شود.

Null Object در Chain of Responsibility

Null Object می‌تواند به‌عنوان Handler نهایی در Chain of Responsibility استفاده شود.

فرض کنید چند Handler برای بررسی درخواست داریم:

  • بررسی احراز هویت
  • بررسی سطح دسترسی
  • بررسی موجودی
  • Handler نهایی

اگر هیچ Handlerای نتواند درخواست را پردازش کند، می‌توان به‌جای null یک Handler خنثی برگرداند.

نمونه Interface:


<?php



declare(strict_types=1);



interface HandlerInterface

{

    public function handle(string $request): string;

}

Handler واقعی:


<?php



declare(strict_types=1);



final class AuthenticationHandler implements HandlerInterface

{

    public function handle(string $request): string

    {

        if ($request === 'login') {

            return 'Authentication handled';

        }



        return 'Request passed';

    }

}

Null Handler:


<?php



declare(strict_types=1);



final class NullHandler implements HandlerInterface

{

    public function handle(string $request): string

    {

        return 'No handler action required';

    }

}

در این حالت، زنجیره همیشه یک Handler معتبر دارد و نیازی نیست در انتهای زنجیره با مقدار null برخورد کنیم.

Null Object در Laravel

در Laravel می‌توان از Null Object در بخش‌های مختلف استفاده کرد؛ البته باید آن را متناسب با نیاز پروژه طراحی کرد.

۱. Null Notification Service

فرض کنید برای بعضی کاربران ارسال اعلان غیرفعال است. به‌جای قرار دادن شرط در تمام Serviceها، می‌توان دو پیاده‌سازی ساخت:

  • RealNotificationService
  • NullNotificationService

<?php



declare(strict_types=1);



interface NotificationSenderInterface

{

    public function send(string $recipient, string $message): void;

}

پیاده‌سازی واقعی:


<?php



declare(strict_types=1);



final class SmsNotificationSender implements NotificationSenderInterface

{

    public function send(string $recipient, string $message): void

    {

        // ارسال پیامک از طریق سرویس‌دهنده

    }

}

پیاده‌سازی Null:


<?php



declare(strict_types=1);



final class NullNotificationSender implements NotificationSenderInterface

{

    public function send(string $recipient, string $message): void

    {

        // ارسال اعلان عمداً انجام نمی‌شود.

    }

}

سپس در Service اصلی:


<?php



declare(strict_types=1);



final class BillingService

{

    public function __construct(

        private readonly NotificationSenderInterface $notificationSender,

    ) {

    }



    public function notifyUser(

        string $mobile,

        string $message,

    ): void {

        $this->notificationSender->send($mobile, $message);

    }

}

اکنون BillingService لازم نیست بداند پیامک فعال است یا غیرفعال.

۲. Null Price Calculator

در سیستم فروشگاهی ممکن است بعضی محصولات قیمت محاسبه‌شده نداشته باشند. می‌توان یک Calculator خنثی ساخت که قیمت پیش‌فرض مشخصی برگرداند.


<?php



declare(strict_types=1);



interface PriceCalculatorInterface

{

    public function calculate(int $productId): int;

}

پیاده‌سازی Null:


<?php



declare(strict_types=1);



final class NullPriceCalculator implements PriceCalculatorInterface

{

    public function calculate(int $productId): int

    {

        return 0;

    }

}

البته مقدار 0 فقط زمانی مناسب است که در منطق کسب‌وکار به معنی «قیمت ندارد» باشد. اگر صفر ممکن است با قیمت واقعی اشتباه شود، بهتر است از Value Object یا وضعیت مشخص دیگری استفاده کنید.

۳. Null Discount Strategy

در سیستم فروشگاهی، همه کاربران تخفیف ندارند. به‌جای شرط‌های متعدد می‌توان از Strategy واقعی و Null Strategy استفاده کرد.


<?php



declare(strict_types=1);



interface DiscountStrategyInterface

{

    public function calculate(int $price): int;

}

استراتژی تخفیف:


<?php



declare(strict_types=1);



final class TenPercentDiscount implements DiscountStrategyInterface

{

    public function calculate(int $price): int

    {

        return (int) round($price * 0.10);

    }

}

استراتژی بدون تخفیف:


<?php



declare(strict_types=1);



final class NullDiscount implements DiscountStrategyInterface

{

    public function calculate(int $price): int

    {

        return 0;

    }

}

استفاده:


<?php



$discount = new NullDiscount();



$price = 500000;



$discountAmount = $discount->calculate($price);



$finalPrice = $price - $discountAmount;



echo $finalPrice;



// 500000

این روش ترکیبی از Strategy Pattern و Null Object Pattern است.

تفاوت Null Object و مقدار null

مقدار null نشان می‌دهد که هیچ Object یا مقداری وجود ندارد. اما Null Object یک Object واقعی است که رفتار پیش‌فرض دارد.

مقدار nullNull Object
هیچ Objectی وجود نداردیک Object معتبر وجود دارد
نیازمند بررسی استمعمولاً بدون شرط استفاده می‌شود
ممکن است خطای فراخوانی متد ایجاد کندمتدهای Contract را ارائه می‌دهد
اطلاعاتی درباره رفتار پیش‌فرض نداردرفتار پیش‌فرض مشخص دارد
برای نبودن مقدار مناسب استبرای نبودن رفتار یا Object جایگزین مناسب است

نکته مهم این است که Null Object به معنی پنهان‌کردن همه خطاها نیست. اگر نبودن یک Object باید باعث توقف عملیات شود، نباید آن را با یک Null Object خنثی جایگزین کنیم.

تفاوت Null Object و Optional

در بعضی زبان‌ها مانند Java یا Kotlin، ساختارهایی مانند Optional برای نمایش وجود یا نبودن مقدار استفاده می‌شوند.

Optional معمولاً به Client می‌گوید که باید وجود مقدار را بررسی کند؛ اما Null Object تلاش می‌کند یک رفتار معتبر و پیش‌فرض ارائه دهد.

برای مثال:


$user = findUser();



if ($user !== null) {

    echo $user->getName();

}

در Null Object:


$user = findUser();



echo $user->getName();

در حالت دوم، متد findUser باید همیشه یک Object با Contract معتبر برگرداند.

تفاوت Null Object و Default Value

گاهی می‌توان به‌جای Object از مقدار پیش‌فرض استفاده کرد:


$name = $userName ?? 'Guest';

این روش برای مقادیر ساده مانند String یا Integer مناسب است.

اما اگر Object رفتارهای مختلفی داشته باشد، مقدار پیش‌فرض کافی نیست. برای مثال User ممکن است متدهای زیر را داشته باشد:


$user->getName();

$user->getRole();

$user->getAvatar();

$user->canPurchase();

در چنین شرایطی، یک NullUser می‌تواند تمام رفتارهای پیش‌فرض را در یک کلاس متمرکز کند.

چه زمانی از Null Object استفاده کنیم؟

Null Object زمانی مناسب است که:

  • نبودن Object یک وضعیت معتبر و قابل پیش‌بینی باشد.
  • رفتار پیش‌فرض مشخصی برای نبودن Object وجود داشته باشد.
  • شرط‌های null در چندین بخش تکرار شده باشند.
  • Client باید با یک Interface ثابت کار کند.
  • می‌خواهید از Polymorphism استفاده کنید.
  • Object خنثی می‌تواند بدون آسیب به منطق برنامه عمل کند.

نمونه‌های مناسب:

  • Logger خنثی
  • ارسال‌کننده اعلان غیرفعال
  • کاربر مهمان
  • تخفیف صفر
  • Handler نهایی
  • خروجی خنثی
  • Cache Driver بدون ذخیره‌سازی

چه زمانی از Null Object استفاده نکنیم؟

اگر نبودن Object نشانه یک خطای جدی است، نباید آن را با Null Object پنهان کنیم.

برای مثال، اگر پیدا نشدن سفارش باید باعث خطای 404 شود، بهتر است همان وضعیت را واضح مدیریت کنید:


$order = $orderRepository->find($id);



if ($order === null) {

    throw new OrderNotFoundException();

}

همچنین در موارد زیر باید با احتیاط از Null Object استفاده کرد:

  • عملیات مالی حساس
  • پرداخت و تراکنش
  • احراز هویت
  • کنترل دسترسی
  • حذف اطلاعات
  • عملیات‌هایی که انجام‌نشدن آن‌ها باید مشخصاً گزارش شود

در این موقعیت‌ها، رفتار خنثی ممکن است خطا را پنهان کند و باعث ایجاد مشکل جدی شود.

مزایای Null Object Pattern

کاهش شرط‌های null

کد Client به بررسی‌های تکراری نیاز ندارد.

خوانایی بهتر

منطق اصلی برنامه از شرط‌های جانبی جدا می‌شود.

استفاده از Polymorphism

Object واقعی و Null Object از یک Interface مشترک استفاده می‌کنند.

تست‌پذیری بیشتر

می‌توان در تست‌ها به‌جای Mock پیچیده از Null Object استفاده کرد.

کاهش وابستگی

Client فقط Contract را می‌شناسد و به کلاس واقعی وابسته نیست.

رفتار پیش‌فرض مشخص

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

معایب Null Object Pattern

افزایش تعداد کلاس‌ها

برای هر Interface ممکن است به یک Null Object جداگانه نیاز داشته باشید.

احتمال پنهان‌شدن خطا

اگر Null Object در جای نامناسب استفاده شود، خطاهای واقعی ممکن است دیده نشوند.

دشواری انتخاب رفتار پیش‌فرض

همیشه مشخص نیست که رفتار خنثی باید چه باشد.

پیچیدگی در Interfaceهای بزرگ

اگر Interface متدهای زیادی داشته باشد، ساخت Null Object سخت‌تر می‌شود.

خطر بازگرداندن مقدار اشتباه

برای مثال برگرداندن 0 به‌جای قیمت نامشخص ممکن است با قیمت واقعی اشتباه گرفته شود.

نکات مهم در طراحی Null Object

Interface را کوچک نگه دارید

هرچه Interface کوچک‌تر باشد، ساخت Null Object ساده‌تر خواهد بود.

رفتار پیش‌فرض را مستند کنید

مشخص کنید Null Object دقیقاً چه کاری انجام می‌دهد و چه کاری انجام نمی‌دهد.

از Null Object برای پنهان‌کردن Exception استفاده نکنید

اگر یک عملیات باید خطا بدهد، بهتر است خطا را مدیریت کنید و آن را بی‌صدا نکنید.

نام کلاس را واضح انتخاب کنید

نام‌هایی مانند موارد زیر رفتار کلاس را مشخص می‌کنند:

  • NullLogger
  • NullUser
  • NullNotificationSender
  • NullDiscount
  • NullHandler

Contract را حفظ کنید

Null Object باید همان Interface یا Contract مربوط به Object واقعی را پیاده‌سازی کند.

رفتار را با منطق کسب‌وکار هماهنگ کنید

رفتار Null Object باید برای پروژه معنا داشته باشد. برای مثال تخفیف صفر ممکن است منطقی باشد، اما قیمت صفر همیشه معنای درستی ندارد.

تست Null Object با PHPUnit

برای تست Null Object بهتر است رفتار پیش‌فرض آن را بررسی کنیم.

نمونه تست برای NullUser:


<?php



declare(strict_types=1);



use PHPUnit\Framework\TestCase;



final class NullUserTest extends TestCase

{

    public function testNullUserReturnsGuestName(): void

    {

        $user = new NullUser();



        self::assertSame('Guest', $user->getName());

        self::assertTrue($user->isGuest());

    }

}

نمونه تست برای NullDiscount:


<?php



declare(strict_types=1);



use PHPUnit\Framework\TestCase;



final class NullDiscountTest extends TestCase

{

    public function testNullDiscountReturnsZero(): void

    {

        $discount = new NullDiscount();



        self::assertSame(0, $discount->calculate(500000));

    }

}

همچنین بهتر است بررسی کنید که Client بدون شرط بتواند با Null Object کار کند:


<?php



declare(strict_types=1);



final class UserPresenter

{

    public function present(UserInterface $user): string

    {

        return sprintf(

            'User: %s',

            $user->getName(),

        );

    }

}

تست:


<?php



declare(strict_types=1);



use PHPUnit\Framework\TestCase;



final class UserPresenterTest extends TestCase

{

    public function testPresenterWorksWithNullUser(): void

    {

        $presenter = new UserPresenter();



        self::assertSame(

            'User: Guest',

            $presenter->present(new NullUser()),

        );

    }

}

اشتباهات رایج در استفاده از Null Object

استفاده از Null Object برای هر نوع خطا

Null Object برای وضعیت معتبر و قابل پیش‌بینی مناسب است، نه برای تمام خطاها.

بازگرداندن مقدار مبهم

اگر Null Object مقدار 0 یا String خالی برگرداند، باید مشخص باشد که این مقدار چه معنایی دارد.

قرار دادن شرط داخل تمام متدهای Null Object

اگر Null Object در تمام متدهای خود شرط‌های پیچیده داشته باشد، ممکن است طراحی بیش از حد پیچیده شود.

نادیده‌گرفتن Contract

Null Object باید همان رفتارهای اصلی Interface را ارائه کند.

ساخت Null Object بسیار بزرگ

اگر یک Null Object متدهای زیادی داشته باشد، احتمالاً Interface اصلی بیش از حد بزرگ است و باید به چند Interface کوچک‌تر تقسیم شود.

جمع‌بندی

Null Object Pattern در PHP راهکاری برای جایگزین‌کردن مقدار null با یک Object معتبر و دارای رفتار پیش‌فرض است. این الگو با استفاده از Interface و Polymorphism باعث می‌شود کد Client به شرط‌های تکراری وابسته نباشد.

در این الگو معمولاً یک Object واقعی و یک Null Object از Contract مشترک استفاده می‌کنند. Object واقعی عملیات اصلی را انجام می‌دهد و Null Object رفتار خنثی یا پیش‌فرض ارائه می‌دهد.

از کاربردهای مهم Null Object می‌توان به موارد زیر اشاره کرد:

  • NullLogger
  • NullUser
  • NullHandler
  • NullNotificationSender
  • NullDiscount
  • سرویس‌های غیرفعال در Laravel

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

سوالات متداول

Null Object Pattern در PHP چیست؟

Null Object Pattern الگویی است که به‌جای بازگرداندن null، یک Object با رفتار پیش‌فرض برمی‌گرداند تا کد مصرف‌کننده به شرط‌های تکراری نیاز نداشته باشد.

آیا Null Object یک Design Pattern رسمی GoF است؟

خیر. Null Object معمولاً در دسته الگوهای رسمی GoF قرار نمی‌گیرد، اما یک الگوی رایج در طراحی شی‌گرا و Refactoring محسوب می‌شود.

مهم‌ترین مزیت Null Object چیست؟

کاهش شرط‌های null، ساده‌ترشدن کد Client و استفاده از یک Interface مشترک بین Object واقعی و Object خنثی از مهم‌ترین مزایای آن است.

آیا Null Object در Laravel کاربرد دارد؟

بله. می‌توان از آن برای Logger خنثی، سرویس اعلان غیرفعال، تخفیف صفر، Handler نهایی و سرویس‌های اختیاری استفاده کرد.

آیا Null Object جایگزین Exception است؟

خیر. اگر نبودن Object نشانه خطای جدی باشد، باید Exception یا پاسخ خطای مشخص استفاده شود. Null Object فقط برای وضعیت‌های معتبر و قابل پیش‌بینی مناسب است.

تفاوت Null Object با null چیست؟

null نشان‌دهنده نبودن مقدار یا Object است؛ اما Null Object یک Object واقعی است که رفتار پیش‌فرض را از طریق Interface ارائه می‌دهد.

آیا استفاده از Null Object همیشه بهتر از null است؟

خیر. اگر بررسی نبودن مقدار بخشی از منطق اصلی برنامه باشد، استفاده از null یا Exception ممکن است شفاف‌تر باشد. Null Object زمانی مناسب است که رفتار پیش‌فرض مشخص و معتبر داشته باشیم.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه