16 Eylül 2020 Çarşamba

sealed Anahtar Kelimesi - Java 15 İle Geliyor

Giriş
sealed, final ve non sealed anahtar kelimeleri ilgili şeyler

Kısaca
- sealed kendisinden kalıtabilen sınıfları belirtir
- non-sealed sınıf, sealed sınıftan kalıtır ve artık sealed özelliğinin kaldırıldığını belirtir
- final sınıf, sealed sınıftan kalıtır ve artık kimsenin kimden kalıtamayacağını belirtir

sealed
JEP360 ile geliyor. Açıklaması şöyle. sealed kelimesi class ve interface için kullanılabilir.
Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
Eğer bir ata sınıf sealed ise permits ile hangi sınıfların kalıtabileceğini belirtir. permit ile belirtilen isimler aynı pakette olmalıdır. Açıklaması şöyle
The classes or interfaces in the permits the list must be located in the same package (or in the same module if the parent is in a named module).
Örnek - nested sınıf için permit kelimesine gerek yok
Normalde şöyle yaparız
sealed interface Parent
  permits ChildA, ChildB, ChildC { ... }
Eğer sınıflar nested veya inner class ise permit kelimesine gerek yok. Şöyle yaparız
public sealed class Parent {
  final class Child1 extends Parent {}
  final class Child2 extends Parent {}
  final class Child3 extends Parent {}
}
Escape Hatch
Bu kalıtan sınıflardan bir tanesi de non-sealed kullanarak, kendisinde de kalıtım yapılabilmesini sağlar. Açıklaması şöyle
Sealed classes are about having finer control over who can extend a given extensible type. There are several reasons you might want to do this, and "ensuring that no one extends the hierarchy ever" is only one of them.

There are many cases where an API has several "built in" abstractions and then an "escape hatch" abstraction; this allows API authors to guide would-be extenders to the escape hatches that are design for extension.
Örnek
Şöyle yaparız
sealed interface Command
    permits LoginCommand, LogoutCommand, ShowProfileCommand, UserPluginCommand { ... }

// final implementations of built-in commands

non-sealed abstract class UserPluginCommand extends Command {
  // plugin-specific API
}
Bu kod şu faydayı sağlar
Such a hierarchy accomplishes two things:

All extension is funneled through the UserPluginCommand, which can be designed defensively for extension and provide an API suited to user extension, but we can still use interface-based polymorphism in our design, knowing that completely uncontrolled subtypes will not appear;

The system can still rely on the fact that the four permitted types cover all implementations of Command. So internal code can use pattern matching and be confident in its exhaustiveness:
sealed ve final Farkı
 Açıklaması şöyle. Yani final ile sınıftan kalıtım yasaklanır. sealed ile sınıftan kalıtım kısıtlı hale getirilir.
final class A {...} means that no class is allowed extend A.

sealed class A permits B {...} means that only B can extend A but no other class is allowed to do that.
Örnek
Şöyle yaparız
public abstract sealed class Shape
    permits Circle, Rectangle, Square {...}

public final class Circle extends Shape {...}

public sealed class Rectangle extends Shape 
    permits TransparentRectangle, FilledRectangle {...}
public final class TransparentRectangle extends Rectangle {...}
public final class FilledRectangle extends Rectangle {...}

public non-sealed class Square extends Shape {...}
Kullanım
Örnek - null kullanmama
Elimizde şöyle bir kod olsun Burada GitHubOrganization sealed olduğu için sonuç olarak ya GitHubOrganizationSuccess veya GitHubOrganizationFailure döndürüyoruz. Sonuca da instanceof ile bakıyoruz. Böylece Optional kullanmaya da gerek kalmıyor
public sealed interface GitHubOrganization permits GitHubOrganizationSuccess, 
  GitHubOrganizationFailure {
}

public record GitHubOrganizationFailure(String error) implements GitHubOrganization {
}

public record GitHubOrganizationSuccess (GHOrganization ghOrganization) 
  implements GitHubOrganization {
}

public static GitHubOrganization verifyGithubOrganization(GitHub gitHub, 
                                                          String organizationName){
  try {
    return new GitHubOrganizationSuccess(gitHub.getOrganization(organizationName));
  } catch (IOException ioe){
    return new GitHubOrganizationFailure(ioe.getLocalizedMessage());
  }
}

GitHubOrganization githubOrganization = Utils.verifyGithubOrganization(gitHub,
  organizationName);
if (githubOrganization instanceof GitHubOrganizationSuccess gitHubOrganizationSuccess) {
}


Hiç yorum yok:

Yorum Gönder