In a very simple way you can follow this design:
trigger ObjectTrigger on Object__c (after insert, after update, before update)
{
if(Trigger.isAfter)
{
if(Trigger.isUpdate)
{
ObjectTriggerHandler.onAfterUpdate(Trigger.new, Trigger.oldMap)
}
else if(Trigger.isInsert)
{
// Pass only trigger.new or Trigger.newMap in param
// Trigger.Old or Trigger.OldMap is null here
ObjectTriggerHandler.onAfterInsert(Trigger.new)
}
}
else if(..)
{
if(Trigger....)
{
....
}
}
...
}
Trigger Handler
public with sharing class ObjecTriggerHandler
{
public static void onAfterUpdate(List<Object__c> newList, Map<Id,Object__c> oldMap)
{
for(Object__c obj : newList)
{
if(Object__c.Field__c != oldMap.get(obj.id).Field__c)
{
// Change identified
// perform Operations
}
else
{
// Throw Error
Object__c.Field__c.addError(' No change is made in the field. Same value: '+obj.Field__c);
}
}
}
}