0

Given an interface, that should be Init to Run. Initialisation code must be run.
Initialisation is two part: one that depend of the configuration, one that do not.

The configurable one must be calling the other one if he does not want to duplicate that code.

public interface IProcess
{
    bool Init(out string error);
    bool Init(ProcessConfiguration processConf, out string error);
    bool Run(object message, out ErrorCode errorCode);
    // ...
}

And it's correct implementation :

public class ProcessGood : IProcess
{
       public bool Init(out string error){
              // Important Code   
              return true;
       }
       
       public bool Init(ProcessConfiguration processConf, out string error){              
              Init(out erreur);    
              // things about processConf    
              return true;
       }

My issue is due to the existence of 2 init method, the need for one to call the other as default behavior is not well followed.
Is there a way using Interface/ Virtual / etc to force one Init to call the other?

Example of one incorrect implementation:

public class ProcessBad : IProcess
{
       public bool Init(out string error){
              // Important Code   
              return true;
       }
       
       public bool Init(ProcessConfiguration processConf, out string error){              
              // Init(out erreur);    // some one forgot to type this. 
              // things about processConf    
              return true;
       }
xdtTransform
  • 1,986
  • 14
  • 34
  • Have you thought about an abstract class with public sealed `Init` which calls two protected abstract `InternalInit`s ? – Fildor Sep 08 '20 at 07:37
  • I am curious if using C# 8 [default interface implementation](https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/) can be used somehow to force a call. – Sinatr Sep 08 '20 at 07:39
  • @Sinatr How? That would mean we can make the default interface impl. "final" or "sealed", right? I don't think that's possible (nor that it should). – Fildor Sep 08 '20 at 07:41
  • @Fildor, No I didn't. In fact I have a hard time figuring this one out. – xdtTransform Sep 08 '20 at 07:45
  • 1
    This doesn't really make sense and it just begs to be refactored and redesigned – TheGeneral Sep 08 '20 at 07:58
  • 1
    You can not enforce contracts like that, except by rewriting. You could create "gateway interfaces", in other words, the only way to get the right interface with the method you actually want to use is to call some other method, kinda like a factory method. In other words, split the interface and make the init method(s) return the one with the Run method. – Lasse V. Karlsen Sep 08 '20 at 08:02
  • @LasseV.Karlsen "Builder Pattern" comes to mind ... – Fildor Sep 08 '20 at 08:03
  • 1
    @Fildor Thanks, I was trying to remember the name of the pattern(s), build pattern is entirely correct. – Lasse V. Karlsen Sep 08 '20 at 08:10
  • @MichaelRandall, YES! Refactor and redesigned is my wet dream. But I lack Skill and budget for external code review. If I were an FB engineer, the job will be done, clean, and robust. But I'm stuck here and any turn over in the team is remplaced by cheap contractor. If you have any idea tips, book, article. I willbe avidly reading those. – xdtTransform Sep 08 '20 at 08:14

2 Answers2

3

If it is feasable to use abstract classes, then I could imagine a solution like this:

public interface IProcess
{
    bool Init(ProcessConfiguration processConf);
    // ...
}

abstract class ProcessBase : IProcess
{

    public bool IProcess.Init(ProcessConfiguration processConf)
    {
     if ( !InitInternal() ) return false;
     return InitInternal(ProcessConfiguration processConf);
    }
    
    protected abstract bool InitInternal();
    protected abstract bool InitInternal(ProcessConfiguration processConf);

}

Here, you force a specific implementation of the init process (in that both sub processes must be called) while leaving the concrete implementation of each part to the child.

Fildor
  • 14,510
  • 4
  • 35
  • 67
  • 1
    This is making the best of a bad situation, and considering the ops specified limitations probably the best that one could hope fore – TheGeneral Sep 08 '20 at 08:18
  • @MichaelRandall tbh, I am not entirely happy with this. I just think it's the easier option compared to a full-on builder pattern with fancy fluent-API ... – Fildor Sep 08 '20 at 08:24
  • 1
    The problem is nothing is going to save the ops design and enforce the contracts. The only thing that can be done now is hide the *explicit* interface implementation in a base class and enforce implementers to inherit and override the abstract methods. Anything is just different fixes for a bad design. Personally i would just go with what you have except making it explicit i.e `bool IProcess.Init(ProcessConfiguration,..)`. That way the interface runs as expected by callers, and can be implemented safely by implementers – TheGeneral Sep 08 '20 at 08:30
0

Are you sure your code is C#? As in C# it should look something like this:

public class ProcessBad : IProcess
{
    public ProcessBad(string error) 
    {
        // Important Code   
    }

    public ProcessBad(ProcessConfiguration processConf, string error) : this(error) // will be called ANYWAY
    {
        // things about processConf    
    }
}
Roman Ryzhiy
  • 1,540
  • 8
  • 5
  • They are _not_ Constructors, though. – Fildor Sep 08 '20 at 07:35
  • 1
    Do you suggest using constructors? Then be explicit, OP methods are not constructors. And you [can't force constructors](https://stackoverflow.com/q/619856/1997232) with interface. I am sure OP aware about `this()`, think of later initiliazation of collection of `IProcess` - calling constructors won't help. – Sinatr Sep 08 '20 at 07:36
  • Ooooh, so you are saying "they _should_ be ctors"? – Fildor Sep 08 '20 at 07:39
  • @Fildor You cannot "enforce" functionality via an interface, so I suggest to do it via .ctor chain. – Roman Ryzhiy Sep 08 '20 at 07:48
  • OK, it looked like you mistook the methods for ctors. Ok, nevermind. – Fildor Sep 08 '20 at 07:50
  • Yes this is CSharp. For some reason my first thought was almost the same. I googled "method chainning with interface C#", "Ctor in interface C#". So I see where you are comming from. For Ctors the issue is that The 2 init help a lot in maintance, process can be heavy configurable or a have a strong base initialisation. If I can enforce the separation I will end up with bad code. – xdtTransform Sep 08 '20 at 07:55