I think you are looking for the Composite
Apex Design Pattern. You are familiar with this pattern already for its implementation in the Selector library.
I highly recommend to any developer to read through the entire Apex Design Patterns article.
I took a different tack than the Selector library in my implementation of Predicate
logic I built out for a fluent query builder. I've stripped out the parts related to query building as you would need to take it in a different direction:
public virtual class Predicate
{
final List<Predicate> children;
Predicate(Predicate left, Predicate right)
{
children = new List<Predicate>();
if (!sharesType(left)) children.add(left);
else children.addAll(left.children);
if (!sharesType(right)) children.add(right);
else children.addAll(right.children);
}
@TestVisible virtual String getDelimiter() { return null; }
@TestVisible virtual Boolean sharesType(Predicate that) { return false; }
public Predicate andX(Predicate that) { return new AndPredicate(this, that); }
public Predicate andX(Expression expression) { return andX(new Predicate(expression)); }
public Predicate orX(Predicate that) { return new OrPredicate(this, that); }
public Predicate orX(Expression expression) { return orX(new Predicate(expression)); }
class AndPredicate extends Predicate
{
AndPredicate(Predicate left, Predicate right) { super(left, right); }
override Boolean sharesType(Predicate that) { return that instanceOf AndPredicate; }
override String getDelimiter() { return ' AND '; }
}
class OrPredicate extends Predicate
{
OrPredicate(Predicate left, Predicate right) { super(left, right); }
override Boolean sharesType(Predicate that) { return that instanceOf OrPredicate; }
override String getDelimiter() { return ' OR '; }
}
}