الكائن الإله.
كائن كبير أو قوي للغاية في البرمجة
في البرمجة كائنية التوجه، الكائن الإله (god object) (ويسمى أحياناً الكائن كلي المعرفة omniscient or all-knowing object) هو كائن يشير إلى عدد كبير من الأنواع المتميزة، أو يحتوي على عدد كبير جداً من الأساليب غير المترابطة أو غير المصنفة، أو مزيج من الاثنين معاً. والكائن الإله هو مثال على النمط المضاد ورائحة الكود (code smell).
الخصائص
تقوم تقنية البرمجة الشائعة على فصل المشكلة الكبيرة إلى عدة مشكلات أصغر (استراتيجية فرق تسد) وإنشاء حلول لكل منها. وبمجرد حل المشكلات الأصغر، يتم حل المشكلة الكبيرة ككل. وبالتالي فإن كائناً معيناً لمشكلة صغيرة لا يحتاج إلا إلى معرفة معلومات عن نفسه فقط. وبالمثل، هناك مجموعة واحدة فقط من المشكلات التي يحتاج الكائن إلى حلها: مشكلاته الخاصة. ويتبع هذا أيضاً مبدأ المسؤولية الفردية.
في المقابل، فإن البرنامج الذي يستخدم كائناً إلهاً لا يتبع هذا النهج. ويتم كتابة معظم وظائف مثل هذا البرنامج الإجمالية في كائن واحد "كلي المعرفة"، والذي يحتفظ بمعظم المعلومات حول البرنامج بأكمله، ويقدم أيضاً معظم الأساليب (methods) للتلاعب بهذه البيانات. ولأن هذا الكائن يحتفظ بالكثير من البيانات ويتطلب العديد من الأساليب، فإن دوره في البرنامج يصبح شبيهاً بالإله (كلي المعرفة وشامل لكل شيء). وبدلاً من تواصل كائنات البرنامج فيما بينها مباشرة، تعتمد الكائنات الأخرى داخل البرنامج على كائن إله واحد للحصول على معظم معلوماتها وتفاعلها. ولأن هذا الكائن مرتبط بشكل وثيق (tightly coupled) بـ (مشار إليه من قبل) جزء كبير من الأكواد الأخرى، تصبح الصيانة أكثر صعوبة مما ستكون عليه في تصميم برمجي مقسم بشكل أكثر توازناً. ويمكن أن يكون للتغييرات التي يتم إجراؤها على الكائن لصالح روتين واحد تأثير تموجي على وظائف أخرى غير ذات صلة.
والكائن الإله هو المقابل كائني التوجه للفشل في استخدام الروتينات الفرعية (subroutines) في لغات البرمجة الإجرائية، أو استخدام عدد كبير جداً من المتغيرات العامة لتخزين معلومات الحالة (state).
وعلى الرغم من أن إنشاء كائن إله يعتبر عادةً ممارسة برمجة سيئة، إلا أن هذه التقنية تُستخدم أحياناً لبيئات البرمجة الضيقة (مثل المتحكمات الدقيقة microcontrollers)، حيث تكون زيادة الأداء ومركزية التحكم أكثر أهمية من قابلية الصيانة وأناقة البرمجة.
مثال
يمكن النظر إلى الكلاس GameManager في هذا المثال بلغة C++ على أنه "كائن إله"، حيث يقوم بكل شيء بدءاً من إدارة اللاعبين، ومعالجة منطق اللعبة، والرسم، وقراءة المدخلات وعمليات الإدخال/الإخراج للملفات.
import std;
using std::string;
using std::vector;
class GameManager {
private:
vector<string> players;
int score = 0;
bool running = false;
public:
GameManager() = default;
~GameManager() = default;
void addPlayer(const string& name) {
players.push_back(name);
std::println("تم إضافة اللاعب: {}", name);
}
void listPlayers() const {
std::println("اللاعبون:");
for (const string& p : players) {
std::println(" - {}", p);
}
}
void startGame() {
running = true;
score = 0;
std::println("بدأت اللعبة!");
}
void updateGame() {
if (running) {
score += 10;
std::println("تم تحديث النتيجة: {}", score);
}
}
void endGame() {
running = false;
std::println("انتهت اللعبة! النتيجة النهائية: {}", score);
}
void draw() {
std::println("[رسم شاشة اللعبة]");
}
void handleInput(const string& input) {
if (input == "quit") {
endGame();
} else if (input == "score") {
std::println("النتيجة الحالية: {}", score);
} else {
std::println("مدخل غير معروف");
}
}
void saveGame() {
std::println("حفظ حالة اللعبة على القرص...");
}
void loadGame() {
std::println("تحميل حالة اللعبة من القرص...");
}
void run() {
// ...
}
};
وبدلاً من ذلك، يمكن تقسيم هذا بشكل أكثر ملاءمة بين مسؤوليات منفصلة:
import std;
using std::string;
using std::vector;
class PlayerManager {
private:
vector<string> players;
public:
PlayerManager() = default;
~PlayerManager() = default;
void addPlayer(const string& name) {
players.push_back(name);
std::println("تم إضافة اللاعب: {}", name);
}
void listPlayers() const {
std::println("اللاعبون:");
for (const string& p : players) {
std::println(" - {}", p);
}
}
};
class GameLogic {
private:
int score = 0;
bool running = false;
public:
GameLogic() = default;
~GameLogic() = default;
void startGame() {
running = true;
score = 0;
std::println("بدأت اللعبة!");
}
void updateGame() {
if (running) {
score += 10;
std::println("تم تحديث النتيجة: {}", score);
}
}
int getScore() const noexcept {
return score;
}
void endGame() {
running = false;
std::println("انتهت اللعبة! النتيجة النهائية: {}", score);
}
};
class Renderer {
public:
Renderer() = default;
~Renderer() = default;
void draw() {
std::println("[رسم شاشة اللعبة]");
}
};
class InputHandler {
private:
GameLogic& logic;
public:
explicit InputHandler(GameLogic& logic):
logic{logic} {}
~InputHandler() = default;
void handleInput(const string& input) {
if (input == "quit") {
logic.endGame();
} else if (input == "score") {
std::println("النتيجة الحالية: {}", logic.getScore());
} else {
std::println("مدخل غير معروف");
}
}
};
class SaveSystem {
public:
SaveSystem() = default;
~SaveSystem() = default;
void saveGame() {
std::println("حفظ حالة اللعبة على القرص...");
}
void loadGame() {
std::println("تحميل حالة اللعبة من القرص...");
}
};
class GameManager {
private:
PlayerManager players;
GameLogic logic;
Renderer renderer;
InputHandler input(logic);
SaveSystem saves;
public:
GameManager() = default;
~GameManager() = default;
void run() {
// ...
}
};