Register to get access to free programming courses with interactive exercises

Null Object Pattern JS: Polymorphism

Sites that have authentication have a concept that we can call the “current user”. This is a user who has been authenticated through a form (or logged in through a social network). The current user is actively used to display various blocks of information, for example, to display that user's blog. This kind of code usually looks like this:

// somewhere in the imaginary template articles/index.html.slim

if isAuthenticated && currentUser.hasArticles()
  each article in currentUser.getArticles()
    // here we output the articles

Note the user authentication check. If you don't do it, the code will crash because the hasArticles() method is called on null (if no one is logged in, there's no user). When there are one or two of these checks, it's okay, but if there are a lot of them, the code gets cluttered quickly. In addition, it's very easy to forget to insert such a check.

Is there any other way to solve this problem? It turns out there is. You can use subtype polymorphism. To do this, a class is created that describes an unauthenticated user, such as Guest. Then all the necessary methods that we want to get polymorphic behavior for are added to it.

class Guest
{
  hasArticles() {
    return false;
  }

  getArticles() {
    return [];
  }
}

Most of these methods return false or empty lists because this user has nothing. Why do we need it then? It's very simple: now the client code always counts on the existence of the user, and it no longer needs to check authentication:

if currentUser.hasArticles()
  each article in currentUser.getArticles()
    // here we output the articles

Conditional constructions will go away in all patterns, but one question remains. Where and how does the process of creating our user take place? And this is we see the one remaining if, which allows the right object to be created. This happens at the stage where the incoming request is processed, and the exact location depends on the framework used. The code at this point looks something like this:

const fetchCurrentUser = (req) => {
    const userId = req.session.userId;
    // If there's an id in the session, we select the user from the database, otherwise we return guest
    return userId ? User.find(userId) : new Guest();
};

This way of using polymorphism has a special name: the "null object" design pattern. It's often used within frameworks and is sometimes found in application code. There are at least three such places on Hexlet. For example, we have dozens of methods in the Guest class. Here's what's inside (not an exhaustive list):

# this is ruby code, but it's as easy as pie
class Guest
  def id
    nil
  end

  def avatar
    nil
  end

  def github_account
    false
  end

  def has_passed_at_least_one_project?
    false
  end

  def city
    ''
  end

  def seeking_job?
    true
  end

  def mentor?
    false
  end

  def locale?
    nil
  end

  def guest?
    true
  end

  def current_subscription_object
    FreeSubscription.new(self)
  end

  def type
    'guest'
  end

  def topics_count
    0
  end
end

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs

From a novice to a developer. Get a job or your money back!

Frontend Developer icon
Profession
beginner
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.