C# Design Patterns – Managing Multiple Objects

cdesign-patternsobject-oriented-designpatterns-and-practices

I´m looking for the best way to solve following problem:

I have three lists of different objects: AppleJuice, OrangeJuice & Juice. All Juice properties exists in AppleJuice & OrangeJuice and I only need these from AppleJuice & OrangeJuice. I can´t change the AppleJuice & OrangeJuice implementations since they come from two unrelated SOAP services. My aim is merge these 3 lists in a Juice lists and then remove the duplicates using a concrete match pattern.

Which pattern would best to merge these different objects?

I was thinking of using the Facade pattern for the different objects and then Strategy for the match pattern. If it helps, I´ll be using C# to implement the code.

Here what I did.

First, I've extended the Juice class and I've created 3 extensions methods for the classes: AppleJuice, OrangeJuice and Juice.

public class JuiceExtended : Juice
{
    public JuiceSourceType JuiceSource { get; set; }
}

public enum JuiceSourceType 
{
    Apple,
    Orange,
    Juice,
    JuiceWithoutSugar
}

I need to know the source, because if there is a duplicate I have to keep the objects from the Juice

    public static IEnumerable<JuiceExtended> ConvertToExtended(this IEnumerable<AppleJuice> juices)
    {
        var list = juices.Select((x) => {
            var item = new JuiceExtended()
            {
                JuiceSource = JuiceSourceType.Apple,
                //More properties                  
            };
            return item;
        });

        return list;
    }

    public static IEnumerable<JuiceExtended> ConvertToExtended(this IEnumerable<OrangeJuice> juices)
    {
        var list = juices.Select((x) => {
            var item = new JuiceExtended()
            {
                JuiceSource = JuiceSourceType.Orange,
                //More properties
            };
            return item;
        });

        return list;
    }

    public static IEnumerable<JuiceExtended> ConvertToExtended(this IEnumerable<Juice> juices, JuiceSourceType type)
    {
        var list = juices.Select((x) => {
            var item = (JuiceExtended) x;
            item.JuiceSource = type;     
            return item;
        });

        return list;
    }

After this, I've created a JuiceHandler and I've implemented the strategy pattern inside for the dedup algorithm

public class JuiceHandler : IJuiceHandler
{
    private static IEnumerable<JuiceExtended> _juices;
    private JuiceStrategy _strategy;

    public JuiceHandler()
    {
        _juices = new List<JuiceExtended>();
    }

    public JuiceHandler(JuiceStrategy strategy)
    {
        _juices = new List<JuiceExtended>();
        _strategy = strategy;
    }

    public void Load(IEnumerable<JuiceExtended> juices)
    {
        _juices = _juices.Concat(juices);
    }

    public void SetJuiceStrategy(JuiceStrategy strategy)
    {
        _strategy = strategy;
    }


    public IEnumerable<Juice> Transform()
    {
        if (_strategy == null)
            throw new NullReferenceException("The strategy has not been selected.");

        else if (_juices.Count() == 0)
            return _juices;

        return _strategy.Dedup(_juices);
    }

}

Looking about below responses, @MainMa, I think I'll move the extension methods in the WCF partial classes, because I already have partial classes for WCF so, there is no point to put them into another location.

Best Answer

You can use the Facade pattern like you thought to treat your AppleJuice and OrangeJuice objects like Juice objects. It's pretty simple. Here's your Juice class:

class Juice
{
    Juice(AppleJuice aj)
    {
        this.Color = aj.Color;
        this.VitaminC = aj.VitaminC;
    }

    Juice(OrangeJuice oj)
    {
        this.Color = oj.Color;
        this.VitaminC = oj.VitaminC;
    }

    public ColorType { get; set; }
    public VitaminCType VitaminC { get; set; }
}

This Juice class covers both juice types and extracts the information that you are interested in. To handle Juice equality, you need to implement IEqualityComparer<Juice>:

class JuiceEq : IEqualityComparer<Juice>
{
    public bool Equals(Juice x, Juice y)
    {
        if (x == null) return y == null;
        if (y == null) return false;
        return x.Color == y.Color && x.VitaminC = y.VitaminC;
    }

    public int GetHashCode(Juice obj)
    {
        if(obj == null) return 0;
        return new { obj.Color, obj.VitaminC }.GetHashCode();
    }
}

Now, to use this when you make you SOAP requests and then remove duplicates:

IEnumerable<Juice> GetJuice()
{
    IEnumerable<AppleJuice> appleJuices = SoapAppleJuiceRequestRequest();
    IEnumerable<OrangeJuice> orangeJuices = SoapOrangeJuiceRequestRequest();

    IEnumerable<Juice> juices = appleJuices.Select(s => new Juice(s))
      .Concat(orangeJuices.Select(s => new Juice(s));

    IEnumerable<Juice> deDuped = juices.Distinct(new JuiceEq());
    return deDuped;
}
Related Topic