Is this a good example for representing the abstract factory pattern
Asked Answered
D

3

6

Want to check if this a good example for representing the abstract factory pattern. Here is the theme Dell (Factory) makes xps (Product) Dell (Factory) makes inspiron (Product) hp (Factory) makes envoy (Product) hp (Factory) makes presario (Product)

BestBuy sells computers.

//Abstract factory
abstract class ComputerFactory
{
    public abstract Computer BuildComputer(Computer.ComputerType compType);
}

//Concrete factory
class Dell : ComputerFactory
{
    public override Computer BuildComputer(Computer.ComputerType compType)
    {
        if (compType == Computer.ComputerType.xps)
            return (new xps());
        else if (compType == Computer.ComputerType.inspiron)
            return new inspiron();
        else
            return null;
    }
}

//Concrete factory
class Hp : ComputerFactory
{
    public override Computer BuildComputer(Computer.ComputerType compType)
    {
        if (compType == Computer.ComputerType.envoy)
            return (new envoy());
        else if (compType == Computer.ComputerType.presario)
            return new presario();
        else
            return null;
    }
}

//Abstract product
public abstract class Computer
{
    public abstract string Mhz { get; set; }
    public enum ComputerType
    {
        xps,
        inspiron,
        envoy,
        presario
    }
}

//Concrete product for DELL
public class xps : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for DELL
public class inspiron : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for HP
public class envoy : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for HP
public class presario : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

public class BestBuy
{
    ComputerFactory compFactory;
    Computer comp;
    public BestBuy(Computer.ComputerType compType)
    {
        if (compType == Computer.ComputerType.xps || compType == Computer.ComputerType.inspiron)
            compFactory = new Dell();
        else
            compFactory = new Hp();

        comp = compFactory.BuildComputer(compType);
    }

    public Computer Sell()
    {
        return comp;
    }
}

Thanks in advance.

Disengagement answered 24/2, 2011 at 18:50 Comment(0)
M
8

It is a good example of portions of the pattern. The basic construction of objects is a decent example, however, the logic relies upon a single Computer.ComputerType enum. This enum needs to know, in advance, every type of computer exposed by every factory.

Often, the motivation for using an abstract factory is to abstract that type of hard coded requirement out of the picture. Instead of having a single enum, it might be better to add a ComputerType class, and allow the factory to return a collection of available types. You could then use the ComputerType returned to construct the new systems.

This allows you to add other factories without changing your API, which is one of the major advantages of the abstract factory pattern. Read up on the Abstract Factory Pattern - one of the main points is:

The client does not know (or care) which concrete objects it gets from each of these internal factories since it uses only the generic interfaces of their products.

In this case, you're "hard coding" the known types into the enum, which violates this portion of the pattern.

Millian answered 24/2, 2011 at 19:12 Comment(3)
Hi, I have added the client class as well. I understand your concern about the using the computertype as enum. ThanksDisengagement
@saidevakumar: This shows the problem. "Best Buy" needs to know about every potential computer type, in advance. Say Dell comes out with a "XPQ" computer in addition to their two lines now. You have to change your API, change your client code, etc. If you want to add a 3rd brand, you have to add it to the enum. By having the factories supply the types they can create, you eliminate that need...Millian
Worse still, what if two computer manufacturers come out with a model with the same name?Comet
M
3

I'm not Factory pattern expert but here are couple of things I would do differently:

  • Instead of an abstract class, I would use an Interface. So if "Dell" needed to inherit from another class it could and still be able to be a ComputerFactory by implementing IComputerFactory for example.
  • The other small thing is use a "switch" instead of an "if/else if" in your BuildComputer function. Who knows how many computers you might end up with in the end.
  • How would you know which concrete Factory to use between Hp and Dell? You might use something like "Autofac" to "resolve" which factory to use.
Mimi answered 24/2, 2011 at 19:16 Comment(0)
C
0

I think, in the scenario and code you have provided, there is only one type of product, i.e 'Computer'. There is no family of products involved. So, the abstract factory pattern will not apply here. Instead factory pattern can be used here. I have modified the code below for understanding.

//Abstract factory
abstract class ComputerFactory
{
    public abstract Computer BuildComputer(Computer.ComputerType compType);
}

public class ConcreteFactory : ComputerFactory
{
    public override Computer BuildComputer(Computer.ComputerType compType)
    {
        if (compType == Computer.ComputerType.xps)
            return (new xps());
        else if (compType == Computer.ComputerType.inspiron)
            return new inspiron();
        else if (compType == Computer.ComputerType.envoy)
            return (new envoy());
        else if (compType == Computer.ComputerType.presario)
            return new presario();
        else
            return null;
    }
}

//Abstract product
public abstract class Computer
{
    public abstract string Mhz { get; set; }
    public enum ComputerType
    {
        xps,
        inspiron,
        envoy,
        presario
    }
}

//Concrete product for DELL
public class xps : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for DELL
public class inspiron : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for HP
public class envoy : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

//Concrete product for HP
public class presario : Computer
{
    string _mhz = string.Empty;

    public override string Mhz
    {
        get
        {
            return _mhz;
        }
        set
        {
            _mhz = value;
        }
    }
}

public class BestBuy
{        
    ConcreteFactory compFactory;
    Computer comp;
    public BestBuy(Computer.ComputerType compType)
    {
        comp = compFactory.BuildComputer(compType);            
    }

    public Computer Sell()
    {
        return comp;
    }
}
Crimmer answered 5/7, 2012 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.