samedi 30 septembre 2023

Analyzing approaches to handling optional arguments in multiple interface implementations: what are the pros and cons of each method?

I have a question regarding the code. The code is an example to illustrate the problem. I have an interface named MembershipInterface and I created a new implementation for this interface called MembershipExternalServiceAdapter. I also have a class MembershipApiSwitch which is used to decide which interface implementation should be called based on conditions. The problem is that in the new MembershipExternalServiceAdapter interface, some arguments which are present in these methods are not needed because they are unused or will be different.

How to solve this properly?

Set default values - and in one implementation ignore these arguments? Create a new interface that will inherit from MembershipInterface and override the methods? Use the strategy pattern - introduce separate strategies for these methods for different implementations and inject them as needed? Which method do you recommend?

Sample code:

interface MembershipInterface {
    fun validate(memberID: String, passphrase: String): MembershipValidationDto
    fun getMembershipData(membershipID: String, showRewards: Boolean): MembershipDataDto
    fun getMembershipData(productList: List<Item>, shopCode: String, membershipID: String): MembershipDataDto
    fun isMemberIDCorrect(memberID: String): Boolean
}

@Component
@Primary
class MembershipApiSwitch(
    @Qualifier("API1_MembershipFacade")
    private val api1Membership: MembershipInterface,
    private val membershipSettings: MembershipSettings,
    @Qualifier("API2_MembershipFacade")
    private val api2Membership: MembershipInterface,
    private val tokenHandler: TokenHandler,
    private val membershipIntegration: MembershipIntegration
) : MembershipInterface {

    If the condition is met, call the methods from `api1Membership`; otherwise, call from `api2Membership`.
}

@Component("API1_MembershipFacade")
class MembershipDatabaseAdapter(
    private val databaseClient: DatabaseClient
) : MembershipInterface {
    override fun validate(memberID: String, passphrase: String): MembershipValidationDto {
        return databaseClient.validateMember(memberID, passphrase)
    }

    override fun getMembershipData(membershipID: String, showRewards: Boolean): MembershipDataDto {
        return databaseClient.getMembershipData(membershipID, showRewards)
    }

    override fun getMembershipData(productList: List<Item>, shopCode: String, membershipID: String): MembershipDataDto {
        return databaseClient.calculateMembershipPoints(productList, shopCode, membershipID)
    }

    override fun isMemberIDCorrect(memberID: String): Boolean {
        return databaseClient.isMemberIDExists(memberID)
    }
}

@Component("API2_MembershipFacade")
class MembershipExternalServiceAdapter(
    private val externalServiceClient: ExternalServiceClient
) : MembershipInterface {
    override fun validate(memberID: String, passphrase: String): MembershipValidationDto {
        return externalServiceClient.validateMember(memberID)
    }

    override fun getMembershipData(membershipID: String, showRewards: Boolean): MembershipDataDto {
        return externalServiceClient.getMembershipData()
    }

    override fun getMembershipData(productList: List<Item>, shopCode: String, membershipID: String): MembershipDataDto {
        return externalServiceClient.calculateMembershipPoints(membershipID)
    }

    override fun isMemberIDCorrect(memberID: String): Boolean {
        return externalServiceClient.isMemberIDExists(memberID)
    }
}

Sample method call: membershipApiSwitch.validate(memberID, passphrase)

I provided some sample code and several variants of solving this problem. I am seeking opinions on which approach seems most sensible.

Aucun commentaire:

Enregistrer un commentaire