Reputation: 1
I am implementing the abstract factory pattern, is there a way to not use an abstract class for different class types?
The structure of my classes is like this: Structure Project
Rectangle.cs and Square.cs implement IShape.cs: Structure Class for AbstractShapeFactory
namespace FactoryMethod.Patterns.Creational.Factory.Shape
{
public interface IShape
{
public void Draw();
}
}
namespace FactoryMethod.Patterns.Creational.Factory.Shape.Normal
{
public class Rectangle : IShape
{
public void Draw()
{
Console.WriteLine("Normal Rectangle");
}
}
}
NormalShapeImp.cs and RoundedShapeImp.cs implement AbstractShapeFactory.cs
The AbstractShapeFactory.cs class looks like this:
namespace FactoryMethod.Patterns.Creational.Factory
{
public enum TypeShape
{
Square = 1,
Rectangle = 2
}
public abstract class AbstractShapeFactory
{
public abstract IShape CreateShape(TypeShape typeShape);
}
}
public class NormalShapeImp : AbstractShapeFactory
{
public override IShape CreateShape(TypeShape typeShape)
{
return typeShape switch
{
TypeShape.Square => new Square(),
TypeShape.Rectangle => new Rectangle(),
_ => new Square(),
};
}
}
The AbstractPaymentFactory.cs class looks like this:
namespace FactoryMethod.Patterns.Creational.Factory
{
public enum TypePayment
{
Google = 1,
Paypal = 2
}
public abstract class AbstractPaymentFactory
{
public abstract IPayment CreatePayment(TypePayment typePayment);
}
}
namespace FactoryMethod.Patterns.Creational.Factory.Payment
{
public class LocalPaymentImp : AbstractPaymentFactory
{
public override IPayment CreatePayment(TypePayment typePayment)
{
return typePayment switch
{
TypePayment.Google => new LocalGooglePayment(),
TypePayment.Paypal => new LocalPaypal(),
_ => new LocalGooglePayment(),
};
}
}
}
I have two abstract factory classes AbstractPaymentFactory.cs Y AbstractShapeFactory.cs
And I have a FactoryProducer.cs class that is in charge of returning one or the other Factory.
namespace FactoryMethod.Patterns.Creational.Factory
{
public class FactoryProducer
{
public static AbstractPaymentFactory GetPaymentFactory(bool isLocal)
{
if (isLocal)
return new LocalPaymentImp();
return new ForeignPaymentImp();
}
public static AbstractShapeFactory GetShapeFactory(bool isRounded)
{
if (isRounded)
return new RoundedShapeImp();
return new NormalShapeImp();
}
}
}
I have my Program.cs class as follows:
static void Main(string[] args)
{
#region Pattern Abstract Factory
/* Factory Payment */
Console.WriteLine("Factory Payment:");
Console.WriteLine("Select Type Payment:");
Console.WriteLine("1- Google (default)");
Console.WriteLine("2- Paypal");
int inputType = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Select Account:");
Console.WriteLine("0- Local");
Console.WriteLine("1- Foreign (default)");
bool opAccount = Console.ReadLine() == "0";
AbstractPaymentFactory factoryPayment = FactoryProducer.GetPaymentFactory(opAccount);
IPayment payment = factoryPayment.CreatePayment((TypePayment)inputType);
payment.DoPayment();
Console.WriteLine("");
/* End Factory Payment */
/* Factory Shape */
Console.WriteLine("Factory Payment:");
Console.WriteLine("Select Type Shape");
Console.WriteLine("1- Square (default)");
Console.WriteLine("2- Rectangle");
int inputTypeShape = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Select:");
Console.WriteLine("0- Normal (default)");
Console.WriteLine("1- Rounded");
bool opShape = Console.ReadLine() == "0";
AbstractShapeFactory factoryShape = FactoryProducer.GetShapeFactory(opShape);
IShape shape = factoryShape.CreateShape((TypeShape)inputTypeShape);
shape.Draw();
/* End Factory Shape */
#endregion
}
Is what I am doing a good practice? Is there another way to not create a abstract factory for different types?
Upvotes: 0
Views: 98
Reputation: 36361
First of all, always ask yourself how the pattern is helping you, and if the benefit outweigh the added complexity. Do not use patterns just because you have read about them. For a toy example like this the code could probably be condensed to a switch-statement:
var shape = (shapeType, isRounded) switch
{
(1, false) => new Square(),
(1, true) => new RoundedSquare(),
(2, false) => new Rectangle(),
(2, true) => new RoundedRectangle(),
};
This involves much less code, so would tend to be easier to read.
Factories and abstract factories provide additional layer of abstraction. This is sometimes needed, say if you have a large amount of shapes, or want to reduce the dependencies from components. But you should generally be careful about your abstraction layers since these can be 'leaky'. Consider for example if you want to create a circle or a line, what would a rounded line be? or a non-round circle? For an intentional example of over-abstraction, see fizzbuzz enterprise edition.
You might also want to read up on the concept of Dependency Injection (DI), Inversion Of Control (IoC) and associated IoC libraries. This can help resolve dependency chains, i.e. classes takes dependencies as constructor parameters. At startup you register what dependencies should be used in the container and request some object of a specific type from the container, the container will then figure out how to create all the dependencies.
Upvotes: 1