Structure question in regards to instantiation

I have two classes one called SpawnMaster which handles placement of the object and has algorithms for placement and other code related to spawning. The other class being MonsterWaveHandler which holds data in relation to which monsters to spawn and has the prefab data.

My question is if I should be instantiating the prefabs from MonsterWaveHandler and then sending it to SpawnMaster to place them or should I send the prefab data and have it instantiate on SpawnMaster.

On a related note, I was thinking of doing something like instantiating a clone of a prefab ingame but not activating at all. The reason is because there is code in the Awake class that has to do with setting it up, in theory it would be less code and more performant if it doesn’t have to be setup for every time the prefab is spawned.
The code below does not instantiate the gameobj
Code:

Creating the SpawnGroup in MonsterWaveHandler.cs

    private SpawnGroup CreateSpawnGroup(Vector3 targetPos, int costCount)
    {
        var spawnGroup = new SpawnGroup();
        spawnGroup.FaceTarget = true;
        spawnGroup.RandomizePos = true;
        spawnGroup.RequiresDeployment = true;
        spawnGroup.SpawnType = SpawnType.Monster;
        spawnGroup.SpawnInfos = new List<SpawnInfo>();
        while (costCount > 0)
        {
            var spawnInfo = new SpawnInfo();
            int cost = 1;
            costCount -= cost;
            spawnInfo.SpawnedObject = Instantiate(GetMonsterPrefabBasedOnCost(cost)).GetComponent<ISpawnable>();
            spawnInfo.Pos = targetPos;
            spawnInfo.OnDestroy = ProcessMonsterKill;
            spawnGroup.SpawnInfos.Add(spawnInfo);
        }
        return spawnGroup;
    }

Placing the monsters on the mesh and vfx on SpawnMaster.cs

 public void ProcessSpawnGroup(SpawnGroup spawnGroup)
    {
        for (int i = 0; i < spawnGroup.SpawnInfos.Count; i++)
        {
            var spawnInfo = spawnGroup.SpawnInfos[i];
            Vector3 spawnPos = spawnInfo.Pos;
            if (spawnGroup.RandomizePos)
            {
                if (_useNavMeshSpawn)
                {
                    spawnPos = _navMeshHandler.GetRandomPointInNavMesh(spawnInfo.Pos, _minRandomDistance, _maxRandomDistance);
                    if (spawnPos == Vector3.zero)
                    {
                        continue;
                    }
                }
                else if (!SpawnAlgorithms.GetRandomPosition(spawnInfo.Pos, _minRandomDistance, _maxRandomDistance, spawnGroup.SpawnType == SpawnType.Monster ? _monsterMask : _pickupabletMask, _obstacleMask, _checkRadius, out spawnPos))
                {
                    Debug.Log("CANNOT FIND FREE SPACE FOR SPAWN");
                    continue;
                }
            }
            spawnInfo.SpawnedObject.GameObject.transform.position = spawnPos;
            spawnInfo.SpawnedObject.GameObject.transform.rotation = Quaternion.LookRotation(spawnGroup.FaceTarget ? GetLookRotationToTarget(spawnInfo.SpawnedObject.GameObject.transform.position, spawnInfo.Pos) : spawnInfo.SpawnedObject.GameObject.transform.eulerAngles);
            if (spawnGroup.RequiresDeployment)
            {
                _dataPool.GetSpawnDeployer(spawnGroup.SpawnType, spawnInfo.SpawnedObject.GameObject.transform.position, spawnInfo.SpawnedObject.GameObject.transform.rotation).Setup(spawnInfo.SpawnedObject);
            }
            else
            {
                spawnInfo.SpawnedObject.Activate();
            }
        }
        _audio.PlayOneShot(_dataPool.GetSpawnSound(spawnGroup.SpawnType), .4f);
      

    }

From the description your class should rather be called: PlacementMaster
That it has other code related to spawning probably makes this a candidate for splitting it up.

Positioning a group of game objects in a “formation” (even randomized) should be a single class or even just one static method.

What does this class “handle”?
It sounds like a better name would be MonsterWaveConfig if it is mainly a data holder. Which I think it should be if it isn’t.

I would have an overall “SpawnMaster”. Possibly I’d call it MonsterSpawner or ActorSpawner depending on how versatile it is.

It takes the current MonsterWaveConfig to perform the spawning: how many, how often, which types, where and so on. It would instantiate these monster prefabs and put them in a list. I’d probably have a separate component like Actors which is simply collections of all dynamic game objects so you can get “all enemies” or only specific types.

Then it would send a list of newly spawned game objects (or transforms really) to the Formations class which applies the changes necessary to make them spawn in a circle, triangle, or evenly distributed in a rectangle, or in 2x2 pairs in a triangle formation. This really just applies position offsets to each transform according to a set of rules, and it happens after spawning.

It could even be done with a selection, so that you can have an RTS style selection of units and apply a formation. Except then the final positions would have to be returned because they have to serve as destinations for pathfinding.

In essence it’s about separating individual steps that can be performed in isolation. You can of course easily take this too far, like a class for instantiate, one for parenting, one for position and rotation, and so on.