How to distinguish Roles interfaces from Result interfaces?

This problem often arises because of me in my coding that I am surprised that I can find so few links to it, and will appreciate the thoughts and ideas of other people.

I define a lot of APIs for the frameworks I'm working on and within the large domain models I want to split. These APIs consist almost entirely of interfaces (which means, in my case, C # interfaces). I find again and again that I want to distinguish between two types of interface. In the absence of more commonly used terms, I define them as follows:

  • Role-based interfaces are designed to be implemented by objects outside the API so that these objects can be used as arguments to methods defined in the API.

  • The Result interfaces are implemented by objects inside the API and become available to other parts of the system through the API. The purpose of determining the interface of the result, and not disclosing the object that implements it, is to limit the representation of the object to the outside world.

To select one example, the Payments subsystem can define IPayableItem as a role interface implemented by many types in other parts of the application so that Payments can be created for them. Those created payment objects can be retrieved via the API, but defined using the IPayment Result interface.

The only way I can currently distinguish between this is naming convention and / or commenting. Ideally, I would like the difference applied by the language to ensure that the rule is respected: you cannot implement the Result interface outside the API, use it only. But C # does not provide such a mechanism. (Can anyone advise me on a language that does this?). I could define an attribute, but that still would not provide anything.

Another important difference is the semantic version of the API. If I add a new member to the roles interface, this should be considered as a breaking change (and therefore a first-level version), since any existing external implementations will need to add this element. But if I add a member to what I consider to be the “interface of the result”, then it should only be my own code that it affects - this is just a new function (version of the second level) for everyone else. But in the absence of a strict difference between the two types, there is some risk that people implement the interfaces of Results, and therefore their code will be broken.

Has anyone else encountered this dilemma? If so, how did you deal with this? I look forward to your answers.

But please, you should not answer both of the following arguments (which I have heard too often):

  • The interfaces of my result should be abstract classes, not interfaces. This does not solve the problem and potentially worsens it, because external code can subclass them.

  • I have to return a specific type and ensure that everything that I don’t want available outside the API will be marked as “internal”. There are many cases where I need the API to be publicly accessible, for example. be available to other frameworks (without going through the API).

+6
source share
1 answer

I think you are asking if you can set the interface, but determine that this instance is the one you created?

If so, you can also create an internal private interface and tag all your implementations, as well as implement a private interface. Then, after receiving the object from the outside world, make sure that it also has an implementation of the internal interface.

public interface IPublic { ... } internal interface ISecret { } public class PublicImplementation : IPublic, ISecret { ... } 

Only you can implement ISecret, so even if someone implements IPublic and passes it to you, he will not be able to run the ISecret test.

+1
source

Source: https://habr.com/ru/post/976879/


All Articles