Fix cyclic dependency between protocol and business classes
I'm designing a library for CANopen protocol. The basic CANopen frames are PDO and SDO, where PDO is like UDP (fire and forget) and SDO is like HTTP (request and response). A CANopen device is a PDO client, PDO server, SDO client, SDO server at the same time. The library should implement the protocol so that the user only need to provide the business logic. // canopen.ts class CanOpenFrame { // id, data, etc } type ResponseOrTimeout = CanOpenFrame|undefined; class CanOpenDevice { // user can send a PDO sendPdo(pdo: CanOpenFrame); // user can send a SDO request and expect a response or timeout sendSdoRequest(request: CanOpenFrame, timeout: number): Promise; } // user interface class CanOpenBusiness { // user should define how to process a PDO frame, and how to process a SDO request // CanOpenDevice will call user callbacks at the right time processPdo(pdo: CanOpenFrame): void | PromiseLike; processSdoRequest(request: CanOpenFrame): ResponseOrTimeout | PromiseLike; } I need some advice about the class relationship. The current design is to make CanOpenBusiness abstract, and let CanOpenDevice contain a CanOpenBusiness reference to call user callbacks at the right time. Problem is the user-defined CanOpenBusiness subclass also needs a CanOpenDevice reference to call sendSdoRequest and sendPdo, so there is a cyclic dependency. How should I improve the design?
I'm designing a library for CANopen protocol. The basic CANopen frames are PDO and SDO, where PDO is like UDP (fire and forget) and SDO is like HTTP (request and response). A CANopen device is a PDO client, PDO server, SDO client, SDO server at the same time. The library should implement the protocol so that the user only need to provide the business logic.
// canopen.ts
class CanOpenFrame {
// id, data, etc
}
type ResponseOrTimeout = CanOpenFrame|undefined;
class CanOpenDevice {
// user can send a PDO
sendPdo(pdo: CanOpenFrame);
// user can send a SDO request and expect a response or timeout
sendSdoRequest(request: CanOpenFrame, timeout: number): Promise;
}
// user interface
class CanOpenBusiness {
// user should define how to process a PDO frame, and how to process a SDO request
// CanOpenDevice will call user callbacks at the right time
processPdo(pdo: CanOpenFrame): void | PromiseLike;
processSdoRequest(request: CanOpenFrame): ResponseOrTimeout | PromiseLike;
}
I need some advice about the class relationship. The current design is to make CanOpenBusiness
abstract, and let CanOpenDevice
contain a CanOpenBusiness
reference to call user callbacks at the right time. Problem is the user-defined CanOpenBusiness
subclass also needs a CanOpenDevice
reference to call sendSdoRequest
and sendPdo
, so there is a cyclic dependency. How should I improve the design?