Q:

strategy to only run the parent batch and not the child batches separately

Is there any design pattern or way to only allow the execution of a parent batch(the parent will chain the subsequent batches or children) and preventing the individual execution of the child batches, in other words, only the parent batch can call the subsequent children but the children cannot be executed separately.
Code example of what I mean by parent batch and child batch:
global class ParentBatch implements Database.batchable<SObject>, Database.Stateful {
    global void finish(Database.BatchableContext bc) {
        Database.executeBatch(new ChildABatch());
    }
}

global class ChildABatch implements Database.batchable<SObject>, Database.Stateful {
    global void finish(Database.BatchableContext bc) {
        Database.executeBatch(new ChildBBatch());
    }
}

global class ChildBBatch implements Database.batchable<SObject>, Database.Stateful {
    global void finish(Database.BatchableContext bc) {
        Database.executeBatch(new ChildCBatch());
    }
}

global class ChildCBatch implements Database.batchable<SObject>, Database.Stateful {

}       

A:

The only way to really prevent execution would be to implement a "private" class scenario. This necessarily means that you'd need some sort of private class on the inside. Here's how I would model this:
public class ParentBatch implements Database.Batchable<SObject> {
    interface BatchInterface {
        Database.QueryLocator start();
        void execute(SObject[] records);
        void finish();
    }
    class ChildA implements BatchInterface {
        public Database.QueryLocator start() {
            return ...;
        }
        public void execute(SObject[] records) {
            // Do stuff
        }
        public void finish() {
            Database.executeBatch(new ChildB());
        }
    }
    class ChildB implements BatchInterface {
        public Database.QueryLocator start() {
            return ...;
        }
        public void execute(SObject[] records) {
            // Do stuff
        }
        void finish() {
            Database.executeBatch(new ChildC());
        }
    }
    class ChildC implements BatchInterface {
        public Database.QueryLocator start() {
            return ...;
        }
        public void execute(SObject[] records) {
            // Do stuff
        }
        public void finish() {

        }
    }
    BatchInterface[] processes = new BatchInterface[] {
        new ChildA(), new ChildB(), new ChildC()
    };
    public Database.QueryLocator start(Database.BatchableContext context) {
        return processes[0].start();
    }
    public void execute(Database.BatchableContext context, SObject[] scope) {
        processes[0].execute(scope);
    }
    public void finish(Database.BatchableContext context) {
        processes.remove(0);
        if(!processes.isEmpty()) {
            Database.executeBatch(this);
        }
    }
}

Basically, we create an interface, then make the classes private to the parent class, and we can chain them together. Because of testing limits, you might need to make the list of processes @TestVisible, but this design allows you to restrict execution of those processes to the main class; there's no way to execute the classes outside of their intended order (except using @TestVisible for unit testing).

