Search code examples
c#design-patternsobject-oriented-analysis

What design pattern to use parent and child class with child method?


I have faced this problem many times when I want to build a parent-child relationship class.
I have a base AuthenticateRequest class. In my case, I have 2 child requests but they have own logic to GetContent().
It doesn't not really fall into Composite Pattern nor Liskov Substitution as the base method is unique and called.
Which design pattern should I use?

public class AuthenticateRequest
{
    public string Url { get; set; }

    public string ContentType { get; set; }

    public string Method { get; set; }

    public virtual HttpContent GetContent()
    {
        return new StringContent("");
    }
} 

public class SoapAuthenticateRequest : AuthenticateRequest
{
    public string SoapMethodName { get; set; }

    public string SoapAction { get; set; }

    public string KeyForUserNameParameter { get; set; }

    public string ValueForUserNameParameter { get; set; }

    public string KeyForPasswordParameter { get; set; }

    public string ValueForPasswordParameter { get; set; }

    public override HttpContent GetContent()
    {
        var methodName = this.SoapMethodName;
        var keyUsername = this.KeyForUserNameParameter;
        var keyPwd = this.KeyForPasswordParameter;
        var valueUsername = this.ValueForUserNameParameter;
        var valuePwd = this.ValueForPasswordParameter;
        var soapAction = this.SoapAction ?? @"http://tempuri.org/"; 

        var soap = $@"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""><soap:Body><{methodName} xmlns=""{soapAction}""><{keyUsername}>{valueUsername}</{keyUsername}><{keyPwd}>{valuePwd}</{keyPwd}></{methodName}></soap:Body></soap:Envelope>";

        return new StringContent(soap, Encoding.UTF8, ContentTypes.XmlSoap);
    }
}

public class JsonAuthenticateRequest : AuthenticateRequest
{
    public string SoapMethodName { get; set; }

    public string SoapAction { get; set; }

    public Dictionary<string, string> ParameterKeyValues { get; set; }

    public override HttpContent GetContent()
    {
        var json = JsonConvert.SerializeObject(ParameterKeyValues);
        return new StringContent(json, Encoding.UTF8, ContentTypes.Json);
    }
}

public async Task<AuthenticateResponse> Authenicate(AuthenticateRequest request)
{
    var requestMsg = new HttpRequestMessage
    {
        RequestUri = new Uri(request.Url),
        Method = new HttpMethod(request.Method.ToString()),
        Content = request.GetContent(),
    };

    var responseMsg = await _httpClient.SendAsync(requestMsg).ConfigureAwait(false);
    var responseContent = await responseMsg.Content.ReadAsStringAsync().ConfigureAwait(false);

    return new AuthenticateResponse
    {
        Message = responseContent,
        IsSuccess = Regex.Match(responseContent, (string)request.RegexForValidUser).Success
    };
}

Solution

  • Did you see Factory pattern?

    But for your problem, to require the class having his proper implementation. You can just simply use the abstract keyword like this

    public abstract class AuthenticateRequest
    {    
        public abstract HttpContent GetContent();
    } 
    
    public class SoapAuthenticateRequest : AuthenticateRequest
    {
        public override HttpContent GetContent()
        {
            // your logic
    
            return new StringContent(soap, Encoding.UTF8, ContentTypes.XmlSoap);
        }
    }
    
    public class JsonAuthenticateRequest : AuthenticateRequest
    {
        public override HttpContent GetContent()
        {
            var json = JsonConvert.SerializeObject(ParameterKeyValues);
            return new StringContent(json, Encoding.UTF8, ContentTypes.Json);
        }
    }