001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2023–2024 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License.  You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.bean;
015
016/**
017 * An interface whose implementations can be ranked numerically in descending order (highest rank wins, or comes first).
018 *
019 * <p>In addition, an implementation may be designated as an {@linkplain #alternate() alternate}, which may affect the
020 * interpretation of the implementation's {@linkplain #rank() rank}.</p>
021 *
022 * <p>Given a series of {@link Ranked} implementations sorted by {@linkplain #rank() rank}, the first element of the
023 * series will bear the greatest {@linkplain #rank() rank}.</p>
024 *
025 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
026 *
027 * @see #alternate()
028 *
029 * @see #rank()
030 *
031 * @see #outranks(Ranked)
032 *
033 * @see #outranks(int)
034 *
035 * @see #outranks(int, int)
036 */
037public interface Ranked {
038
039
040  /*
041   * Static fields.
042   */
043
044
045  /**
046   * The default rank ({@value}) when returned by an implementation of the {@link #rank()} method.
047   *
048   * @see #rank()
049   */
050  public static final int DEFAULT_RANK = 0;
051
052
053  /*
054   * Instance methods.
055   */
056
057
058  /**
059   * Returns the rank of this {@link Ranked} implementation.
060   *
061   * <p>Implementations of this method may return any integer: positive, zero, or negative.</p>
062   *
063   * <p>The default implementation of this method returns the value of the {@link #DEFAULT_RANK} field ({@value
064   * #DEFAULT_RANK}).</p>
065   *
066   * <p>Overrides of this method must return a determinate value.</p>
067   *
068   * @return the rank of this {@link Ranked} implementation
069   *
070   * @see #outranks(int, int)
071   */
072  // Highest rank wins (comes first), i.e. descending order
073  public default int rank() {
074    return DEFAULT_RANK;
075  }
076
077  /**
078   * Returns {@code true} if this {@link Ranked} is to be considered an <em>alternate</em>, which may have an effect on
079   * how the return value of the {@link #rank()} method is interpreted in some situations.
080   *
081   * <p>The default implementation of this method returns {@code false}.</p>
082   *
083   * <p>Overrides of this method must be idempotent and return a determinate value.</p>
084   *
085   * @return {@code true} if this {@link Ranked} is to be considered an <em>alternate</em>
086   */
087  public default boolean alternate() {
088    return false;
089  }
090
091  /**
092   * Returns {@code true} if this {@link Ranked} outranks the supplied {@link Ranked} according to the rules described
093   * in the {@linkplain #outranks(int, int) specification for the <code>outranks(int, int)</code> method}.
094   *
095   * <p>Overriding this method, while possible and permitted, is discouraged.</p>
096   *
097   * @param other a {@link Ranked}; may be {@code null} (in which case this method will return {@code true})
098   *
099   * @return {@code true} if this {@link Ranked} outranks the supplied {@link Ranked}
100   *
101   * @see #outranks(int, int)
102   */
103  public default boolean outranks(final Ranked other) {
104    return other == null || outranks(this.rank(), other.rank());
105  }
106
107  /**
108   * Returns {@code true} if this {@link Ranked} bears a {@linkplain #rank() rank} that outranks the rank represented by
109   * {@code j} according to the rules described in the {@linkplain #outranks(int, int) specification for the
110   * <code>outranks(int, int)</code> method}.
111   *
112   * <p>Overriding this method, while possible and permitted, is discouraged.</p>
113   *
114   * @param j a rank
115   *
116   * @return {@code true} if this {@link Ranked} bears a {@linkplain #rank() rank} that {@linkplain #outranks(int, int)
117   * outranks} the supplied rank
118   *
119   * @see #outranks(int, int)
120   */
121  public default boolean outranks(final int j) {
122    return outranks(this.rank(), j);
123  }
124
125
126  /*
127   * Static methods.
128   */
129
130
131  /**
132   * Returns {@code true} if and only if {@code r0} is non-{@code null} and {@linkplain #outranks(Ranked) outranks}
133   * {@code r1}.
134   *
135   * @param r0 a {@link Ranked}; may be {@code null} in which case {@code false} will be returned
136   *
137   * @param r1 a {@link Ranked}; may be {@code null}
138   *
139   * @return {@code true} if and only if {@code r0} is non-{@code null} and {@linkplain #outranks(Ranked) outranks}
140   * {@code r1}
141   *
142   * @see #outranks(Ranked)
143   */
144  public static boolean outranks(final Ranked r0, final Ranked r1) {
145    return r0 != null && r0.outranks(r1);
146  }
147
148  /**
149   * Returns {@code true} if and only if a rank represented by {@code i} outranks a rank represented by {@code j}.
150   *
151   * <p>Given two ranks, <em>i</em> and <em>j</em>, <em>i</em> <em>outranks</em> <em>j</em> if and only if <em>i</em> is
152   * greater than ({@code >}) <em>j</em>.</p>
153   *
154   * @param i an {@code int} representing a rank
155   *
156   * @param j an {@code int} representing a rank
157   *
158   * @return {@code true} if and only if {@code i} outranks {@code j}
159   *
160   * @idempotency This method is idempotent and deterministic.
161   *
162   * @threadsafety This method is safe for concurrent use by multiple threads.
163   */
164  public static boolean outranks(final int i, final int j) {
165    return i > j;
166  }
167
168}