In Apex, modifiers control who can reference a member or type. Start restrictive (private), then widen only when needed.
A practical rule: expose a small public surface (methods callers need), keep validation and formatting in private helpers — that makes large classes easier to read and safer to change.
Pattern: hide helpers, expose intent
Callers only see save()— the messy rules stay inside the class.
public class AccountService {
public void save(Account a) {
normalizeName(a);
if (!isValid(a)) {
return;
}
insert a;
}
private void normalizeName(Account a) {
if (a.Name != null) {
a.Name = a.Name.trim();
}
}
private Boolean isValid(Account a) {
return a.Name != null && a.Name.length() > 0;
}
}Pattern: extend behavior with protected
Subclasses can reuse a hook without opening it to unrelated classes in the org.
public virtual class BaseProcessor {
protected virtual void beforeInsert(Account a) {
// default: no-op
}
}
public class StrictProcessor extends BaseProcessor {
protected override void beforeInsert(Account a) {
a.Name = (a.Name == null) ? 'Required' : a.Name;
}
}Pick a modifier
private Integer secret = 1;
Only this class can use it — the tightest visibility.
Who can access it?
Simplified mental model for learning — real org security also includes sharing, profiles, and managed-package namespaces.
virtual on a method allows subclasses to replace it with override. The subclass still has to respect visibility: it cannot override what it cannot see.
public virtual class DiscountEngine {
public virtual Decimal rate() {
return 0.05;
}
}
public class PartnerDiscount extends DiscountEngine {
public override Decimal rate() {
return 0.15;
}
}