Self-adaptivity allows software systems to autonomously adjust their behavior during run-time to reduce the cost complexities caused by manual maintenance. In this paper, a framework for building an external adaptation engine for self-adaptive software systems is proposed. In order to improve the quality of selfadaptive software systems, this research addresses two challenges in self-adaptive software systems. The first challenge is to provide better performance of the adaptation engine by managing the complexity of the adaptation space efficiently and the second challenge is handling run-time uncertainty that hinders the adaptation process. This research utilizes Case-based Reasoning as an adaptation engine along with utility functions for realizing the managed system's requirements.