I'm developing a class for connection to LCD (Liquid Crystal Display).
It can connect in two modes: 4-bit and 8-bit. And the number of modes may be increased. The mode can be configured in the constructor.
A lot of behavior depends on the mode. But! The mode can be changed in run-time, so I can't create the Lcd abstract class and two derivatives FourBitLcd and EightBitLcd.
Code:
class Lcd {
public:
enum Mode {
Mode4bit,
Mode8bit,
};
explicit Lcd(Mode mode) : mode(mode) {}
public:
void Init() {
if (this->mode == Mode8bit) {
SendCommand(LCD_CMD_8_BIT_MODE);
}
else {
this->Reset();
SendCommand(LCD_CMD_4_BIT_MODE);
}
}
void SendCommand(uint8_t command_id) {
if (this->mode == Mode8bit) {
this->SendLowerNibble(command_id);
}
else {
this->SendHigherNibble(command_id);
this->SendCmdSignals();
command_id <<= 4;
}
this->SendHigherNibble(command_id);
this->SendCmdSignals();
}
void SendData(uint8_t data) {
if (this->mode == Mode8bit) {
this->SendLowerNibble(data);
}
else {
this->SendHigherNibble(data);
this->SendDataSignals();
data <<= 4;
}
this->SendHigherNibble(data);
this->SendDataSignals();
}
private:
void BusyCheck() {
// ...
if (this->mode == Mode4bit) {
en.Write(true);
_delay_us(10);
en.Write(false);
_delay_us(10);
}
// ...
}
void Reset();
void SendHigherNibble(uint8_t val);
void SendLowerNibble(uint8_t val);
void SendCmdSignals();
void SendDataSignals();
private:
Mode mode = Mode8bit;
};
In this case, I think I should use polymorphism instead of if/else. But then I have another problem. For example, I can create ModeStrategy abstract class and FourBitModeStrategy and EightBitModeStrategy. But derivative classes need the instance of the class Lcd because they need to use its methods such as SendLowerNibble and SendHigherNibble. But if I pass a pointer of Lcd to derivatives of ModeStrategy then it will be a bidirectional reference. As far as I know, it's not good. For example, code:
class Lcd {
public:
class ModeStrategy {
public:
void InitLcdPtr(Lcd *lcd) {
this->lcd_ = lcd;
}
virtual void InitMode() = 0;
virtual void SendCommandPart(uint8_t &command_id) = 0;
virtual void SendDataPart(uint8_t &data) = 0;
virtual void BusyCheck() {}
protected:
Lcd *lcd_ = nullptr;
};
class FourBitModeStrategy : public ModeStrategy {
public:
void InitMode() override {
this->lcd_->Reset();
this->lcd_->SendCommand(LCD_CMD_4_BIT_MODE);
}
void SendCommandPart(uint8_t &command_id) override {
this->lcd_->SendHigherNibble(command_id);
this->lcd_->SendCmdSignals();
command_id <<= 4;
}
void SendDataPart(uint8_t &data) override {
this->lcd_->SendHigherNibble(data);
this->lcd_->SendDataSignals();
data <<= 4;
}
};
class EightBitModeStrategy : public ModeStrategy {
public:
void InitMode() override {
this->lcd_->SendCommand(LCD_CMD_8_BIT_MODE);
}
void SendCommandPart(uint8_t &command_id) override {
this->lcd_->SendLowerNibble(command_id);
}
void SendDataPart(uint8_t &data) override {
this->lcd_->SendLowerNibble(data);
}
};
friend FourBitModeStrategy;
public:
enum Mode {
Mode4bit,
Mode8bit,
};
explicit Lcd(ModeStrategy *mode_strategy) : mode_strategy(mode_strategy) {
// Bidirectional reference.
this->mode_strategy->InitLcdPtr(this);
}
public:
void Init() {
this->mode_strategy->InitMode();
}
void SendCommand(uint8_t command_id) {
this->mode_strategy->SendCommandPart(command_id);
this->SendHigherNibble(command_id);
this->SendCmdSignals();
}
void SendData(uint8_t data) {
this->mode_strategy->SendDataPart(data);
this->SendHigherNibble(data);
this->SendDataSignals();
}
private:
void BusyCheck() {
// ...
this->mode_strategy->BusyCheck();
// ...
}
void Reset();
void SendHigherNibble(uint8_t val);
void SendLowerNibble(uint8_t val);
void SendCmdSignals();
void SendDataSignals();
private:
ModeStrategy *mode_strategy = nullptr;
};
But as I said there is a bidirectional reference. How to solve it? Thanks in advance!
protectedas well asprivateand public. Derivative classes can accessprotectedfunctions. \$\endgroup\$