Это почему сеттеры нарушают инкапсуляцию? Вовсе нет. Контроль сохраняется за внутренней логикой класса. И в отношении конструкторов, получается, странным образом интерпретируете инкапсуляцию. Логика ООП практически потеряет смысл, если нельзя будет настраивать поведение объектов. Каким образом с чем-либо взаимодействовать, если нет значений, которые можно передать объекту?
Самая банальная проблема, которую решает инкапсуляция, это нарушение работы объекта и непредсказуемость последствий при прямом обращении к свойствам объекта. Например, у нас есть класс, реализующий работу с файлом, и одним из его свойств является дескриптор открытого файла. Если открыть файл, а затем обнулить или заменить дескриптор, то объект потеряет контроль над открытым ранее файлом. Понятно, что это свойство должно быть целиком закрыто и лишено внешнего доступа. Но объект может инициализироваться с путем файла, и путь к файлу может быть так же сеттером, и при изменении пути файла пользователем можно корректно среагировать, от исключения до закрытия ранее открытого файла. Это двоякое свойство, которое логично сохранить, скажем, только для конструктора — объекту необходимо установить это свойство, и объект прямо ассоциируется с путем, ему переданным, цикл жизни будет связан с конкретным файлом. Могут быть и иные опции, например, размер буфера, который можно позволить менять в реальном времени, перенастраивая некоторые параметры работы с файлом в логике сеттера и т.д..
То есть, смысл инкапсуляции — это возможность реализации конкретной логики с распределением закрытости свойств. В одних случаях уместно закрыть доступ целиком, чтобы не нарушать базовое поведение объекта, когда разумно оставить установку значений только через конструктор, скажем, если цикл жизни объекта это некий конечный процесс, и может быть уместно запретить изменение этого поведения для дочерних классов, в других — допустимо менять свойства динамически, сеттерами, но оставляя обработку изменения за логикой класса.