Private constructor for public class

I want to make sure that I am the only one who can create some type of object class. But I want the class to be public so that I can have methods for manipulating those objects. I don't want to use an interface for those methods because I want to make sure the object is really one of mine.

In java, I would implement it like this.

package com.example;

public enum Factory {
  INSTANCE;
  public Element createElement() {
  return new Element(“test”);
  }
  public static class Element {
  private final String name;
  private Element(final String name) { this.name = name; }
  public String getName() { return name; }
  }
}

final Element element = Factory.INSTANCE.createElement();

This achieves my goal: Element is public, but nobody can create one without going through my factory
unless they use reflection.

I don’t know how to achieve the same with kotlin. The java solution relies on the fact that you can have a public class with a private constructor,
and I don’t know if or how I can do that in kotlin.

In Kotlin, if you need to provide custom visibility for constructor, you write it in class header, before constructor parenthesis. Your sample looks like this in Kotlin:

public object Factory {   public fun createElement(): Element = Element("test")

  public class Element internal (public val name: String)
}

Note that visibility of constructor in nested class is internal, not private, because otherwise it coundn't be used in outer class.

Awesome, thanks.

doesn’t work for me - is this info outdated? I had to add the word ‘constructor’ after the visibility modifier, making it like “secondary constructor syntax”.

2 Likes

It is correct that you have to name it construtor explicitly, if you want to add visibility modifiers or annotations like @Inject to the constructor.

class ClassName private constructor() {}

or If you are using multiple constructor

class ClassName() {
 private constructor(params: Params){}
}

Another way to define a private constructor for a public class:

class MyClass private constructor(val thing: Int) {
    // ...
}